Bladeren bron

优化最小服务

fancl 10 maanden geleden
bovenliggende
commit
57c134b6ba
11 gewijzigde bestanden met toevoegingen van 111 en 88 verwijderingen
  1. 1 1
      cmd/main.go
  2. 5 1
      entry/cli/serialize.go
  3. 6 0
      entry/cli/server.go
  4. 6 0
      entry/http/server.go
  5. 30 24
      instance.go
  6. 9 2
      options.go
  7. 29 26
      service.go
  8. 1 0
      types.go
  9. 14 11
      util/fs/dir.go
  10. 0 1
      util/fs/file.go
  11. 10 22
      util/sys/homedir.go

+ 1 - 1
cmd/main.go

@@ -36,7 +36,7 @@ func (s *subServer) Start(ctx context.Context) (err error) {
 			[]string{"SSS", "aaa"},
 		})
 	})
-	
+
 	kos.Command().Handle("/users", "test command", func(ctx *cli.Context) (err error) {
 		return ctx.Success([]*users{
 			{Name: "Zhan", Age: 10, Tags: []string{"a", "b"}},

+ 5 - 1
entry/cli/serialize.go

@@ -191,8 +191,12 @@ func serializeArray(val []any) (buf []byte, err error) {
 					row := make([]any, 0, rv.Type().NumField())
 					for j := 0; j < rv.Type().NumField(); j++ {
 						st := rv.Type().Field(j).Tag
-						if columnName, ok = st.Lookup("name"); !ok {
+						if columnName, ok = st.Lookup("kos"); !ok {
 							columnName = strings.ToUpper(rv.Type().Field(j).Name)
+						} else {
+							if columnName == "-" {
+								continue
+							}
 						}
 						row = append(row, columnName)
 					}

+ 6 - 0
entry/cli/server.go

@@ -10,6 +10,7 @@ import (
 	"runtime"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	"git.nspix.com/golang/kos/util/env"
@@ -29,6 +30,7 @@ type Server struct {
 	middleware     []Middleware
 	router         *Router
 	l              net.Listener
+	exitFlag       int32
 }
 
 func (svr *Server) applyContext() *Context {
@@ -200,10 +202,14 @@ func (svr *Server) Serve(l net.Listener) (err error) {
 		return ctx.Success(svr.router.String())
 	})
 	svr.serve()
+	atomic.StoreInt32(&svr.exitFlag, 0)
 	return
 }
 
 func (svr *Server) Shutdown() (err error) {
+	if !atomic.CompareAndSwapInt32(&svr.exitFlag, 0, 1) {
+		return
+	}
 	err = svr.l.Close()
 	svr.ctxMap.Range(func(key, value any) bool {
 		if ctx, ok := value.(*Context); ok {

+ 6 - 0
entry/http/server.go

@@ -9,6 +9,7 @@ import (
 	"path"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
@@ -26,6 +27,7 @@ type Server struct {
 	fileSystem         http.FileSystem
 	beforeRequests     []HandleFunc
 	anyRequests        map[string]http.Handler
+	exitFlag           int32
 }
 
 func (svr *Server) applyContext() *Context {
@@ -216,10 +218,14 @@ func (svr *Server) Serve(l net.Listener) (err error) {
 	}
 	svr.router.NotFound = NotFound{}
 	svr.router.MethodNotAllowed = NotAllowed{}
+	atomic.StoreInt32(&svr.exitFlag, 0)
 	return svr.serve.Serve(l)
 }
 
 func (svr *Server) Shutdown() (err error) {
+	if !atomic.CompareAndSwapInt32(&svr.exitFlag, 0, 1) {
+		return
+	}
 	if svr.serve != nil {
 		err = svr.serve.Shutdown(svr.ctx)
 	}

+ 30 - 24
instance.go

@@ -19,53 +19,59 @@ var (
 	std  *application
 )
 
-func initApplication(cbs ...Option) {
+func initialization(cbs ...Option) {
 	once.Do(func() {
 		std = New(cbs...)
 	})
 }
 
-func Init(cbs ...Option) *application {
-	initApplication(cbs...)
+func Init(cbs ...Option) Application {
+	initialization(cbs...)
 	return std
 }
 
-func Node() *Info {
-	initApplication()
-	return std.Info()
-}
-
-func Http() *http.Server {
-	initApplication()
-	return std.Http()
-}
-
 func Name() string {
-	initApplication()
+	initialization()
 	return std.opts.Name
 }
 
+func ShortName() string {
+	initialization()
+	return std.opts.ShortName()
+}
+
 func Version() string {
-	initApplication()
+	initialization()
 	return std.opts.Version
 }
 
-func Debug() bool {
-	initApplication()
+func Debug(args ...any) bool {
+	initialization()
+	if len(args) <= 0 {
+		return std.opts.EnableDebug
+	}
+	if b, ok := args[0].(bool); ok {
+		std.opts.EnableDebug = b
+	}
 	return std.opts.EnableDebug
 }
 
-func Command() *cli.Server {
-	initApplication()
-	return std.Command()
+func Node() *Info {
+	initialization()
+	return std.Info()
 }
 
-func ShortName() string {
-	initApplication()
-	return std.opts.ShortName()
+func Http() *http.Server {
+	initialization()
+	return std.Http()
+}
+
+func Command() *cli.Server {
+	initialization()
+	return std.Command()
 }
 
 func Handle(method string, cb HandleFunc) {
-	initApplication()
+	initialization()
 	std.Handle(method, cb)
 }

+ 9 - 2
options.go

@@ -18,10 +18,11 @@ type (
 		Address             string            //绑定地址
 		Port                int               //端口
 		EnableDebug         bool              //开启调试模式
+		DisableGateway      bool              //禁用HTTP和COMMAND入口
 		DisableHttp         bool              //禁用HTTP入口
 		EnableDirectHttp    bool              //启用HTTP直连模式
-		DisableCommand      bool              //禁用命令行入口
-		EnableDirectCommand bool              //启用命令行直连模式
+		DisableCommand      bool              //禁用COMMAND入口
+		EnableDirectCommand bool              //启用COMMAND直连模式
 		DisableStateApi     bool              //禁用系统状态接口
 		Metadata            map[string]string //原数据
 		Context             context.Context
@@ -64,6 +65,12 @@ func WithName(name string, version string) Option {
 	}
 }
 
+func WithoutGateway() Option {
+	return func(o *Options) {
+		o.DisableGateway = true
+	}
+}
+
 func WithPort(port int) Option {
 	return func(o *Options) {
 		o.Port = port

+ 29 - 26
service.go

@@ -94,7 +94,6 @@ func (app *application) httpServe() (err error) {
 	var (
 		l net.Listener
 	)
-	app.http = http.New(app.ctx)
 	if l, err = app.gateway.Apply(
 		entry.Feature(http.MethodGet),
 		entry.Feature(http.MethodHead),
@@ -141,7 +140,6 @@ func (app *application) commandServe() (err error) {
 	var (
 		l net.Listener
 	)
-	app.command = cli.New(app.ctx)
 	if l, err = app.gateway.Apply(
 		cli.Feature,
 	); err != nil {
@@ -213,23 +211,26 @@ func (app *application) preStart() (err error) {
 	app.Log().Infof("server starting")
 	env.Set(EnvAppName, app.opts.ShortName())
 	env.Set(EnvAppVersion, app.opts.Version)
-	addr = net.JoinHostPort(app.opts.Address, strconv.Itoa(app.opts.Port))
-	app.Log().Infof("server listen on: %s", addr)
-	app.gateway = entry.New(addr)
-	if err = app.gateway.Start(app.ctx); err != nil {
-		return
-	}
-	if !app.opts.DisableHttp {
-		if err = app.httpServe(); err != nil {
+	app.http = http.New(app.ctx)
+	app.command = cli.New(app.ctx)
+	if !app.opts.DisableGateway {
+		addr = net.JoinHostPort(app.opts.Address, strconv.Itoa(app.opts.Port))
+		app.Log().Infof("server listen on: %s", addr)
+		app.gateway = entry.New(addr)
+		if err = app.gateway.Start(app.ctx); err != nil {
 			return
 		}
-	}
-	if !app.opts.DisableCommand {
-		if err = app.commandServe(); err != nil {
-			return
+		if !app.opts.DisableHttp {
+			if err = app.httpServe(); err != nil {
+				return
+			}
+		}
+		if !app.opts.DisableCommand {
+			if err = app.commandServe(); err != nil {
+				return
+			}
 		}
 	}
-
 	app.plugins.Range(func(key, value any) bool {
 		if plugin, ok := value.(Plugin); ok {
 			if err = plugin.BeforeStart(); err != nil {
@@ -289,18 +290,20 @@ func (app *application) preStop() (err error) {
 		}
 		return true
 	})
-	if app.http != nil {
-		if err = app.http.Shutdown(); err != nil {
-			app.Log().Warnf("server http shutdown error: %s", err.Error())
+	if !app.opts.DisableGateway {
+		if app.http != nil {
+			if err = app.http.Shutdown(); err != nil {
+				app.Log().Warnf("server http shutdown error: %s", err.Error())
+			}
 		}
-	}
-	if app.command != nil {
-		if err = app.command.Shutdown(); err != nil {
-			app.Log().Warnf("server command shutdown error: %s", err.Error())
+		if app.command != nil {
+			if err = app.command.Shutdown(); err != nil {
+				app.Log().Warnf("server command shutdown error: %s", err.Error())
+			}
+		}
+		if err = app.gateway.Stop(); err != nil {
+			app.Log().Warnf("server gateway shutdown error: %s", err.Error())
 		}
-	}
-	if err = app.gateway.Stop(); err != nil {
-		app.Log().Warnf("server gateway shutdown error: %s", err.Error())
 	}
 	app.plugins.Range(func(key, value any) bool {
 		if plugin, ok := value.(Plugin); ok {
@@ -345,7 +348,7 @@ func (app *application) Run() (err error) {
 	return app.preStop()
 }
 
-func New(cbs ...Option) *application {
+func New(cbs ...Option) Application {
 	opts := NewOptions(cbs...)
 	app := &application{
 		opts:   opts,

+ 1 - 0
types.go

@@ -23,6 +23,7 @@ type (
 		Http() *http.Server
 		Command() *cli.Server
 		Handle(method string, cb HandleFunc, opts ...HandleOption)
+		Run() (err error)
 	}
 
 	// Info application information

+ 14 - 11
util/fs/dir.go

@@ -1,7 +1,6 @@
 package fs
 
 import (
-	"errors"
 	"os"
 )
 
@@ -11,22 +10,26 @@ func IsDir(filename string) (bool, error) {
 	if err != nil {
 		return false, err
 	}
-	fm := fd.Mode()
-	return fm.IsDir(), nil
+	return fd.Mode().IsDir(), nil
 }
 
-// DirectoryOrCreate checking directory, is not exists will create
-func DirectoryOrCreate(dirname string) error {
+// IsFile Tells whether the filename is a file
+func IsFile(filename string) (bool, error) {
+	fd, err := os.Stat(filename)
+	if err != nil {
+		return false, err
+	}
+	return !fd.Mode().IsDir(), nil
+}
+
+// Mkdir checking directory, is not exists will create
+func Mkdir(dirname string, perm os.FileMode) error {
 	if fi, err := os.Stat(dirname); err != nil {
-		if errors.Is(err, os.ErrNotExist) {
-			return os.MkdirAll(dirname, 0755)
-		} else {
-			return err
-		}
+		return os.MkdirAll(dirname, perm)
 	} else {
 		if fi.IsDir() {
 			return nil
 		}
-		return errors.New("file not directory")
+		return os.ErrPermission
 	}
 }

+ 0 - 1
util/fs/file.go

@@ -1 +0,0 @@
-package fs

+ 10 - 22
util/sys/homedir.go

@@ -2,19 +2,15 @@ package sys
 
 import (
 	"os"
-	"path/filepath"
 	"runtime"
 )
 
 // HomeDir return user home directory
 func HomeDir() string {
-	if runtime.GOOS == "windows" {
-		return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+	if dirname, err := os.UserHomeDir(); err == nil {
+		return dirname
 	}
-	if h := os.Getenv("HOME"); h != "" {
-		return h
-	}
-	return "/"
+	return os.TempDir()
 }
 
 // HiddenFile get hidden file prefix
@@ -29,20 +25,12 @@ func HiddenFile(name string) string {
 
 // CacheDir return user cache directory
 func CacheDir() string {
-	switch runtime.GOOS {
-	case "darwin":
-		return filepath.Join(HomeDir(), "Library", "Caches")
-	case "windows":
-		for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
-			if v := os.Getenv(ev); v != "" {
-				return v
-			}
-		}
-		// Worst case:
-		return HomeDir()
+	if dirname, err := os.UserCacheDir(); err == nil {
+		return dirname
 	}
-	if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
-		return xdg
-	}
-	return filepath.Join(HomeDir(), ".cache")
+	return os.TempDir()
+}
+
+func TempFile() (*os.File, error) {
+	return os.CreateTemp(os.TempDir(), "kos_*")
 }