升级异常处理机制
This commit is contained in:
parent
fa97cace29
commit
627c05fd06
@ -22,7 +22,10 @@ func NewCaller(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|||||||
|
|
||||||
func makeResult(r *httpclient.Result, vm *goja.Runtime) goja.Value {
|
func makeResult(r *httpclient.Result, vm *goja.Runtime) goja.Value {
|
||||||
if r.Error != nil {
|
if r.Error != nil {
|
||||||
panic(vm.NewGoError(r.Error))
|
// panic(vm.NewGoError(r.Error))
|
||||||
|
vm.SetData("_lastError", r.Error)
|
||||||
|
gojs.GetLogger(vm).Error(r.Error.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
headers := map[string]string{}
|
headers := map[string]string{}
|
||||||
for k, v := range r.Response.Header {
|
for k, v := range r.Response.Header {
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -3,7 +3,7 @@ module apigo.cc/gojs/service
|
|||||||
go 1.24.0
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/gojs v0.0.31
|
apigo.cc/gojs v0.0.32
|
||||||
apigo.cc/gojs/console v0.0.4
|
apigo.cc/gojs/console v0.0.4
|
||||||
apigo.cc/gojs/file v0.0.7
|
apigo.cc/gojs/file v0.0.7
|
||||||
apigo.cc/gojs/http v0.0.8
|
apigo.cc/gojs/http v0.0.8
|
||||||
@ -14,7 +14,7 @@ require (
|
|||||||
github.com/ssgo/config v1.7.10
|
github.com/ssgo/config v1.7.10
|
||||||
github.com/ssgo/discover v1.7.10
|
github.com/ssgo/discover v1.7.10
|
||||||
github.com/ssgo/httpclient v1.7.8
|
github.com/ssgo/httpclient v1.7.8
|
||||||
github.com/ssgo/log v1.7.9
|
github.com/ssgo/log v1.7.10
|
||||||
github.com/ssgo/redis v1.7.8
|
github.com/ssgo/redis v1.7.8
|
||||||
github.com/ssgo/s v1.7.25
|
github.com/ssgo/s v1.7.25
|
||||||
github.com/ssgo/standard v1.7.7
|
github.com/ssgo/standard v1.7.7
|
||||||
|
|||||||
15
request.go
15
request.go
@ -91,7 +91,10 @@ func (r *Request) MakeURL(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value
|
|||||||
func (r *Request) ReadAll(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
func (r *Request) ReadAll(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
data, err := io.ReadAll(r.req.Body)
|
data, err := io.ReadAll(r.req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return vm.ToValue(data)
|
return vm.ToValue(data)
|
||||||
}
|
}
|
||||||
@ -102,7 +105,10 @@ func (r *Request) Read(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|||||||
data := make([]byte, size)
|
data := make([]byte, size)
|
||||||
n, err := r.req.Body.Read(data)
|
n, err := r.req.Body.Read(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return vm.ToValue(data[0:n])
|
return vm.ToValue(data[0:n])
|
||||||
}
|
}
|
||||||
@ -110,7 +116,10 @@ func (r *Request) Read(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|||||||
func (r *Request) Close(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
func (r *Request) Close(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
err := r.req.Body.Close()
|
err := r.req.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
292
service.go
292
service.go
@ -50,10 +50,11 @@ type TplCache struct {
|
|||||||
Tpl *template.Template
|
Tpl *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
var tplFunc = map[string]any{}
|
// var tplFunc = map[string]any{}
|
||||||
var tplFuncLock = sync.RWMutex{}
|
var tplReplaces = map[string]string{}
|
||||||
var tplCache = map[string]*TplCache{}
|
var tplLock = sync.RWMutex{}
|
||||||
var tplCacheLock = sync.RWMutex{}
|
|
||||||
|
// var tplCache = map[string]*TplCache{}
|
||||||
|
|
||||||
type LimiterConfig struct {
|
type LimiterConfig struct {
|
||||||
From string
|
From string
|
||||||
@ -74,6 +75,7 @@ type Config struct {
|
|||||||
Limiters map[string]*LimiterConfig
|
Limiters map[string]*LimiterConfig
|
||||||
LimiterRedis string
|
LimiterRedis string
|
||||||
HotLoad int
|
HotLoad int
|
||||||
|
TplSafePaths []string
|
||||||
|
|
||||||
Proxy map[string]string
|
Proxy map[string]string
|
||||||
Rewrite map[string]string
|
Rewrite map[string]string
|
||||||
@ -93,9 +95,12 @@ func initConfig(opt *gojs.Obj, logger *log.Logger, vm *goja.Runtime) {
|
|||||||
s.SetWorkPath(u.String(startPath))
|
s.SetWorkPath(u.String(startPath))
|
||||||
}
|
}
|
||||||
// 处理配置
|
// 处理配置
|
||||||
serviceConfig = Config{"Session", "Device", "Client", "id", "", 3600, "auth failed", "verify failed", "too many requests", nil, "", 0, map[string]string{}, map[string]string{}, map[string]string{}}
|
serviceConfig = Config{"Session", "Device", "Client", "id", "", 3600, "auth failed", "verify failed", "too many requests", nil, "", 0, []string{}, map[string]string{}, map[string]string{}, map[string]string{}}
|
||||||
if errs := config.LoadConfig("service", &serviceConfig); len(errs) > 0 {
|
if errs := config.LoadConfig("service", &serviceConfig); len(errs) > 0 {
|
||||||
panic(vm.NewGoError(errs[0]))
|
// panic(vm.NewGoError(errs[0]))
|
||||||
|
vm.SetData("_lastError", errs[0])
|
||||||
|
gojs.GetLogger(vm).Error(errs[0].Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
config.LoadConfig("service", &discover.Config)
|
config.LoadConfig("service", &discover.Config)
|
||||||
// var auth goja.Callable
|
// var auth goja.Callable
|
||||||
@ -138,6 +143,7 @@ func initConfig(opt *gojs.Obj, logger *log.Logger, vm *goja.Runtime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有session中的authLevel验证失败,则使用Access-Token中的authLevel(服务间调用)
|
// 如果没有session中的authLevel验证失败,则使用Access-Token中的authLevel(服务间调用)
|
||||||
if authAccessToken && setAuthLevel < authLevel {
|
if authAccessToken && setAuthLevel < authLevel {
|
||||||
setAuthLevel = s.GetAuthTokenLevel(request.Header.Get("Access-Token"))
|
setAuthLevel = s.GetAuthTokenLevel(request.Header.Get("Access-Token"))
|
||||||
@ -251,7 +257,10 @@ func init() {
|
|||||||
// panic(vm.NewGoError(errors.New("must run service.config frist")))
|
// panic(vm.NewGoError(errors.New("must run service.config frist")))
|
||||||
}
|
}
|
||||||
if server != nil {
|
if server != nil {
|
||||||
panic(vm.NewGoError(errors.New("server already started")))
|
// panic(vm.NewGoError(errors.New("server already started")))
|
||||||
|
vm.SetData("_lastError", errors.New("server already started"))
|
||||||
|
gojs.GetLogger(vm).Error("server already started")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// 处理静态文件
|
// 处理静态文件
|
||||||
if len(serviceConfig.Static) > 0 {
|
if len(serviceConfig.Static) > 0 {
|
||||||
@ -362,7 +371,10 @@ func init() {
|
|||||||
},
|
},
|
||||||
"stop": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"stop": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
if server == nil {
|
if server == nil {
|
||||||
panic(vm.NewGoError(errors.New("server not started")))
|
// panic(vm.NewGoError(errors.New("server not started")))
|
||||||
|
vm.SetData("_lastError", errors.New("server not started"))
|
||||||
|
gojs.GetLogger(vm).Error("server not started")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
server.Stop()
|
server.Stop()
|
||||||
s.ResetAllSets()
|
s.ResetAllSets()
|
||||||
@ -480,7 +492,10 @@ func init() {
|
|||||||
o := args.Obj(0)
|
o := args.Obj(0)
|
||||||
action := args.Func(1)
|
action := args.Func(1)
|
||||||
if action == nil {
|
if action == nil {
|
||||||
panic(vm.NewGoError(errors.New("action must be a callback function")))
|
// panic(vm.NewGoError(errors.New("action must be a callback function")))
|
||||||
|
vm.SetData("_lastError", errors.New("action must be a callback function"))
|
||||||
|
gojs.GetLogger(vm).Error("action must be a callback function")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
authLevel := o.Int("authLevel")
|
authLevel := o.Int("authLevel")
|
||||||
@ -597,11 +612,17 @@ func init() {
|
|||||||
fi := u.GetFileInfo(actionFile)
|
fi := u.GetFileInfo(actionFile)
|
||||||
if fi == nil {
|
if fi == nil {
|
||||||
fullActionFile, _ := filepath.Abs(actionFile)
|
fullActionFile, _ := filepath.Abs(actionFile)
|
||||||
panic(vm.NewGoError(errors.New("actionFile must be a js file path: " + fullActionFile)))
|
// panic(vm.NewGoError(errors.New("actionFile must be a js file path: " + fullActionFile)))
|
||||||
|
vm.SetData("_lastError", errors.New("actionFile must be a js file path: "+fullActionFile))
|
||||||
|
gojs.GetLogger(vm).Error("actionFile must be a js file path: " + fullActionFile)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
actionCode := u.ReadFileN(actionFile)
|
actionCode := u.ReadFileN(actionFile)
|
||||||
if !strings.Contains(actionCode, "function main(") { // || !strings.Contains(actionCode, ".register(")
|
if !strings.Contains(actionCode, "function main(") { // || !strings.Contains(actionCode, ".register(")
|
||||||
panic(vm.NewGoError(errors.New("actionFile must be a js file with main function")))
|
// panic(vm.NewGoError(errors.New("actionFile must be a js file with main function")))
|
||||||
|
vm.SetData("_lastError", errors.New("actionFile must be a js file with main function"))
|
||||||
|
gojs.GetLogger(vm).Error("actionFile must be a js file with main function")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
poolsLock.Lock()
|
poolsLock.Lock()
|
||||||
poolExists[actionFile] = true
|
poolExists[actionFile] = true
|
||||||
@ -654,49 +675,80 @@ func init() {
|
|||||||
// })
|
// })
|
||||||
// return nil
|
// return nil
|
||||||
// },
|
// },
|
||||||
"setTplFunc": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
// "setTplFunc": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
|
// args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
||||||
|
// fnObj := args.Obj(0)
|
||||||
|
// if fnObj != nil {
|
||||||
|
// fnList := map[string]any{}
|
||||||
|
// for _, k := range fnObj.O.Keys() {
|
||||||
|
// if jsFunc := fnObj.Func(k); jsFunc != nil {
|
||||||
|
// fn := func(args ...any) any {
|
||||||
|
// jsArgs := make([]goja.Value, len(args))
|
||||||
|
// for i := 0; i < len(args); i++ {
|
||||||
|
// jsArgs[i] = vm.ToValue(args[i])
|
||||||
|
// }
|
||||||
|
// // vm.CallbackLocker.Lock()
|
||||||
|
// r, err := jsFunc(argsIn.This, jsArgs...)
|
||||||
|
// // vm.CallbackLocker.Unlock()
|
||||||
|
// if err == nil {
|
||||||
|
// return r.Export()
|
||||||
|
// } else {
|
||||||
|
// panic(vm.NewGoError(err))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// fnList[k] = fn
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if len(fnList) > 0 {
|
||||||
|
// tplLock.Lock()
|
||||||
|
// for k, v := range fnList {
|
||||||
|
// tplFunc[k] = v
|
||||||
|
// }
|
||||||
|
// tplLock.Unlock()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// },
|
||||||
|
"setTplReplaces": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
||||||
fnObj := args.Obj(0)
|
replaces := args.Map(0)
|
||||||
if fnObj != nil {
|
tplLock.Lock()
|
||||||
fnList := map[string]any{}
|
for k, v := range replaces {
|
||||||
for _, k := range fnObj.O.Keys() {
|
tplReplaces[k] = u.String(v)
|
||||||
if jsFunc := fnObj.Func(k); jsFunc != nil {
|
|
||||||
fn := func(args ...any) any {
|
|
||||||
jsArgs := make([]goja.Value, len(args))
|
|
||||||
for i := 0; i < len(args); i++ {
|
|
||||||
jsArgs[i] = vm.ToValue(args[i])
|
|
||||||
}
|
|
||||||
if r, err := jsFunc(argsIn.This, jsArgs...); err == nil {
|
|
||||||
return r.Export()
|
|
||||||
} else {
|
|
||||||
panic(vm.NewGoError(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fnList[k] = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(fnList) > 0 {
|
|
||||||
tplFuncLock.Lock()
|
|
||||||
for k, v := range fnList {
|
|
||||||
tplFunc[k] = v
|
|
||||||
}
|
|
||||||
tplFuncLock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tplLock.Unlock()
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
"tpl": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"tpl": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
||||||
filename := args.Path(0)
|
filename := args.Path(0)
|
||||||
|
if !tplIsSafe(filename) {
|
||||||
|
// panic(vm.NewGoError(errors.New("tpl file " + filename + " not in safe paths")))
|
||||||
|
vm.SetData("_lastError", errors.New("tpl file "+filename+" not in safe paths"))
|
||||||
|
gojs.GetLogger(vm).Error("tpl file " + filename + " not in safe paths")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
basepath := filepath.Dir(filename)
|
||||||
info := u.GetFileInfo(filename)
|
info := u.GetFileInfo(filename)
|
||||||
if info == nil {
|
if info == nil {
|
||||||
panic(vm.NewGoError(errors.New("tpl file " + filename + " not exists")))
|
// panic(vm.NewGoError(errors.New("tpl file " + filename + " not exists")))
|
||||||
|
vm.SetData("_lastError", errors.New("tpl file "+filename+" not exists"))
|
||||||
|
gojs.GetLogger(vm).Error("tpl file " + filename + " not exists")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data := args.Any(1)
|
data := args.Any(1)
|
||||||
tplCacheLock.RLock()
|
// tplLock.RLock()
|
||||||
t := tplCache[filename]
|
// t := tplCache[filename]
|
||||||
tplCacheLock.RUnlock()
|
var t *TplCache
|
||||||
|
if t1 := vm.GetData("TPL_" + filename); t1 != nil {
|
||||||
|
if t2, ok := t1.(*TplCache); ok {
|
||||||
|
t = t2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// t := vm.GetData("TPL_" + filename).(*TplCache)
|
||||||
|
// tplLock.RUnlock()
|
||||||
if t != nil {
|
if t != nil {
|
||||||
for f, tm := range t.FileModTime {
|
for f, tm := range t.FileModTime {
|
||||||
info := u.GetFileInfo(f)
|
info := u.GetFileInfo(f)
|
||||||
@ -707,44 +759,110 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t == nil {
|
if t == nil {
|
||||||
tpl := template.New("main")
|
tpl := template.New(filename)
|
||||||
if len(tplFunc) > 0 {
|
fnList := map[string]any{}
|
||||||
tpl = tpl.Funcs(tplFunc)
|
if fnObj := args.Obj(2); fnObj != nil {
|
||||||
|
for _, k := range fnObj.O.Keys() {
|
||||||
|
if jsFunc := fnObj.Func(k); jsFunc != nil {
|
||||||
|
fn := func(args ...any) any {
|
||||||
|
jsArgs := make([]goja.Value, len(args))
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
jsArgs[i] = vm.ToValue(args[i])
|
||||||
|
}
|
||||||
|
r, err := jsFunc(argsIn.This, jsArgs...)
|
||||||
|
if err == nil {
|
||||||
|
return r.Export()
|
||||||
|
} else {
|
||||||
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fnList[k] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(fnList) > 0 {
|
||||||
|
tpl = tpl.Funcs(fnList)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileModTime := map[string]int64{
|
fileModTime := map[string]int64{
|
||||||
filename: info.ModTime.UnixMilli(),
|
filename: info.ModTime.UnixMilli(),
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
for _, m := range tplIncludeMatcher.FindAllStringSubmatch(u.ReadFileN(filename), -1) {
|
code := tplReplace(u.ReadFileN(filename))
|
||||||
includeFilename := m[1]
|
for _, m := range tplIncludeMatcher.FindAllStringSubmatch(code, -1) {
|
||||||
info2 := u.GetFileInfo(includeFilename)
|
a := strings.SplitN(m[1], ":", 2)
|
||||||
if info2 == nil {
|
includeFilename := a[0]
|
||||||
includeFilename = filepath.Join(filepath.Dir(filename), m[1])
|
includeFilepath := filepath.Join(basepath, includeFilename)
|
||||||
info2 = u.GetFileInfo(includeFilename)
|
if !tplIsSafe(includeFilepath) {
|
||||||
|
// panic(vm.NewGoError(errors.New("tpl file " + includeFilepath + " not in safe paths")))
|
||||||
|
vm.SetData("_lastError", errors.New("tpl file "+includeFilepath+" not in safe paths"))
|
||||||
|
gojs.GetLogger(vm).Error("tpl file " + includeFilepath + " not in safe paths")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if info2 != nil {
|
|
||||||
tpl, err = tpl.Parse(`{{ define "` + m[1] + `" }}` + u.ReadFileN(includeFilename) + `{{ end }}`)
|
// 每个被包含的文件只解析一次(统一修正)
|
||||||
if err != nil {
|
if fileModTime[includeFilepath] == 0 {
|
||||||
panic(vm.NewGoError(err))
|
info2 := u.GetFileInfo(includeFilepath)
|
||||||
|
if info2 != nil {
|
||||||
|
includeCode := tplReplace(u.ReadFileN(includeFilepath))
|
||||||
|
foundBlock := false
|
||||||
|
includeCode = tplDefineMatcher.ReplaceAllStringFunc(includeCode, func(str string) string {
|
||||||
|
if m := tplDefineMatcher.FindStringSubmatch(str); len(m) > 1 {
|
||||||
|
foundBlock = true
|
||||||
|
if m[1] == "main" {
|
||||||
|
return `{{ define "` + includeFilename + `" }}`
|
||||||
|
}
|
||||||
|
return `{{ define "` + includeFilename + ":" + m[1] + `" }}`
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
})
|
||||||
|
if !foundBlock {
|
||||||
|
includeCode = `{{ define "` + includeFilename + `" }}` + includeCode + `{{ end }}`
|
||||||
|
}
|
||||||
|
tpl, err = tpl.Parse(includeCode)
|
||||||
|
if err != nil {
|
||||||
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fileModTime[includeFilepath] = info2.ModTime.UnixMilli()
|
||||||
|
} else {
|
||||||
|
// panic(vm.NewGoError(errors.New("tpl file " + includeFilepath + " not exists")))
|
||||||
|
vm.SetData("_lastError", errors.New("tpl file "+includeFilepath+" not exists"))
|
||||||
|
gojs.GetLogger(vm).Error("tpl file " + includeFilepath + " not exists")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
fileModTime[includeFilename] = info2.ModTime.UnixMilli()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tpl, err = tpl.ParseFiles(filename)
|
|
||||||
|
tpl, err = tpl.Parse(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
t = &TplCache{
|
t = &TplCache{
|
||||||
Tpl: tpl,
|
Tpl: tpl,
|
||||||
FileModTime: fileModTime,
|
FileModTime: fileModTime,
|
||||||
}
|
}
|
||||||
|
// tplLock.Lock()
|
||||||
|
// tplCache[filename] = t
|
||||||
|
// tplLock.Unlock()
|
||||||
|
vm.SetData("TPL_"+filename, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0))
|
buf := bytes.NewBuffer(make([]byte, 0))
|
||||||
err := t.Tpl.ExecuteTemplate(buf, filepath.Base(filename), data)
|
err := t.Tpl.ExecuteTemplate(buf, filename, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return vm.ToValue(buf.String())
|
return vm.ToValue(buf.String())
|
||||||
},
|
},
|
||||||
@ -784,10 +902,53 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var regexpCache = map[string]*regexp.Regexp{}
|
||||||
|
var regexpLock = sync.RWMutex{}
|
||||||
|
|
||||||
|
func getRegexp(regexpStr string) (*regexp.Regexp, error) {
|
||||||
|
regexpLock.RLock()
|
||||||
|
rx, ok := regexpCache[regexpStr]
|
||||||
|
regexpLock.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return rx, nil
|
||||||
|
}
|
||||||
|
rx, err := regexp.Compile(regexpStr)
|
||||||
|
if err == nil {
|
||||||
|
regexpLock.Lock()
|
||||||
|
defer regexpLock.Unlock()
|
||||||
|
regexpCache[regexpStr] = rx
|
||||||
|
}
|
||||||
|
return rx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func tplReplace(code string) string {
|
||||||
|
for k, v := range tplReplaces {
|
||||||
|
if rx, err := getRegexp(k); err == nil {
|
||||||
|
code = rx.ReplaceAllString(code, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func tplIsSafe(filename string) bool {
|
||||||
|
if len(serviceConfig.TplSafePaths) > 0 {
|
||||||
|
isSafe := false
|
||||||
|
for _, safePath := range serviceConfig.TplSafePaths {
|
||||||
|
if strings.HasPrefix(filename, safePath) {
|
||||||
|
isSafe = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isSafe
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
var tplIncludeMatcher = regexp.MustCompile(`{{\s*template\s+"([^"]+)"`)
|
var tplIncludeMatcher = regexp.MustCompile(`{{\s*template\s+"([^"]+)"`)
|
||||||
|
var tplDefineMatcher = regexp.MustCompile(`{{\s*define\s+"([^"]+)"\s*}}`)
|
||||||
|
|
||||||
func verifyRegexp(regexpStr string) func(any, *goja.Runtime) bool {
|
func verifyRegexp(regexpStr string) func(any, *goja.Runtime) bool {
|
||||||
if rx, err := regexp.Compile(regexpStr); err != nil {
|
if rx, err := getRegexp(regexpStr); err != nil {
|
||||||
return func(value any, vm *goja.Runtime) bool {
|
return func(value any, vm *goja.Runtime) bool {
|
||||||
return rx.MatchString(u.String(value))
|
return rx.MatchString(u.String(value))
|
||||||
}
|
}
|
||||||
@ -907,6 +1068,15 @@ func runAction(action goja.Callable, vm *goja.Runtime, thisArg goja.Value, args
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// force set userId to vm
|
||||||
|
vmUserId := "_guest"
|
||||||
|
if session != nil {
|
||||||
|
if userId, ok := session.data[serviceConfig.UserIdKey]; ok {
|
||||||
|
vmUserId = u.String(userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm.SetData("userId", vmUserId)
|
||||||
|
|
||||||
requestParams, resp := makeRequestParams(args, headers, request, response, client, caller, session, logger)
|
requestParams, resp := makeRequestParams(args, headers, request, response, client, caller, session, logger)
|
||||||
var r any
|
var r any
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,8 @@ export default {
|
|||||||
// idL,
|
// idL,
|
||||||
// uniqueId,
|
// uniqueId,
|
||||||
// uniqueIdL,
|
// uniqueIdL,
|
||||||
setTplFunc,
|
// setTplFunc,
|
||||||
|
setTplReplaces,
|
||||||
tpl,
|
tpl,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,8 +53,9 @@ function id(size?: number): string { return '' }
|
|||||||
// function idL(space: string, size?: number): string { return '' }
|
// function idL(space: string, size?: number): string { return '' }
|
||||||
// function uniqueId(size?: number): string { return '' }
|
// function uniqueId(size?: number): string { return '' }
|
||||||
// function uniqueIdL(size?: number): string { return '' }
|
// function uniqueIdL(size?: number): string { return '' }
|
||||||
function setTplFunc(fnList: Object): void { }
|
// function setTplFunc(fnList: Object): void { }
|
||||||
function tpl(file: string, data: Object): string { return '' }
|
function setTplReplaces(replaces: Object): void { }
|
||||||
|
function tpl(file: string, data: Object, fnList?: Object): string { return '' }
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
// github.com/ssgo/s 的配置参数
|
// github.com/ssgo/s 的配置参数
|
||||||
@ -118,6 +120,7 @@ export interface Config {
|
|||||||
limiterRedis: string // 限流器使用的Redis连接,默认使用内存存储
|
limiterRedis: string // 限流器使用的Redis连接,默认使用内存存储
|
||||||
limiters: Map<string, LimiterConfig> // 限流器配置,from 为数据来源,例如:ip、user、device、header.User-Agent、in.phone 等(in表示从请求参数中获取),time为时间间隔,单位ms,times为 时间间隔内允许访问的次数
|
limiters: Map<string, LimiterConfig> // 限流器配置,from 为数据来源,例如:ip、user、device、header.User-Agent、in.phone 等(in表示从请求参数中获取),time为时间间隔,单位ms,times为 时间间隔内允许访问的次数
|
||||||
hotLoad: number // 热加载配置,单位s,默认值:0,0表示不检测热加载
|
hotLoad: number // 热加载配置,单位s,默认值:0,0表示不检测热加载
|
||||||
|
tplSafePaths: string[] // 模板文件的安全路径,默认不开启安全检查
|
||||||
|
|
||||||
// gateway 的配置参数
|
// gateway 的配置参数
|
||||||
proxy: Map<string, string> // 代理配置,key为[host][path],value为代理的目标应用或URL
|
proxy: Map<string, string> // 代理配置,key为[host][path],value为代理的目标应用或URL
|
||||||
|
|||||||
@ -45,7 +45,9 @@ func TestWS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStopWSByPool(t *testing.T) {
|
func TestStopWSByPool(t *testing.T) {
|
||||||
|
fmt.Println(u.BGreen("stop ws"))
|
||||||
_, err := rt3.RunCode("s.stop();task.stop();")
|
_, err := rt3.RunCode("s.stop();task.stop();")
|
||||||
|
fmt.Println(u.BGreen("stop ws ok"), err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("stop failed", err)
|
t.Fatal("stop failed", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,32 +3,29 @@ import co from 'apigo.cc/gojs/console'
|
|||||||
import task from 'apigo.cc/gojs/task'
|
import task from 'apigo.cc/gojs/task'
|
||||||
|
|
||||||
function onStart() {
|
function onStart() {
|
||||||
co.info('task start')
|
co.info('task start')
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
function onRun() {
|
function onRun() {
|
||||||
let keys = task.keys('wsTest_')
|
let keys = task.keys('wsTest_')
|
||||||
// let connCount = s.dataCount('wsTest')
|
// let connCount = s.dataCount('wsTest')
|
||||||
if (keys.length > 0) {
|
if (keys.length > 0) {
|
||||||
// let conns = s.dataFetch('wsTest')
|
// let conns = s.dataFetch('wsTest')
|
||||||
let conns = task.getAll('wsTest_')
|
let conns = task.getAll('wsTest_')
|
||||||
for (let id in conns) {
|
for (let id in conns) {
|
||||||
let conn = conns[id]
|
let conn = conns[id]
|
||||||
try {
|
if (!conn.write(i++)) {
|
||||||
conn.write(i++)
|
task.remove(id)
|
||||||
} catch (e) {
|
}
|
||||||
co.error(e)
|
}
|
||||||
task.remove(id)
|
}
|
||||||
}
|
co.info('task run', keys.length)
|
||||||
}
|
|
||||||
}
|
|
||||||
co.info('task run', keys.length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onStop() {
|
function onStop() {
|
||||||
// s.dataRemove('wsTest')
|
// s.dataRemove('wsTest')
|
||||||
task.removeAll('wsTest_')
|
task.removeAll('wsTest_')
|
||||||
co.info('task stop')
|
co.info('task stop')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import s from "apigo.cc/gojs/service"
|
import s from "apigo.cc/gojs/service"
|
||||||
|
|
||||||
function main(args) {
|
function main(args) {
|
||||||
s.setTplFunc({
|
return s.tpl('tpl/page.html', { title: 'Abc' }, {
|
||||||
bb: text => { return '<b>' + text + '</b>' }
|
bb: text => { return '<b>' + text + '</b>' }
|
||||||
})
|
})
|
||||||
return s.tpl('tpl/page.html', { title: 'Abc' })
|
|
||||||
}
|
}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
<header>
|
<header>
|
||||||
<h1>Welcome to {{bb .title}}</h1>
|
<h1>Welcome to {{bb .title}}</h1>
|
||||||
</header>
|
</header>
|
||||||
@ -2,15 +2,15 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>{{.title}}</title>
|
<title>{{.title}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{{template "header.html" .}}
|
{{template "header.html" .}}
|
||||||
<pre>
|
<pre>
|
||||||
hello world
|
hello world
|
||||||
</pre>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
33
ws.go
33
ws.go
@ -18,7 +18,10 @@ func MakeWSClient(client *websocket.Conn, id string) gojs.Map {
|
|||||||
"read": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"read": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
typ, data, err := readWSMessage(client)
|
typ, data, err := readWSMessage(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return vm.ToValue(false)
|
||||||
}
|
}
|
||||||
return vm.ToValue(gojs.Map{
|
return vm.ToValue(gojs.Map{
|
||||||
"type": typ,
|
"type": typ,
|
||||||
@ -37,16 +40,22 @@ func MakeWSClient(client *websocket.Conn, id string) gojs.Map {
|
|||||||
err = client.WriteMessage(websocket.TextMessage, u.JsonBytes(args.Any(0)))
|
err = client.WriteMessage(websocket.TextMessage, u.JsonBytes(args.Any(0)))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return vm.ToValue(false)
|
||||||
}
|
}
|
||||||
return nil
|
return vm.ToValue(true)
|
||||||
},
|
},
|
||||||
"ping": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"ping": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
err := client.WriteMessage(websocket.PingMessage, nil)
|
err := client.WriteMessage(websocket.PingMessage, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return vm.ToValue(false)
|
||||||
}
|
}
|
||||||
return nil
|
return vm.ToValue(true)
|
||||||
},
|
},
|
||||||
"writeMessage": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"writeMessage": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
||||||
@ -68,16 +77,22 @@ func MakeWSClient(client *websocket.Conn, id string) gojs.Map {
|
|||||||
err = client.WriteMessage(websocket.TextMessage, args.Bytes(1))
|
err = client.WriteMessage(websocket.TextMessage, args.Bytes(1))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return vm.ToValue(false)
|
||||||
}
|
}
|
||||||
return nil
|
return vm.ToValue(true)
|
||||||
},
|
},
|
||||||
"close": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
"close": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||||
err := client.Close()
|
err := client.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(vm.NewGoError(err))
|
// panic(vm.NewGoError(err))
|
||||||
|
vm.SetData("_lastError", err)
|
||||||
|
gojs.GetLogger(vm).Error(err.Error())
|
||||||
|
return vm.ToValue(false)
|
||||||
}
|
}
|
||||||
return nil
|
return vm.ToValue(true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user