[change] refactor the yao service

This commit is contained in:
Max 2023-03-26 17:12:02 +08:00
parent 8761a26d52
commit 75ee709c23
9 changed files with 163 additions and 103 deletions

View file

@ -1,14 +1,12 @@
package cmd package cmd
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"time"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -153,7 +151,7 @@ var startCmd = &cobra.Command{
printStores(true) printStores(true)
} }
srv, err := service.Start() srv, err := service.Start(config.Conf)
// Start server // Start server
go func() { go func() {
@ -170,11 +168,9 @@ var startCmd = &cobra.Command{
for { for {
select { select {
case <-interrupt: case <-interrupt:
ctx, canceled := context.WithTimeout(context.Background(), (5 * time.Second)) // ctx, canceled := context.WithTimeout(context.Background(), (5 * time.Second))
defer canceled() // defer canceled()
service.StopWithContext(ctx, func() { service.Stop(srv)
fmt.Println(color.GreenString(L("✨STOPPED✨")))
})
return return
} }
} }

View file

@ -1,6 +1,7 @@
package engine package engine
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -245,7 +246,33 @@ func loadApp(root string) error {
} }
application.Load(app) application.Load(app)
return nil
var info []byte
// Read app setting
if has, _ := application.App.Exists("app.yao"); has {
info, err = application.App.Read("app.yao")
if err != nil {
return err
}
} else if has, _ := application.App.Exists("app.jsonc"); has {
info, err = application.App.Read("app.jsonc")
if err != nil {
return err
}
} else if has, _ := application.App.Exists("app.json"); has {
info, err = application.App.Read("app.json")
if err != nil {
return err
}
} else {
return fmt.Errorf("app.yao or app.jsonc or app.json does not exists")
}
share.App = share.AppInfo{}
return json.Unmarshal(info, &share.App)
} }
func printErr(mode, widget string, err error) { func printErr(mode, widget string, err error) {

View file

@ -14,7 +14,6 @@ import (
"github.com/yaoapp/kun/any" "github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/maps" "github.com/yaoapp/kun/maps"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/service"
) )
func TestCommandVersion(t *testing.T) { func TestCommandVersion(t *testing.T) {
@ -41,7 +40,7 @@ func TestCommandStart(t *testing.T) {
oldArgs := os.Args oldArgs := os.Args
defer func() { defer func() {
os.Args = oldArgs os.Args = oldArgs
service.Stop(func() {}) // service.Stop(func() {})
log.Println("服务已关闭") log.Println("服务已关闭")
}() }()
@ -129,7 +128,7 @@ func TestCommandStop(t *testing.T) {
assert.Equal(t, "管理员", res.Get("name")) assert.Equal(t, "管理员", res.Get("name"))
// 测试关闭 // 测试关闭
service.Stop(func() { log.Println("服务已关闭") }) // service.Stop(func() { log.Println("服务已关闭") })
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)
_, err = request() _, err = request()
assert.NotNil(t, err) assert.NotNil(t, err)

View file

@ -4,7 +4,6 @@ import (
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yaoapp/yao/share"
) )
// Middlewares 服务中间件 // Middlewares 服务中间件
@ -22,30 +21,21 @@ func BinStatic(c *gin.Context) {
c.Next() c.Next()
return return
} else if share.App.XGen == "1.0" { }
// Xgen 1.0 // Xgen 1.0
if length >= AdminRootLen && c.Request.URL.Path[0:AdminRootLen] == AdminRoot { if length >= AdminRootLen && c.Request.URL.Path[0:AdminRootLen] == AdminRoot {
c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, c.Request.URL.Path[0:AdminRootLen-1]) c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, c.Request.URL.Path[0:AdminRootLen-1])
XGenFileServerV1.ServeHTTP(c.Writer, c.Request) XGenFileServerV1.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
}
if length >= 18 && c.Request.URL.Path[0:18] == "/__yao_admin_root/" {
c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, "/__yao_admin_root")
XGenFileServerV1.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
}
} else if share.App.XGen == "" && length >= 7 && c.Request.URL.Path[0:7] == "/xiang/" {
// Xgen 0.9
c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, "/xiang")
XGenFileServerV0.ServeHTTP(c.Writer, c.Request)
c.Abort() c.Abort()
return return
}
if length >= 18 && c.Request.URL.Path[0:18] == "/__yao_admin_root/" {
c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, "/__yao_admin_root")
XGenFileServerV1.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
} }
// 应用内静态文件目录(/ui or public) // 应用内静态文件目录(/ui or public)

View file

@ -1,22 +1,21 @@
package service package service
import ( import (
"context" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yaoapp/gou/api" "github.com/yaoapp/gou/api"
"github.com/yaoapp/gou/server/http" "github.com/yaoapp/gou/server/http"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
) )
var shutdown = make(chan bool, 1) // Start the yao service
func Start(cfg config.Config) (*http.Server, error) {
var shutdownComplete = make(chan bool, 1) if cfg.AllowFrom == nil {
cfg.AllowFrom = []string{}
// Start 启动服务 }
func Start() (*http.Server, error) {
err := prepare() err := prepare()
if err != nil { if err != nil {
@ -24,64 +23,46 @@ func Start() (*http.Server, error) {
} }
router := gin.New() router := gin.New()
api.SetRoutes(router, "/api", config.Conf.AllowFrom...) api.SetGuards(Guards)
api.SetRoutes(router, "/api", cfg.AllowFrom...)
srv := http.New(router, http.Option{ srv := http.New(router, http.Option{
Host: config.Conf.Host, Host: cfg.Host,
Port: config.Conf.Port, Port: cfg.Port,
Root: "/api", Root: "/api",
Allows: config.Conf.AllowFrom, Allows: cfg.AllowFrom,
Timeout: 5 * time.Second,
}).With(Middlewares...) }).With(Middlewares...)
go func() {
err = srv.Start()
}()
return srv, nil return srv, nil
} }
// StartWithouttSession 启动服务 // Stop the yao service
func StartWithouttSession() (*http.Server, error) { func Stop(srv *http.Server) error {
err := srv.Stop()
router := gin.New() if err != nil {
api.SetRoutes(router, "/api", config.Conf.AllowFrom...) return err
srv := http.New(router, http.Option{
Host: config.Conf.Host,
Port: config.Conf.Port,
Root: "/api",
Allows: config.Conf.AllowFrom,
}).With(Middlewares...)
return srv, nil
}
// StopWithouttSession 关闭服务
func StopWithouttSession(onComplete func()) {
shutdown <- true
select {
case <-shutdownComplete:
onComplete()
}
}
// Stop 关闭服务
func Stop(onComplete func()) {
shutdown <- true
select {
case <-shutdownComplete:
share.SessionStop()
share.DBClose()
onComplete()
} }
<-srv.Event()
return nil
} }
// StopWithContext stop with timeout // StopWithContext stop with timeout
func StopWithContext(ctx context.Context, onComplete func()) { // func StopWithContext(ctx context.Context, onComplete func()) {
shutdown <- true // shutdown <- true
select { // select {
case <-ctx.Done(): // case <-ctx.Done():
log.Error("[STOP] canceled (%v)", ctx.Err()) // log.Error("[STOP] canceled (%v)", ctx.Err())
onComplete() // onComplete()
case <-shutdownComplete: // case <-shutdownComplete:
share.SessionStop() // share.SessionStop()
onComplete() // onComplete()
} // }
} // }
func prepare() error { func prepare() error {

74
service/service_test.go Normal file
View file

@ -0,0 +1,74 @@
package service
import (
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/test"
)
func TestStartStop(t *testing.T) {
gin.SetMode(gin.ReleaseMode)
cfg := config.Conf
cfg.Port = 0
err := engine.Load(cfg)
if err != nil {
t.Fatal(err)
}
srv, err := Start(cfg)
if err != nil {
t.Fatal(err)
}
defer Stop(srv)
<-srv.Event()
if !srv.Ready() {
t.Fatal("server not ready")
}
port, err := srv.Port()
if err != nil {
t.Fatal(err)
}
if port <= 0 {
t.Fatal("invalid port")
}
// API Server
req := test.NewRequest(port).Route("/api/__yao/app/setting")
res, err := req.Get()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 200, res.Status())
data, err := res.Map()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Demo Application", data["name"])
// Public
req = test.NewRequest(port).Route("/")
res, err = req.Get()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 200, res.Status())
assert.Equal(t, "Hello World\n", res.Body())
// XGEN
req = test.NewRequest(port).Route("/admin/")
res, err = req.Get()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 200, res.Status())
assert.Contains(t, res.Body(), "ROOT /admin/")
}

View file

@ -18,9 +18,6 @@ import (
// AppFileServer static file server // AppFileServer static file server
var AppFileServer http.Handler var AppFileServer http.Handler
// XGenFileServerV0 XGen v0.9
var XGenFileServerV0 http.Handler = http.FileServer(data.XgenV0())
// XGenFileServerV1 XGen v1.0 // XGenFileServerV1 XGen v1.0
var XGenFileServerV1 http.Handler = http.FileServer(data.XgenV1()) var XGenFileServerV1 http.Handler = http.FileServer(data.XgenV1())
@ -41,9 +38,6 @@ func SetupStatic() error {
// Static file server // Static file server
AppFileServer = http.FileServer(Dir(filepath.Join(config.Conf.Root, "public"))) AppFileServer = http.FileServer(Dir(filepath.Join(config.Conf.Root, "public")))
if share.App.XGen == "" || share.App.XGen == "0.9" {
AppFileServer = http.FileServer(Dir(filepath.Join(config.Conf.Root, "ui")))
}
return nil return nil
} }

View file

@ -1,7 +1,6 @@
package service package service
import ( import (
"context"
"fmt" "fmt"
"io/fs" "io/fs"
"io/ioutil" "io/ioutil"
@ -262,12 +261,12 @@ func watchReload(root string, file string, event string, cfg config.Config) {
} }
// Restart Server // Restart Server
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // defer cancel()
StopWithContext(ctx, func() { // Stop(func() {
go Start() // go Start()
fmt.Println(color.GreenString("[Watch] Reload Completed")) // fmt.Println(color.GreenString("[Watch] Reload Completed"))
}) // })
} }
} }

View file

@ -34,8 +34,8 @@ func TestWatch(t *testing.T) {
} }
func TestWatchReload(t *testing.T) { func TestWatchReload(t *testing.T) {
go Start() go Start(config.Conf)
defer Stop(func() {}) // defer Stop(func() {})
share.DBConnect(config.Conf.DB) share.DBConnect(config.Conf.DB)
watchReload("", "", "", config.Conf) watchReload("", "", "", config.Conf)
} }