优化最小服务
This commit is contained in:
parent
281b44f637
commit
57c134b6ba
|
@ -191,8 +191,12 @@ func serializeArray(val []any) (buf []byte, err error) {
|
||||||
row := make([]any, 0, rv.Type().NumField())
|
row := make([]any, 0, rv.Type().NumField())
|
||||||
for j := 0; j < rv.Type().NumField(); j++ {
|
for j := 0; j < rv.Type().NumField(); j++ {
|
||||||
st := rv.Type().Field(j).Tag
|
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)
|
columnName = strings.ToUpper(rv.Type().Field(j).Name)
|
||||||
|
} else {
|
||||||
|
if columnName == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
row = append(row, columnName)
|
row = append(row, columnName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.nspix.com/golang/kos/util/env"
|
"git.nspix.com/golang/kos/util/env"
|
||||||
|
@ -29,6 +30,7 @@ type Server struct {
|
||||||
middleware []Middleware
|
middleware []Middleware
|
||||||
router *Router
|
router *Router
|
||||||
l net.Listener
|
l net.Listener
|
||||||
|
exitFlag int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Server) applyContext() *Context {
|
func (svr *Server) applyContext() *Context {
|
||||||
|
@ -200,10 +202,14 @@ func (svr *Server) Serve(l net.Listener) (err error) {
|
||||||
return ctx.Success(svr.router.String())
|
return ctx.Success(svr.router.String())
|
||||||
})
|
})
|
||||||
svr.serve()
|
svr.serve()
|
||||||
|
atomic.StoreInt32(&svr.exitFlag, 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Server) Shutdown() (err error) {
|
func (svr *Server) Shutdown() (err error) {
|
||||||
|
if !atomic.CompareAndSwapInt32(&svr.exitFlag, 0, 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = svr.l.Close()
|
err = svr.l.Close()
|
||||||
svr.ctxMap.Range(func(key, value any) bool {
|
svr.ctxMap.Range(func(key, value any) bool {
|
||||||
if ctx, ok := value.(*Context); ok {
|
if ctx, ok := value.(*Context); ok {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ type Server struct {
|
||||||
fileSystem http.FileSystem
|
fileSystem http.FileSystem
|
||||||
beforeRequests []HandleFunc
|
beforeRequests []HandleFunc
|
||||||
anyRequests map[string]http.Handler
|
anyRequests map[string]http.Handler
|
||||||
|
exitFlag int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Server) applyContext() *Context {
|
func (svr *Server) applyContext() *Context {
|
||||||
|
@ -216,10 +218,14 @@ func (svr *Server) Serve(l net.Listener) (err error) {
|
||||||
}
|
}
|
||||||
svr.router.NotFound = NotFound{}
|
svr.router.NotFound = NotFound{}
|
||||||
svr.router.MethodNotAllowed = NotAllowed{}
|
svr.router.MethodNotAllowed = NotAllowed{}
|
||||||
|
atomic.StoreInt32(&svr.exitFlag, 0)
|
||||||
return svr.serve.Serve(l)
|
return svr.serve.Serve(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Server) Shutdown() (err error) {
|
func (svr *Server) Shutdown() (err error) {
|
||||||
|
if !atomic.CompareAndSwapInt32(&svr.exitFlag, 0, 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if svr.serve != nil {
|
if svr.serve != nil {
|
||||||
err = svr.serve.Shutdown(svr.ctx)
|
err = svr.serve.Shutdown(svr.ctx)
|
||||||
}
|
}
|
||||||
|
|
60
instance.go
60
instance.go
|
@ -19,53 +19,59 @@ var (
|
||||||
std *application
|
std *application
|
||||||
)
|
)
|
||||||
|
|
||||||
func initApplication(cbs ...Option) {
|
func initialization(cbs ...Option) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
std = New(cbs...)
|
std = New(cbs...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Init(cbs ...Option) *application {
|
func Init(cbs ...Option) Application {
|
||||||
initApplication(cbs...)
|
initialization(cbs...)
|
||||||
return std
|
return std
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Name() string {
|
||||||
|
initialization()
|
||||||
|
return std.opts.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShortName() string {
|
||||||
|
initialization()
|
||||||
|
return std.opts.ShortName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Version() string {
|
||||||
|
initialization()
|
||||||
|
return std.opts.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Node() *Info {
|
func Node() *Info {
|
||||||
initApplication()
|
initialization()
|
||||||
return std.Info()
|
return std.Info()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Http() *http.Server {
|
func Http() *http.Server {
|
||||||
initApplication()
|
initialization()
|
||||||
return std.Http()
|
return std.Http()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Name() string {
|
|
||||||
initApplication()
|
|
||||||
return std.opts.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func Version() string {
|
|
||||||
initApplication()
|
|
||||||
return std.opts.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug() bool {
|
|
||||||
initApplication()
|
|
||||||
return std.opts.EnableDebug
|
|
||||||
}
|
|
||||||
|
|
||||||
func Command() *cli.Server {
|
func Command() *cli.Server {
|
||||||
initApplication()
|
initialization()
|
||||||
return std.Command()
|
return std.Command()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShortName() string {
|
|
||||||
initApplication()
|
|
||||||
return std.opts.ShortName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Handle(method string, cb HandleFunc) {
|
func Handle(method string, cb HandleFunc) {
|
||||||
initApplication()
|
initialization()
|
||||||
std.Handle(method, cb)
|
std.Handle(method, cb)
|
||||||
}
|
}
|
||||||
|
|
11
options.go
11
options.go
|
@ -18,10 +18,11 @@ type (
|
||||||
Address string //绑定地址
|
Address string //绑定地址
|
||||||
Port int //端口
|
Port int //端口
|
||||||
EnableDebug bool //开启调试模式
|
EnableDebug bool //开启调试模式
|
||||||
|
DisableGateway bool //禁用HTTP和COMMAND入口
|
||||||
DisableHttp bool //禁用HTTP入口
|
DisableHttp bool //禁用HTTP入口
|
||||||
EnableDirectHttp bool //启用HTTP直连模式
|
EnableDirectHttp bool //启用HTTP直连模式
|
||||||
DisableCommand bool //禁用命令行入口
|
DisableCommand bool //禁用COMMAND入口
|
||||||
EnableDirectCommand bool //启用命令行直连模式
|
EnableDirectCommand bool //启用COMMAND直连模式
|
||||||
DisableStateApi bool //禁用系统状态接口
|
DisableStateApi bool //禁用系统状态接口
|
||||||
Metadata map[string]string //原数据
|
Metadata map[string]string //原数据
|
||||||
Context context.Context
|
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 {
|
func WithPort(port int) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Port = port
|
o.Port = port
|
||||||
|
|
11
service.go
11
service.go
|
@ -94,7 +94,6 @@ func (app *application) httpServe() (err error) {
|
||||||
var (
|
var (
|
||||||
l net.Listener
|
l net.Listener
|
||||||
)
|
)
|
||||||
app.http = http.New(app.ctx)
|
|
||||||
if l, err = app.gateway.Apply(
|
if l, err = app.gateway.Apply(
|
||||||
entry.Feature(http.MethodGet),
|
entry.Feature(http.MethodGet),
|
||||||
entry.Feature(http.MethodHead),
|
entry.Feature(http.MethodHead),
|
||||||
|
@ -141,7 +140,6 @@ func (app *application) commandServe() (err error) {
|
||||||
var (
|
var (
|
||||||
l net.Listener
|
l net.Listener
|
||||||
)
|
)
|
||||||
app.command = cli.New(app.ctx)
|
|
||||||
if l, err = app.gateway.Apply(
|
if l, err = app.gateway.Apply(
|
||||||
cli.Feature,
|
cli.Feature,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -213,6 +211,9 @@ func (app *application) preStart() (err error) {
|
||||||
app.Log().Infof("server starting")
|
app.Log().Infof("server starting")
|
||||||
env.Set(EnvAppName, app.opts.ShortName())
|
env.Set(EnvAppName, app.opts.ShortName())
|
||||||
env.Set(EnvAppVersion, app.opts.Version)
|
env.Set(EnvAppVersion, app.opts.Version)
|
||||||
|
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))
|
addr = net.JoinHostPort(app.opts.Address, strconv.Itoa(app.opts.Port))
|
||||||
app.Log().Infof("server listen on: %s", addr)
|
app.Log().Infof("server listen on: %s", addr)
|
||||||
app.gateway = entry.New(addr)
|
app.gateway = entry.New(addr)
|
||||||
|
@ -229,7 +230,7 @@ func (app *application) preStart() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
app.plugins.Range(func(key, value any) bool {
|
app.plugins.Range(func(key, value any) bool {
|
||||||
if plugin, ok := value.(Plugin); ok {
|
if plugin, ok := value.(Plugin); ok {
|
||||||
if err = plugin.BeforeStart(); err != nil {
|
if err = plugin.BeforeStart(); err != nil {
|
||||||
|
@ -289,6 +290,7 @@ func (app *application) preStop() (err error) {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
if !app.opts.DisableGateway {
|
||||||
if app.http != nil {
|
if app.http != nil {
|
||||||
if err = app.http.Shutdown(); err != nil {
|
if err = app.http.Shutdown(); err != nil {
|
||||||
app.Log().Warnf("server http shutdown error: %s", err.Error())
|
app.Log().Warnf("server http shutdown error: %s", err.Error())
|
||||||
|
@ -302,6 +304,7 @@ func (app *application) preStop() (err error) {
|
||||||
if err = app.gateway.Stop(); err != nil {
|
if err = app.gateway.Stop(); err != nil {
|
||||||
app.Log().Warnf("server gateway shutdown error: %s", err.Error())
|
app.Log().Warnf("server gateway shutdown error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
app.plugins.Range(func(key, value any) bool {
|
app.plugins.Range(func(key, value any) bool {
|
||||||
if plugin, ok := value.(Plugin); ok {
|
if plugin, ok := value.(Plugin); ok {
|
||||||
if err = plugin.AfterStop(); err != nil {
|
if err = plugin.AfterStop(); err != nil {
|
||||||
|
@ -345,7 +348,7 @@ func (app *application) Run() (err error) {
|
||||||
return app.preStop()
|
return app.preStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cbs ...Option) *application {
|
func New(cbs ...Option) Application {
|
||||||
opts := NewOptions(cbs...)
|
opts := NewOptions(cbs...)
|
||||||
app := &application{
|
app := &application{
|
||||||
opts: opts,
|
opts: opts,
|
||||||
|
|
1
types.go
1
types.go
|
@ -23,6 +23,7 @@ type (
|
||||||
Http() *http.Server
|
Http() *http.Server
|
||||||
Command() *cli.Server
|
Command() *cli.Server
|
||||||
Handle(method string, cb HandleFunc, opts ...HandleOption)
|
Handle(method string, cb HandleFunc, opts ...HandleOption)
|
||||||
|
Run() (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info application information
|
// Info application information
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,22 +10,26 @@ func IsDir(filename string) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
fm := fd.Mode()
|
return fd.Mode().IsDir(), nil
|
||||||
return fm.IsDir(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectoryOrCreate checking directory, is not exists will create
|
// IsFile Tells whether the filename is a file
|
||||||
func DirectoryOrCreate(dirname string) error {
|
func IsFile(filename string) (bool, error) {
|
||||||
if fi, err := os.Stat(dirname); err != nil {
|
fd, err := os.Stat(filename)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if err != nil {
|
||||||
return os.MkdirAll(dirname, 0755)
|
return false, err
|
||||||
} else {
|
|
||||||
return 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 {
|
||||||
|
return os.MkdirAll(dirname, perm)
|
||||||
} else {
|
} else {
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("file not directory")
|
return os.ErrPermission
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package fs
|
|
|
@ -2,19 +2,15 @@ package sys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HomeDir return user home directory
|
// HomeDir return user home directory
|
||||||
func HomeDir() string {
|
func HomeDir() string {
|
||||||
if runtime.GOOS == "windows" {
|
if dirname, err := os.UserHomeDir(); err == nil {
|
||||||
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
return dirname
|
||||||
}
|
}
|
||||||
if h := os.Getenv("HOME"); h != "" {
|
return os.TempDir()
|
||||||
return h
|
|
||||||
}
|
|
||||||
return "/"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HiddenFile get hidden file prefix
|
// HiddenFile get hidden file prefix
|
||||||
|
@ -29,20 +25,12 @@ func HiddenFile(name string) string {
|
||||||
|
|
||||||
// CacheDir return user cache directory
|
// CacheDir return user cache directory
|
||||||
func CacheDir() string {
|
func CacheDir() string {
|
||||||
switch runtime.GOOS {
|
if dirname, err := os.UserCacheDir(); err == nil {
|
||||||
case "darwin":
|
return dirname
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
return os.TempDir()
|
||||||
}
|
}
|
||||||
// Worst case:
|
|
||||||
return HomeDir()
|
func TempFile() (*os.File, error) {
|
||||||
}
|
return os.CreateTemp(os.TempDir(), "kos_*")
|
||||||
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
|
||||||
return xdg
|
|
||||||
}
|
|
||||||
return filepath.Join(HomeDir(), ".cache")
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue