diff --git a/go.mod b/go.mod index 0479012..67f3830 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module apigo.cc/gojs/service go 1.18 require ( - apigo.cc/gojs v0.0.3 + apigo.cc/gojs v0.0.4 apigo.cc/gojs/console v0.0.1 apigo.cc/gojs/http v0.0.3 - apigo.cc/gojs/util v0.0.2 + apigo.cc/gojs/util v0.0.3 github.com/gorilla/websocket v1.5.3 github.com/ssgo/config v1.7.8 github.com/ssgo/discover v1.7.9 github.com/ssgo/httpclient v1.7.8 github.com/ssgo/log v1.7.7 github.com/ssgo/redis v1.7.7 - github.com/ssgo/s v1.7.17 + github.com/ssgo/s v1.7.18 github.com/ssgo/standard v1.7.7 github.com/ssgo/u v1.7.9 ) diff --git a/service.go b/service.go index b953faf..74fceb5 100644 --- a/service.go +++ b/service.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "path/filepath" "reflect" "regexp" "strings" @@ -66,10 +67,17 @@ var serviceConfig Config var onStop goja.Callable var limiters = map[string]*s.Limiter{} +var configed = false func init() { + s.Config.KeepKeyCase = true obj := map[string]any{ "config": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + configed = true + s.InitConfig() + if startPath, ok := vm.GoData["startPath"]; ok { + s.SetWorkPath(u.String(startPath)) + } // 处理配置 args := gojs.MakeArgs(&argsIn, vm) serviceConfig = Config{"Session", "Device", "Client", "userId", "", 3600, "auth failed", "verify failed", "too many requests", nil, "", map[string]string{}, map[string]string{}, map[string]string{}} @@ -165,6 +173,9 @@ func init() { return nil }, "start": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { + if !configed { + panic(vm.NewGoError(errors.New("must run service.config frist"))) + } if server != nil { panic(vm.NewGoError(errors.New("server already started"))) } @@ -190,6 +201,9 @@ func init() { } }) server.OnStopped(func() { + ClearRewritesAndProxies() + pools = map[string]*gojs.Pool{} + server = nil if waitChan != nil { waitChan <- true } @@ -201,9 +215,6 @@ func init() { panic(vm.NewGoError(errors.New("server not started"))) } server.Stop() - ClearRewritesAndProxies() - pools = map[string]*gojs.Pool{} - server = nil return nil }, "register": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value { @@ -225,6 +236,13 @@ func init() { usedLimiters = append(usedLimiters, limiter1) } } + if requiresObj := o.Array("requires"); requiresObj != nil { + requires := make([]string, len(requiresObj)) + for i, require := range requiresObj { + requires[i] = u.String(require) + } + vm.GoData[fmt.Sprint("REQUIRE_"+host, method, path)] = requires + } if verifiesObj := o.Obj("verifies"); verifiesObj != nil { verifiesSet := map[string]func(any, *goja.Runtime) bool{} for _, field := range verifiesObj.Keys() { @@ -319,7 +337,8 @@ func init() { } } if !u.FileExists(actionFile) { - panic(vm.NewGoError(errors.New("actionFile must be a js file path"))) + fullActionFile, _ := filepath.Abs(actionFile) + panic(vm.NewGoError(errors.New("actionFile must be a js file path: " + fullActionFile))) } actionCode := u.ReadFileN(actionFile) if !strings.Contains(actionCode, "function main(") || !strings.Contains(actionCode, ".register(") { @@ -363,7 +382,6 @@ func init() { if err != nil { panic(vm.NewGoError(err)) } - println(u.BMagenta("taskFile: "), taskFile, interval) s.NewTimerServer(taskFile, time.Duration(interval)*time.Millisecond, func(isRunning *bool) { rt.RunCode("if(onRun)onRun()") }, func() { @@ -390,6 +408,11 @@ func init() { Object: obj, TsCode: serviceTS, Example: serviceMD, + OnKill: func() { + if server != nil { + server.Stop() + } + }, WaitForStop: func() { if waitChan != nil { <-waitChan @@ -487,6 +510,15 @@ func runAction(action goja.Callable, vm *goja.Runtime, thisArg goja.Value, args // 验证请求参数的有效性 if verifies, ok := vm.GoData["VERIFY_"+u.String(request.Get("registerTag"))].(map[string]func(any, *goja.Runtime) bool); ok { failedFields := make([]string, 0) + // 检查必填字段 + if requires, ok := vm.GoData["REQUIRE_"+u.String(request.Get("registerTag"))].([]string); ok { + for _, requireField := range requires { + if _, ok := args[requireField]; !ok { + failedFields = append(failedFields, requireField) + } + } + } + // 验证数据有效性 for k, v := range args { if verifier, ok1 := verifies[k]; ok1 { if !verifier(v, vm) { diff --git a/service.ts b/service.ts index e311e49..a180d68 100644 --- a/service.ts +++ b/service.ts @@ -75,7 +75,7 @@ interface Config { memoryLimitTimes: number // 内存超过最高占用值超过次数(1-100)将报警(如果MemoryMonitor开启的话),默认6(即30秒内连续6次) cookieScope: string // 启用Session时Cookie的有效范围,host|domain|topDomain,默认值为host idServer: string // 用s.UniqueId、s.Id来生成唯一ID(雪花算法)时所需的redis服务器连接,如果不指定将不能实现跨服务的全局唯一 - keepKeyCase: boolean // 是否保持Key的首字母大小写?默认一律使用小写 + keepKeyCase: boolean // 是否保持Key的首字母大小写?默认保持,设置为false则自动将首字母转为小写 indexFiles: string[] // 访问静态文件时的索引文件,默认为 index.html indexDir: boolean // 访问目录时显示文件列表 readTimeout: number // 读取请求的超时时间,单位ms @@ -145,6 +145,8 @@ interface RegisterOption { noBody: boolean noLog200: boolean limiters: string[] + verifies: Object + requires: string[] onMessage: (params: OnMessageParams) => void onClose: (params: RequestParams) => void }