diff --git a/cmd/start.go b/cmd/start.go index 216f7786..70677279 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -1,14 +1,12 @@ package cmd import ( - "context" "fmt" "os" "os/signal" "path/filepath" "strings" "syscall" - "time" "github.com/fatih/color" "github.com/spf13/cobra" @@ -153,7 +151,7 @@ var startCmd = &cobra.Command{ printStores(true) } - srv, err := service.Start() + srv, err := service.Start(config.Conf) // Start server go func() { @@ -170,11 +168,9 @@ var startCmd = &cobra.Command{ for { select { case <-interrupt: - ctx, canceled := context.WithTimeout(context.Background(), (5 * time.Second)) - defer canceled() - service.StopWithContext(ctx, func() { - fmt.Println(color.GreenString(L("✨STOPPED✨"))) - }) + // ctx, canceled := context.WithTimeout(context.Background(), (5 * time.Second)) + // defer canceled() + service.Stop(srv) return } } diff --git a/engine/load.go b/engine/load.go index e1972c73..e73c01a1 100644 --- a/engine/load.go +++ b/engine/load.go @@ -1,6 +1,7 @@ package engine import ( + "encoding/json" "fmt" "os" "strings" @@ -245,7 +246,33 @@ func loadApp(root string) error { } 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) { diff --git a/main_test.go b/main_test.go index f54d9659..560d1669 100644 --- a/main_test.go +++ b/main_test.go @@ -14,7 +14,6 @@ import ( "github.com/yaoapp/kun/any" "github.com/yaoapp/kun/maps" "github.com/yaoapp/yao/config" - "github.com/yaoapp/yao/service" ) func TestCommandVersion(t *testing.T) { @@ -41,7 +40,7 @@ func TestCommandStart(t *testing.T) { oldArgs := os.Args defer func() { os.Args = oldArgs - service.Stop(func() {}) + // service.Stop(func() {}) log.Println("服务已关闭") }() @@ -129,7 +128,7 @@ func TestCommandStop(t *testing.T) { assert.Equal(t, "管理员", res.Get("name")) // 测试关闭 - service.Stop(func() { log.Println("服务已关闭") }) + // service.Stop(func() { log.Println("服务已关闭") }) time.Sleep(time.Second * 5) _, err = request() assert.NotNil(t, err) diff --git a/service/middleware.go b/service/middleware.go index 297fb0a5..1554d061 100644 --- a/service/middleware.go +++ b/service/middleware.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/gin-gonic/gin" - "github.com/yaoapp/yao/share" ) // Middlewares 服务中间件 @@ -22,30 +21,21 @@ func BinStatic(c *gin.Context) { c.Next() return - } else if share.App.XGen == "1.0" { + } - // Xgen 1.0 - 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]) - 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) + // Xgen 1.0 + 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]) + 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 } // 应用内静态文件目录(/ui or public) diff --git a/service/service.go b/service/service.go index bd6cf0e0..f41001ca 100644 --- a/service/service.go +++ b/service/service.go @@ -1,22 +1,21 @@ package service import ( - "context" + "time" "github.com/gin-gonic/gin" "github.com/yaoapp/gou/api" "github.com/yaoapp/gou/server/http" - "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "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) - -// Start 启动服务 -func Start() (*http.Server, error) { + if cfg.AllowFrom == nil { + cfg.AllowFrom = []string{} + } err := prepare() if err != nil { @@ -24,64 +23,46 @@ func Start() (*http.Server, error) { } 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{ - Host: config.Conf.Host, - Port: config.Conf.Port, - Root: "/api", - Allows: config.Conf.AllowFrom, + Host: cfg.Host, + Port: cfg.Port, + Root: "/api", + Allows: cfg.AllowFrom, + Timeout: 5 * time.Second, }).With(Middlewares...) + go func() { + err = srv.Start() + }() + return srv, nil } -// StartWithouttSession 启动服务 -func StartWithouttSession() (*http.Server, error) { - - router := gin.New() - api.SetRoutes(router, "/api", config.Conf.AllowFrom...) - 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() +// Stop the yao service +func Stop(srv *http.Server) error { + err := srv.Stop() + if err != nil { + return err } + <-srv.Event() + return nil } // StopWithContext stop with timeout -func StopWithContext(ctx context.Context, onComplete func()) { - shutdown <- true - select { - case <-ctx.Done(): - log.Error("[STOP] canceled (%v)", ctx.Err()) - onComplete() - case <-shutdownComplete: - share.SessionStop() - onComplete() - } -} +// func StopWithContext(ctx context.Context, onComplete func()) { +// shutdown <- true +// select { +// case <-ctx.Done(): +// log.Error("[STOP] canceled (%v)", ctx.Err()) +// onComplete() +// case <-shutdownComplete: +// share.SessionStop() +// onComplete() +// } +// } func prepare() error { diff --git a/service/service_test.go b/service/service_test.go new file mode 100644 index 00000000..f86495fa --- /dev/null +++ b/service/service_test.go @@ -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/") +} diff --git a/service/static.go b/service/static.go index a13be588..e58aaff4 100644 --- a/service/static.go +++ b/service/static.go @@ -18,9 +18,6 @@ import ( // AppFileServer static file server var AppFileServer http.Handler -// XGenFileServerV0 XGen v0.9 -var XGenFileServerV0 http.Handler = http.FileServer(data.XgenV0()) - // XGenFileServerV1 XGen v1.0 var XGenFileServerV1 http.Handler = http.FileServer(data.XgenV1()) @@ -41,9 +38,6 @@ func SetupStatic() error { // Static file server 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 } diff --git a/service/watch.go b/service/watch.go index 1a8a97a8..48a2f755 100644 --- a/service/watch.go +++ b/service/watch.go @@ -1,7 +1,6 @@ package service import ( - "context" "fmt" "io/fs" "io/ioutil" @@ -262,12 +261,12 @@ func watchReload(root string, file string, event string, cfg config.Config) { } // Restart Server - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() + // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + // defer cancel() - StopWithContext(ctx, func() { - go Start() - fmt.Println(color.GreenString("[Watch] Reload Completed")) - }) + // Stop(func() { + // go Start() + // fmt.Println(color.GreenString("[Watch] Reload Completed")) + // }) } } diff --git a/service/watch_test.go b/service/watch_test.go index e1cd9b37..aad54ec9 100644 --- a/service/watch_test.go +++ b/service/watch_test.go @@ -34,8 +34,8 @@ func TestWatch(t *testing.T) { } func TestWatchReload(t *testing.T) { - go Start() - defer Stop(func() {}) + go Start(config.Conf) + // defer Stop(func() {}) share.DBConnect(config.Conf.DB) watchReload("", "", "", config.Conf) }