使用 gojs/task 代替内置任务
支持 load 加载的服务热更新(需配置hotLoad) 增强唯一id获取(使用新算法,依赖Redis) session支持基于细粒度权限匹配(传入支持的功能列表匹配)
This commit is contained in:
		
							parent
							
								
									afcce4d649
								
							
						
					
					
						commit
						715de5e442
					
				
							
								
								
									
										52
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								go.mod
									
									
									
									
									
								
							@ -1,44 +1,54 @@
 | 
				
			|||||||
module apigo.cc/gojs/service
 | 
					module apigo.cc/gojs/service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.18
 | 
					go 1.23.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	apigo.cc/gojs v0.0.12
 | 
						apigo.cc/gojs v0.0.23
 | 
				
			||||||
	apigo.cc/gojs/console v0.0.2
 | 
						apigo.cc/gojs/console v0.0.2
 | 
				
			||||||
	apigo.cc/gojs/http v0.0.3
 | 
						apigo.cc/gojs/file v0.0.4
 | 
				
			||||||
	apigo.cc/gojs/util v0.0.8
 | 
						apigo.cc/gojs/http v0.0.7
 | 
				
			||||||
 | 
						apigo.cc/gojs/runtime v0.0.3
 | 
				
			||||||
 | 
						apigo.cc/gojs/task v0.0.4
 | 
				
			||||||
 | 
						apigo.cc/gojs/util v0.0.13
 | 
				
			||||||
	github.com/gorilla/websocket v1.5.3
 | 
						github.com/gorilla/websocket v1.5.3
 | 
				
			||||||
	github.com/ssgo/config v1.7.9
 | 
						github.com/ssgo/config v1.7.9
 | 
				
			||||||
	github.com/ssgo/discover v1.7.9
 | 
						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.7
 | 
						github.com/ssgo/log v1.7.9
 | 
				
			||||||
	github.com/ssgo/redis v1.7.7
 | 
						github.com/ssgo/redis v1.7.8
 | 
				
			||||||
	github.com/ssgo/s v1.7.22
 | 
						github.com/ssgo/s v1.7.24
 | 
				
			||||||
	github.com/ssgo/standard v1.7.7
 | 
						github.com/ssgo/standard v1.7.7
 | 
				
			||||||
	github.com/ssgo/u v1.7.13
 | 
						github.com/ssgo/u v1.7.21
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/ZZMarquis/gm v1.3.2 // indirect
 | 
						github.com/ZZMarquis/gm v1.3.2 // indirect
 | 
				
			||||||
	github.com/dlclark/regexp2 v1.11.4 // indirect
 | 
						github.com/dlclark/regexp2 v1.11.5 // indirect
 | 
				
			||||||
	github.com/emmansun/gmsm v0.29.6 // indirect
 | 
						github.com/emmansun/gmsm v0.30.1 // indirect
 | 
				
			||||||
	github.com/fsnotify/fsnotify v1.8.0 // indirect
 | 
						github.com/fsnotify/fsnotify v1.9.0 // indirect
 | 
				
			||||||
	github.com/go-ole/go-ole v1.3.0 // indirect
 | 
						github.com/go-ole/go-ole v1.3.0 // indirect
 | 
				
			||||||
 | 
						github.com/go-rod/rod v0.116.2 // indirect
 | 
				
			||||||
	github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
 | 
						github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
 | 
				
			||||||
	github.com/gomodule/redigo v1.9.2 // indirect
 | 
						github.com/gomodule/redigo v1.9.2 // indirect
 | 
				
			||||||
	github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
 | 
						github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 // indirect
 | 
				
			||||||
	github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
 | 
						github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
 | 
				
			||||||
	github.com/obscuren/ecies v0.0.0-20150213224233-7c0f4a9b18d9 // indirect
 | 
						github.com/obscuren/ecies v0.0.0-20150213224233-7c0f4a9b18d9 // indirect
 | 
				
			||||||
	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 | 
						github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 | 
				
			||||||
 | 
						github.com/robfig/cron/v3 v3.0.1 // indirect
 | 
				
			||||||
	github.com/shirou/gopsutil/v3 v3.24.5 // indirect
 | 
						github.com/shirou/gopsutil/v3 v3.24.5 // indirect
 | 
				
			||||||
	github.com/shoenig/go-m1cpu v0.1.6 // indirect
 | 
						github.com/shoenig/go-m1cpu v0.1.6 // indirect
 | 
				
			||||||
	github.com/ssgo/tool v0.4.28 // indirect
 | 
						github.com/ssgo/tool v0.4.29 // indirect
 | 
				
			||||||
	github.com/tklauser/go-sysconf v0.3.14 // indirect
 | 
						github.com/tklauser/go-sysconf v0.3.15 // indirect
 | 
				
			||||||
	github.com/tklauser/numcpus v0.9.0 // indirect
 | 
						github.com/tklauser/numcpus v0.10.0 // indirect
 | 
				
			||||||
 | 
						github.com/ysmood/fetchup v0.2.3 // indirect
 | 
				
			||||||
 | 
						github.com/ysmood/goob v0.4.0 // indirect
 | 
				
			||||||
 | 
						github.com/ysmood/got v0.40.0 // indirect
 | 
				
			||||||
 | 
						github.com/ysmood/gson v0.7.3 // indirect
 | 
				
			||||||
 | 
						github.com/ysmood/leakless v0.9.0 // indirect
 | 
				
			||||||
	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 | 
						github.com/yusufpapurcu/wmi v1.2.4 // indirect
 | 
				
			||||||
	golang.org/x/crypto v0.31.0 // indirect
 | 
						golang.org/x/crypto v0.40.0 // indirect
 | 
				
			||||||
	golang.org/x/net v0.32.0 // indirect
 | 
						golang.org/x/net v0.42.0 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.28.0 // indirect
 | 
						golang.org/x/sys v0.34.0 // indirect
 | 
				
			||||||
	golang.org/x/text v0.21.0 // indirect
 | 
						golang.org/x/text v0.27.0 // indirect
 | 
				
			||||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
						gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										316
									
								
								service.go
									
									
									
									
									
								
							
							
						
						
									
										316
									
								
								service.go
									
									
									
									
									
								
							@ -37,6 +37,8 @@ var serviceMD string
 | 
				
			|||||||
var server *s.AsyncServer
 | 
					var server *s.AsyncServer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var pools = map[string]*gojs.Pool{}
 | 
					var pools = map[string]*gojs.Pool{}
 | 
				
			||||||
 | 
					var poolsMTime = map[string]int64{}
 | 
				
			||||||
 | 
					var poolsConfig = map[string]gojs.PoolConfig{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var poolExists = map[string]bool{}
 | 
					var poolExists = map[string]bool{}
 | 
				
			||||||
var poolActionRegistered = map[string]bool{}
 | 
					var poolActionRegistered = map[string]bool{}
 | 
				
			||||||
@ -71,6 +73,7 @@ type Config struct {
 | 
				
			|||||||
	LimitedMessage     string
 | 
						LimitedMessage     string
 | 
				
			||||||
	Limiters           map[string]*LimiterConfig
 | 
						Limiters           map[string]*LimiterConfig
 | 
				
			||||||
	LimiterRedis       string
 | 
						LimiterRedis       string
 | 
				
			||||||
 | 
						HotLoad            int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Proxy   map[string]string
 | 
						Proxy   map[string]string
 | 
				
			||||||
	Rewrite map[string]string
 | 
						Rewrite map[string]string
 | 
				
			||||||
@ -90,8 +93,8 @@ 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, "", 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, map[string]string{}, map[string]string{}, map[string]string{}}
 | 
				
			||||||
	if errs := config.LoadConfig("service", &serviceConfig); errs != nil && len(errs) > 0 {
 | 
						if errs := config.LoadConfig("service", &serviceConfig); len(errs) > 0 {
 | 
				
			||||||
		panic(vm.NewGoError(errs[0]))
 | 
							panic(vm.NewGoError(errs[0]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	config.LoadConfig("service", &discover.Config)
 | 
						config.LoadConfig("service", &discover.Config)
 | 
				
			||||||
@ -139,9 +142,23 @@ func initConfig(opt *gojs.Obj, logger *log.Logger, vm *goja.Runtime) {
 | 
				
			|||||||
			if authAccessToken && setAuthLevel < authLevel {
 | 
								if authAccessToken && setAuthLevel < authLevel {
 | 
				
			||||||
				setAuthLevel = s.GetAuthTokenLevel(request.Header.Get("Access-Token"))
 | 
									setAuthLevel = s.GetAuthTokenLevel(request.Header.Get("Access-Token"))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								authOk := false
 | 
				
			||||||
			if setAuthLevel >= authLevel {
 | 
								if setAuthLevel >= authLevel {
 | 
				
			||||||
 | 
									authOk = true // 默认通过
 | 
				
			||||||
 | 
									if options != nil && options.Ext != nil && options.Ext["funcs"] != nil {
 | 
				
			||||||
 | 
										if needFuncs, ok := options.Ext["funcs"].([]string); ok && len(needFuncs) > 0 {
 | 
				
			||||||
 | 
											// 指定了细化的权限验证要求
 | 
				
			||||||
 | 
											request.Set("funcs", needFuncs)
 | 
				
			||||||
 | 
											authOk = session.authFuncs(needFuncs)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if authOk {
 | 
				
			||||||
				return true, session
 | 
									return true, session
 | 
				
			||||||
			} else {
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			msg := serviceConfig.AuthFieldMessage
 | 
								msg := serviceConfig.AuthFieldMessage
 | 
				
			||||||
			if strings.Contains(msg, "{{") {
 | 
								if strings.Contains(msg, "{{") {
 | 
				
			||||||
				msg = strings.ReplaceAll(msg, "{{TARGET_AUTHLEVEL}}", u.String(authLevel))
 | 
									msg = strings.ReplaceAll(msg, "{{TARGET_AUTHLEVEL}}", u.String(authLevel))
 | 
				
			||||||
@ -153,7 +170,6 @@ func initConfig(opt *gojs.Obj, logger *log.Logger, vm *goja.Runtime) {
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return false, msg
 | 
									return false, msg
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		s.Init()
 | 
							s.Init()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -180,6 +196,44 @@ func initConfig(opt *gojs.Obj, logger *log.Logger, vm *goja.Runtime) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if serviceConfig.HotLoad > 0 {
 | 
				
			||||||
 | 
							s.NewTimerServer("hotload", time.Duration(serviceConfig.HotLoad)*time.Second, func(b *bool) {
 | 
				
			||||||
 | 
								tmpPoolsMTimes := map[string]int64{}
 | 
				
			||||||
 | 
								poolsLock.RLock()
 | 
				
			||||||
 | 
								for actionFile, mtime := range poolsMTime {
 | 
				
			||||||
 | 
									tmpPoolsMTimes[actionFile] = mtime
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								poolsLock.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for actionFile, mtime := range tmpPoolsMTimes {
 | 
				
			||||||
 | 
									fi := u.GetFileInfo(actionFile)
 | 
				
			||||||
 | 
									if fi == nil {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									newMtime := fi.ModTime.Unix()
 | 
				
			||||||
 | 
									if newMtime > mtime {
 | 
				
			||||||
 | 
										// 重新加载文件
 | 
				
			||||||
 | 
										actionCode := u.ReadFileN(actionFile)
 | 
				
			||||||
 | 
										if !strings.Contains(actionCode, "function main(") { // || !strings.Contains(actionCode, ".register(")
 | 
				
			||||||
 | 
											logger.Error("hotload file %s failed, must be a js file with main function", actionFile)
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										poolsLock.RLock()
 | 
				
			||||||
 | 
										oldOpt := poolsConfig[actionFile]
 | 
				
			||||||
 | 
										poolsLock.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										p := gojs.NewPoolByCode(actionCode, actionFile, oldOpt, logger)
 | 
				
			||||||
 | 
										poolsLock.Lock()
 | 
				
			||||||
 | 
										pools[actionFile] = p
 | 
				
			||||||
 | 
										poolsMTime[actionFile] = newMtime
 | 
				
			||||||
 | 
										poolsLock.Unlock()
 | 
				
			||||||
 | 
										logger.Info("hotload file %s success", actionFile, "mtime", fi.ModTime)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}, nil, nil)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@ -312,72 +366,113 @@ func init() {
 | 
				
			|||||||
			s.ResetAllSets()
 | 
								s.ResetAllSets()
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"uniqueId": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
							// "uniqueId": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm)
 | 
							// 	args := gojs.MakeArgs(&argsIn, vm)
 | 
				
			||||||
			size := args.Int(0)
 | 
							// 	size := args.Int(0)
 | 
				
			||||||
			var id string
 | 
							// 	var id string
 | 
				
			||||||
			if size >= 20 {
 | 
							// 	if size >= 20 {
 | 
				
			||||||
				id = s.UniqueId20()
 | 
							// 		id = s.UniqueId20()
 | 
				
			||||||
			} else if size >= 16 {
 | 
							// 	} else if size >= 16 {
 | 
				
			||||||
				id = s.UniqueId16()
 | 
							// 		id = s.UniqueId16()
 | 
				
			||||||
			} else if size >= 14 {
 | 
							// 	} else if size >= 14 {
 | 
				
			||||||
				id = s.UniqueId14()
 | 
							// 		id = s.UniqueId14()
 | 
				
			||||||
			} else if size >= 12 {
 | 
							// 	} else if size >= 12 {
 | 
				
			||||||
				id = s.UniqueId14()[0:12]
 | 
							// 		id = s.UniqueId14()[0:12]
 | 
				
			||||||
			} else {
 | 
							// 	} else {
 | 
				
			||||||
				id = s.UniqueId()
 | 
							// 		id = s.UniqueId()
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			return vm.ToValue(id)
 | 
							// 	return vm.ToValue(id)
 | 
				
			||||||
		},
 | 
							// },
 | 
				
			||||||
		"uniqueIdL": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
							// "uniqueIdL": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm)
 | 
							// 	args := gojs.MakeArgs(&argsIn, vm)
 | 
				
			||||||
			size := args.Int(0)
 | 
							// 	size := args.Int(0)
 | 
				
			||||||
			var id string
 | 
							// 	var id string
 | 
				
			||||||
			if size >= 20 {
 | 
							// 	if size >= 20 {
 | 
				
			||||||
				id = s.UniqueId20()
 | 
							// 		id = s.UniqueId20()
 | 
				
			||||||
			} else if size >= 16 {
 | 
							// 	} else if size >= 16 {
 | 
				
			||||||
				id = s.UniqueId16()
 | 
							// 		id = s.UniqueId16()
 | 
				
			||||||
			} else if size >= 14 {
 | 
							// 	} else if size >= 14 {
 | 
				
			||||||
				id = s.UniqueId14()
 | 
							// 		id = s.UniqueId14()
 | 
				
			||||||
			} else if size >= 12 {
 | 
							// 	} else if size >= 12 {
 | 
				
			||||||
				id = s.UniqueId14()[0:12]
 | 
							// 		id = s.UniqueId14()[0:12]
 | 
				
			||||||
			} else {
 | 
							// 	} else {
 | 
				
			||||||
				id = s.UniqueId()
 | 
							// 		id = s.UniqueId()
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			return vm.ToValue(strings.ToLower(id))
 | 
							// 	return vm.ToValue(strings.ToLower(id))
 | 
				
			||||||
		},
 | 
							// },
 | 
				
			||||||
		"id": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
							"id": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
								args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
			space := args.Str(0)
 | 
								size := args.Int(0)
 | 
				
			||||||
			size := args.Int(1)
 | 
								if size == 0 {
 | 
				
			||||||
			var id string
 | 
									size = 12
 | 
				
			||||||
			if size >= 12 {
 | 
					 | 
				
			||||||
				id = s.Id12(space)
 | 
					 | 
				
			||||||
			} else if size >= 10 {
 | 
					 | 
				
			||||||
				id = s.Id10(space)
 | 
					 | 
				
			||||||
			} else if size >= 8 {
 | 
					 | 
				
			||||||
				id = s.Id8(space)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				id = s.Id6(space)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return vm.ToValue(id)
 | 
								if size > 20 {
 | 
				
			||||||
		},
 | 
									size = 20
 | 
				
			||||||
		"idL": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					 | 
				
			||||||
			space := args.Str(0)
 | 
					 | 
				
			||||||
			size := args.Int(1)
 | 
					 | 
				
			||||||
			var id string
 | 
					 | 
				
			||||||
			if size >= 12 {
 | 
					 | 
				
			||||||
				id = s.Id12(space)
 | 
					 | 
				
			||||||
			} else if size >= 10 {
 | 
					 | 
				
			||||||
				id = s.Id10(space)
 | 
					 | 
				
			||||||
			} else if size >= 8 {
 | 
					 | 
				
			||||||
				id = s.Id8(space)
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				id = s.Id6(space)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return vm.ToValue(strings.ToLower(id))
 | 
					
 | 
				
			||||||
 | 
								rd := sessionRedis
 | 
				
			||||||
 | 
								if rd == nil {
 | 
				
			||||||
 | 
									// 使用u.Id
 | 
				
			||||||
 | 
									return vm.ToValue(u.UniqueId()[0:size])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								tm := time.Now()
 | 
				
			||||||
 | 
								// 计算从2000年开始到现在的索引值(2000年时间戳:946656000)(5位62进制最小值:14776336)(可以表示901356495个,即142.9年至2142年)
 | 
				
			||||||
 | 
								secIndex := (tm.Unix()-946656000)/5 + 14776336
 | 
				
			||||||
 | 
								secTag := int(tm.UnixMicro() % 5)
 | 
				
			||||||
 | 
								uid := u.AppendInt(nil, uint64(secIndex))
 | 
				
			||||||
 | 
								secIndexKey := fmt.Sprintf("_SecIdx_%d", secIndex)
 | 
				
			||||||
 | 
								inSecIndex := rd.INCR(secIndexKey)
 | 
				
			||||||
 | 
								if inSecIndex == 1 {
 | 
				
			||||||
 | 
									rd.EXPIRE(secIndexKey, 6)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								inSecIndexBytes := u.EncodeInt(uint64(inSecIndex))
 | 
				
			||||||
 | 
								uid = u.AppendInt(uid, uint64(secTag*12+len(inSecIndexBytes))) // 长度位,防止不同长度+随机值发生碰撞(用毫秒的%4*12位基础+位数可以随机表示12位长度,看起来有变化)
 | 
				
			||||||
 | 
								uid = append(uid, inSecIndexBytes...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 用随机数填充
 | 
				
			||||||
 | 
								uid = u.FillInt(uid, size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 交叉乱序
 | 
				
			||||||
 | 
								uid = u.ExchangeInt(uid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 散列乱序
 | 
				
			||||||
 | 
								uid = u.HashInt(uid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return vm.ToValue(string(uid))
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							// "id": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
 | 
							// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
 | 
							// 	space := args.Str(0)
 | 
				
			||||||
 | 
							// 	size := args.Int(1)
 | 
				
			||||||
 | 
							// 	var id string
 | 
				
			||||||
 | 
							// 	if size >= 12 {
 | 
				
			||||||
 | 
							// 		id = s.Id12(space)
 | 
				
			||||||
 | 
							// 	} else if size >= 10 {
 | 
				
			||||||
 | 
							// 		id = s.Id10(space)
 | 
				
			||||||
 | 
							// 	} else if size >= 8 {
 | 
				
			||||||
 | 
							// 		id = s.Id8(space)
 | 
				
			||||||
 | 
							// 	} else {
 | 
				
			||||||
 | 
							// 		id = s.Id6(space)
 | 
				
			||||||
 | 
							// 	}
 | 
				
			||||||
 | 
							// 	return vm.ToValue(id)
 | 
				
			||||||
 | 
							// },
 | 
				
			||||||
 | 
							// "idL": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
 | 
							// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
 | 
							// 	space := args.Str(0)
 | 
				
			||||||
 | 
							// 	size := args.Int(1)
 | 
				
			||||||
 | 
							// 	var id string
 | 
				
			||||||
 | 
							// 	if size >= 12 {
 | 
				
			||||||
 | 
							// 		id = s.Id12(space)
 | 
				
			||||||
 | 
							// 	} else if size >= 10 {
 | 
				
			||||||
 | 
							// 		id = s.Id10(space)
 | 
				
			||||||
 | 
							// 	} else if size >= 8 {
 | 
				
			||||||
 | 
							// 		id = s.Id8(space)
 | 
				
			||||||
 | 
							// 	} else {
 | 
				
			||||||
 | 
							// 		id = s.Id6(space)
 | 
				
			||||||
 | 
							// 	}
 | 
				
			||||||
 | 
							// 	return vm.ToValue(strings.ToLower(id))
 | 
				
			||||||
 | 
							// },
 | 
				
			||||||
		"register": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
							"register": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
								args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
				
			||||||
			o := args.Obj(0)
 | 
								o := args.Obj(0)
 | 
				
			||||||
@ -443,7 +538,7 @@ func init() {
 | 
				
			|||||||
				NoBody:   o.Bool("noBody"),
 | 
									NoBody:   o.Bool("noBody"),
 | 
				
			||||||
				NoLog200: o.Bool("noLog200"),
 | 
									NoLog200: o.Bool("noLog200"),
 | 
				
			||||||
				Host:     host,
 | 
									Host:     host,
 | 
				
			||||||
				//Ext:      nil,
 | 
									Ext:      o.Map("ext"),
 | 
				
			||||||
				Limiters: usedLimiters,
 | 
									Limiters: usedLimiters,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -497,61 +592,66 @@ func init() {
 | 
				
			|||||||
					mainArgs = mainArgs1
 | 
										mainArgs = mainArgs1
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if !u.FileExists(actionFile) {
 | 
								fi := u.GetFileInfo(actionFile)
 | 
				
			||||||
 | 
								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)))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			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 and call service.register")))
 | 
									panic(vm.NewGoError(errors.New("actionFile must be a js file with main function")))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			poolsLock.Lock()
 | 
								poolsLock.Lock()
 | 
				
			||||||
			poolExists[actionFile] = true
 | 
								poolExists[actionFile] = true
 | 
				
			||||||
			poolsLock.Unlock()
 | 
								poolsLock.Unlock()
 | 
				
			||||||
			p := gojs.NewPoolByCode(actionCode, actionFile, gojs.PoolConfig{
 | 
								poolOpt := gojs.PoolConfig{
 | 
				
			||||||
				Min:   mi,
 | 
									Min:   mi,
 | 
				
			||||||
				Max:   ma,
 | 
									Max:   ma,
 | 
				
			||||||
				Idle:  idle,
 | 
									Idle:  idle,
 | 
				
			||||||
				Debug: debug,
 | 
									Debug: debug,
 | 
				
			||||||
				Args:  mainArgs,
 | 
									Args:  mainArgs,
 | 
				
			||||||
			}, args.Logger)
 | 
								}
 | 
				
			||||||
 | 
								p := gojs.NewPoolByCode(actionCode, actionFile, poolOpt, args.Logger)
 | 
				
			||||||
			//p := gojs.NewLBByCode(actionCode, actionFile, gojs.LBConfig{
 | 
								//p := gojs.NewLBByCode(actionCode, actionFile, gojs.LBConfig{
 | 
				
			||||||
			//	Num:   num,
 | 
								//	Num:   num,
 | 
				
			||||||
			//	Debug: debug,
 | 
								//	Debug: debug,
 | 
				
			||||||
			//	Args:  mainArgs,
 | 
								//	Args:  mainArgs,
 | 
				
			||||||
			//}, args.Logger)
 | 
								//}, args.Logger)
 | 
				
			||||||
 | 
								mtime := fi.ModTime.Unix()
 | 
				
			||||||
			poolsLock.Lock()
 | 
								poolsLock.Lock()
 | 
				
			||||||
			pools[actionFile] = p
 | 
								pools[actionFile] = p
 | 
				
			||||||
 | 
								poolsMTime[actionFile] = mtime
 | 
				
			||||||
 | 
								poolsConfig[actionFile] = poolOpt
 | 
				
			||||||
			poolsLock.Unlock()
 | 
								poolsLock.Unlock()
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"task": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
							// "task": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
			args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
							// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
			taskFile := args.Path(0)
 | 
							// 	taskFile := args.Path(0)
 | 
				
			||||||
			interval := args.Int(1)
 | 
							// 	interval := args.Int(1)
 | 
				
			||||||
			if interval == 0 {
 | 
							// 	if interval == 0 {
 | 
				
			||||||
				interval = 1000
 | 
							// 		interval = 1000
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			if interval < 100 {
 | 
							// 	if interval < 100 {
 | 
				
			||||||
				interval = 100
 | 
							// 		interval = 100
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			if !u.FileExists(taskFile) {
 | 
							// 	if !u.FileExists(taskFile) {
 | 
				
			||||||
				panic(vm.NewGoError(errors.New("taskFile must be a js file path")))
 | 
							// 		panic(vm.NewGoError(errors.New("taskFile must be a js file path")))
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			rt := gojs.New()
 | 
							// 	rt := gojs.New()
 | 
				
			||||||
			_, err := rt.RunFile(taskFile)
 | 
							// 	_, err := rt.RunFile(taskFile)
 | 
				
			||||||
			if err != nil {
 | 
							// 	if err != nil {
 | 
				
			||||||
				panic(vm.NewGoError(err))
 | 
							// 		panic(vm.NewGoError(err))
 | 
				
			||||||
			}
 | 
							// 	}
 | 
				
			||||||
			s.NewTimerServer(taskFile, time.Duration(interval)*time.Millisecond, func(isRunning *bool) {
 | 
							// 	s.NewTimerServer(taskFile, time.Duration(interval)*time.Millisecond, func(isRunning *bool) {
 | 
				
			||||||
				rt.RunCode("if(onRun)onRun()")
 | 
							// 		rt.RunCode("if(onRun)onRun()")
 | 
				
			||||||
			}, func() {
 | 
							// 	}, func() {
 | 
				
			||||||
				rt.RunCode("if(onStart)onStart()")
 | 
							// 		rt.RunCode("if(onStart)onStart()")
 | 
				
			||||||
			}, func() {
 | 
							// 	}, func() {
 | 
				
			||||||
				rt.RunCode("if(onStop)onStop()")
 | 
							// 		rt.RunCode("if(onStop)onStop()")
 | 
				
			||||||
			})
 | 
							// 	})
 | 
				
			||||||
			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)
 | 
								args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
			fnObj := args.Obj(0)
 | 
								fnObj := args.Obj(0)
 | 
				
			||||||
@ -646,16 +746,16 @@ func init() {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			return vm.ToValue(buf.String())
 | 
								return vm.ToValue(buf.String())
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"dataSet":    DataSet,
 | 
							// "dataSet":    DataSet,
 | 
				
			||||||
		"dataGet":    DataGet,
 | 
							// "dataGet":    DataGet,
 | 
				
			||||||
		"dataKeys":   DataKeys,
 | 
							// "dataKeys":   DataKeys,
 | 
				
			||||||
		"dataCount":  DataCount,
 | 
							// "dataCount":  DataCount,
 | 
				
			||||||
		"dataFetch":  DataFetch,
 | 
							// "dataFetch":  DataFetch,
 | 
				
			||||||
		"dataRemove": DataRemove,
 | 
							// "dataRemove": DataRemove,
 | 
				
			||||||
		"listPop":    ListPop,
 | 
							// "listPop":    ListPop,
 | 
				
			||||||
		"listPush":   ListPush,
 | 
							// "listPush":   ListPush,
 | 
				
			||||||
		"listCount":  ListCount,
 | 
							// "listCount":  ListCount,
 | 
				
			||||||
		"listRemove": ListRemove,
 | 
							// "listRemove": ListRemove,
 | 
				
			||||||
		"newCaller": NewCaller,
 | 
							"newCaller": NewCaller,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										61
									
								
								service.ts
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								service.ts
									
									
									
									
									
								
							@ -6,22 +6,22 @@ export default {
 | 
				
			|||||||
    stop,
 | 
					    stop,
 | 
				
			||||||
    register,
 | 
					    register,
 | 
				
			||||||
    load,
 | 
					    load,
 | 
				
			||||||
    task,
 | 
					    // task,
 | 
				
			||||||
    newCaller,
 | 
					    newCaller,
 | 
				
			||||||
    dataSet,
 | 
					    // dataSet,
 | 
				
			||||||
    dataGet,
 | 
					    // dataGet,
 | 
				
			||||||
    dataKeys,
 | 
					    // dataKeys,
 | 
				
			||||||
    dataCount,
 | 
					    // dataCount,
 | 
				
			||||||
    dataFetch,
 | 
					    // dataFetch,
 | 
				
			||||||
    dataRemove,
 | 
					    // dataRemove,
 | 
				
			||||||
    listPush,
 | 
					    // listPush,
 | 
				
			||||||
    listPop,
 | 
					    // listPop,
 | 
				
			||||||
    listCount,
 | 
					    // listCount,
 | 
				
			||||||
    listRemove,
 | 
					    // listRemove,
 | 
				
			||||||
    id,
 | 
					    id,
 | 
				
			||||||
    idL,
 | 
					    // idL,
 | 
				
			||||||
    uniqueId,
 | 
					    // uniqueId,
 | 
				
			||||||
    uniqueIdL,
 | 
					    // uniqueIdL,
 | 
				
			||||||
    setTplFunc,
 | 
					    setTplFunc,
 | 
				
			||||||
    tpl,
 | 
					    tpl,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -32,25 +32,26 @@ function stop(): void { }
 | 
				
			|||||||
function register(option: RegisterOption, callback: (params: RequestParams) => void): any { return null }
 | 
					function register(option: RegisterOption, callback: (params: RequestParams) => void): any { return null }
 | 
				
			||||||
function load(serviceFile: string, poolConfig?: PoolConfig): void { }
 | 
					function load(serviceFile: string, poolConfig?: PoolConfig): void { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function task(taskFile: string, interval: number = 1000): void { }
 | 
					// function task(taskFile: string, interval: number = 1000): void { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function newCaller(): Caller { return null as any }
 | 
					function newCaller(): Caller { return null as any }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function dataSet(scope: string, key: string, value: any): void { }
 | 
					// function dataSet(scope: string, key: string, value: any): void { }
 | 
				
			||||||
function dataGet(scope: string, key: string): any { return null }
 | 
					// function dataGet(scope: string, key: string): any { return null }
 | 
				
			||||||
function dataKeys(scope: string): string[] { return [] }
 | 
					// function dataKeys(scope: string): string[] { return [] }
 | 
				
			||||||
function dataCount(scope: string): number { return 0 }
 | 
					// function dataCount(scope: string): number { return 0 }
 | 
				
			||||||
function dataFetch(scope: string): Map<string, any> { return null as any }
 | 
					// function dataFetch(scope: string): Map<string, any> { return null as any }
 | 
				
			||||||
function dataRemove(scope: string, key?: string): void { }
 | 
					// function dataRemove(scope: string, key?: string): void { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function listPush(scope: string, key: string, value: any): void { }
 | 
					// function listPush(scope: string, key: string, value: any): void { }
 | 
				
			||||||
function listPop(scope: string, key: string): any { return null }
 | 
					// function listPop(scope: string, key: string): any { return null }
 | 
				
			||||||
function listCount(scope: string): number { return 0 }
 | 
					// function listCount(scope: string): number { return 0 }
 | 
				
			||||||
function listRemove(scope: string): void { }
 | 
					// function listRemove(scope: string): void { }
 | 
				
			||||||
function id(space: string, size?: number): string { return '' }
 | 
					function id(size?: number): string { return '' }
 | 
				
			||||||
function idL(space: string, size?: number): string { return '' }
 | 
					// function id(space: string, size?: number): string { return '' }
 | 
				
			||||||
function uniqueId(size?: number): string { return '' }
 | 
					// function idL(space: string, size?: number): string { return '' }
 | 
				
			||||||
function uniqueIdL(size?: number): string { return '' }
 | 
					// function uniqueId(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 tpl(file: string, data: Object): string { return '' }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,6 +117,7 @@ interface Config {
 | 
				
			|||||||
    limitedMessage: string | Object             // 访问受限时的消息,默认为 too many requests,可以设置对象来返回JSON,可以使用模版 {{LIMITED_FROM}}、{{LIMITED_VALUE}}
 | 
					    limitedMessage: string | Object             // 访问受限时的消息,默认为 too many requests,可以设置对象来返回JSON,可以使用模版 {{LIMITED_FROM}}、{{LIMITED_VALUE}}
 | 
				
			||||||
    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表示不检测热加载
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // gateway 的配置参数
 | 
					    // gateway 的配置参数
 | 
				
			||||||
    proxy: Map<string, string>                  // 代理配置,key为[host][path],value为代理的目标应用或URL
 | 
					    proxy: Map<string, string>                  // 代理配置,key为[host][path],value为代理的目标应用或URL
 | 
				
			||||||
@ -160,6 +162,7 @@ interface RegisterOption {
 | 
				
			|||||||
    limiters: string[]
 | 
					    limiters: string[]
 | 
				
			||||||
    verifies: Object
 | 
					    verifies: Object
 | 
				
			||||||
    requires: string[]
 | 
					    requires: string[]
 | 
				
			||||||
 | 
					    ext: Object
 | 
				
			||||||
    onMessage: (params: OnMessageParams) => void
 | 
					    onMessage: (params: OnMessageParams) => void
 | 
				
			||||||
    onClose: (params: RequestParams) => void
 | 
					    onClose: (params: RequestParams) => void
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										71
									
								
								session.go
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								session.go
									
									
									
									
									
								
							@ -2,6 +2,7 @@ package service
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,12 +10,14 @@ import (
 | 
				
			|||||||
	"apigo.cc/gojs/goja"
 | 
						"apigo.cc/gojs/goja"
 | 
				
			||||||
	"github.com/ssgo/log"
 | 
						"github.com/ssgo/log"
 | 
				
			||||||
	"github.com/ssgo/redis"
 | 
						"github.com/ssgo/redis"
 | 
				
			||||||
 | 
						"github.com/ssgo/u"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Session struct {
 | 
					type Session struct {
 | 
				
			||||||
	id            string
 | 
						id            string
 | 
				
			||||||
	conn          *redis.Redis
 | 
						conn          *redis.Redis
 | 
				
			||||||
	data          map[string]any
 | 
						data          map[string]any
 | 
				
			||||||
 | 
						funcAuthCache map[string]bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var sessionRedis *redis.Redis
 | 
					var sessionRedis *redis.Redis
 | 
				
			||||||
@ -43,6 +46,7 @@ func NewSession(id string, logger *log.Logger) *Session {
 | 
				
			|||||||
		id:            id,
 | 
							id:            id,
 | 
				
			||||||
		conn:          conn,
 | 
							conn:          conn,
 | 
				
			||||||
		data:          data,
 | 
							data:          data,
 | 
				
			||||||
 | 
							funcAuthCache: map[string]bool{},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -102,6 +106,73 @@ func (session *Session) SetAuthLevel(argsIn goja.FunctionCall, vm *goja.Runtime)
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (session *Session) authFuncs(needFuncs []string) bool {
 | 
				
			||||||
 | 
						cacheKey := strings.Join(needFuncs, "; ")
 | 
				
			||||||
 | 
						if cachedResult, ok := session.funcAuthCache[cacheKey]; ok {
 | 
				
			||||||
 | 
							return cachedResult
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						normalAuthOk := 0
 | 
				
			||||||
 | 
						requiredAuthTotal := 0
 | 
				
			||||||
 | 
						requiredAuthOk := 0
 | 
				
			||||||
 | 
						isOk := false
 | 
				
			||||||
 | 
						if userFuncs, ok := session.data["funcs"].([]string); ok && len(userFuncs) > 0 {
 | 
				
			||||||
 | 
							if u.StringIn(userFuncs, "system.superAdmin.") {
 | 
				
			||||||
 | 
								isOk = true
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// 统计必须有几个权限
 | 
				
			||||||
 | 
								for _, needFunc := range needFuncs {
 | 
				
			||||||
 | 
									if needFunc[0] == '&' {
 | 
				
			||||||
 | 
										requiredAuthTotal++
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 检查是否有匹配的权限(左匹配)
 | 
				
			||||||
 | 
								for _, needFunc := range needFuncs {
 | 
				
			||||||
 | 
									isRequired := false
 | 
				
			||||||
 | 
									if needFunc[0] == '&' {
 | 
				
			||||||
 | 
										// 必须有此权限
 | 
				
			||||||
 | 
										isRequired = true
 | 
				
			||||||
 | 
										needFunc = needFunc[1:]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									for _, userFunc := range userFuncs {
 | 
				
			||||||
 | 
										if strings.HasPrefix(userFunc, needFunc) {
 | 
				
			||||||
 | 
											// 匹配成功
 | 
				
			||||||
 | 
											if isRequired {
 | 
				
			||||||
 | 
												// 必须有此权限并且匹配成功
 | 
				
			||||||
 | 
												requiredAuthOk++
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												// 普通权限匹配成功
 | 
				
			||||||
 | 
												normalAuthOk++
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											break
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if normalAuthOk > 0 && requiredAuthOk == requiredAuthTotal {
 | 
				
			||||||
 | 
										// 普通权限匹配成功,并且必须有权限也匹配成功,直接返回
 | 
				
			||||||
 | 
										isOk = true
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						session.funcAuthCache[cacheKey] = isOk
 | 
				
			||||||
 | 
						return isOk
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (session *Session) AuthFuncs(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
 | 
						args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
 | 
						var needFuncs []string
 | 
				
			||||||
 | 
						if args.Arguments[0].ExportType().Kind() == reflect.Slice {
 | 
				
			||||||
 | 
							// 第一个参数是数组
 | 
				
			||||||
 | 
							needFuncs = args.Arr(0).StrArray(0)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// 平铺的参数
 | 
				
			||||||
 | 
							needFuncs = args.StrArray(0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return vm.ToValue(session.authFuncs(needFuncs))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (session *Session) Save(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					func (session *Session) Save(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	if session.conn == nil {
 | 
						if session.conn == nil {
 | 
				
			||||||
		now := time.Now().Unix()
 | 
							now := time.Now().Unix()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										299
									
								
								task.go
									
									
									
									
									
								
							
							
						
						
									
										299
									
								
								task.go
									
									
									
									
									
								
							@ -1,162 +1,165 @@
 | 
				
			|||||||
package service
 | 
					package service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					// type Task struct {
 | 
				
			||||||
	"container/list"
 | 
					// 	spec  string
 | 
				
			||||||
	"sync"
 | 
					// 	file  string
 | 
				
			||||||
 | 
					// 	vm    *gojs.Runtime
 | 
				
			||||||
 | 
					// 	lock  sync.RWMutex
 | 
				
			||||||
 | 
					// 	mtime time.Time
 | 
				
			||||||
 | 
					// 	// policy  string
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					// var tasks []Task
 | 
				
			||||||
 | 
					// var tasksLock = sync.RWMutex{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"apigo.cc/gojs"
 | 
					// var taskData = map[string]map[string]any{}
 | 
				
			||||||
	"apigo.cc/gojs/goja"
 | 
					// var taskDataLock = sync.RWMutex{}
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
var taskData = map[string]map[string]any{}
 | 
					// var taskList = map[string]*list.List{}
 | 
				
			||||||
var taskDataLock = sync.RWMutex{}
 | 
					// var taskListLock = sync.RWMutex{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var taskList = map[string]*list.List{}
 | 
					// func DataSet(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
var taskListLock = sync.RWMutex{}
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(3)
 | 
				
			||||||
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
 | 
					// 	key := args.Str(1)
 | 
				
			||||||
 | 
					// 	value := args.Any(2)
 | 
				
			||||||
 | 
					// 	taskDataLock.Lock()
 | 
				
			||||||
 | 
					// 	defer taskDataLock.Unlock()
 | 
				
			||||||
 | 
					// 	if taskData[scope] == nil {
 | 
				
			||||||
 | 
					// 		taskData[scope] = map[string]any{}
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	taskData[scope][key] = value
 | 
				
			||||||
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataSet(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func DataGet(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(3)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	key := args.Str(1)
 | 
					// 	key := args.Str(1)
 | 
				
			||||||
	value := args.Any(2)
 | 
					// 	taskDataLock.RLock()
 | 
				
			||||||
	taskDataLock.Lock()
 | 
					// 	defer taskDataLock.RUnlock()
 | 
				
			||||||
	defer taskDataLock.Unlock()
 | 
					// 	if taskData[scope] != nil {
 | 
				
			||||||
	if taskData[scope] == nil {
 | 
					// 		return vm.ToValue(taskData[scope][key])
 | 
				
			||||||
		taskData[scope] = map[string]any{}
 | 
					// 	}
 | 
				
			||||||
	}
 | 
					// 	return nil
 | 
				
			||||||
	taskData[scope][key] = value
 | 
					// }
 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataGet(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func DataKeys(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	key := args.Str(1)
 | 
					// 	taskDataLock.RLock()
 | 
				
			||||||
	taskDataLock.RLock()
 | 
					// 	defer taskDataLock.RUnlock()
 | 
				
			||||||
	defer taskDataLock.RUnlock()
 | 
					// 	if taskData[scope] != nil {
 | 
				
			||||||
	if taskData[scope] != nil {
 | 
					// 		keys := make([]string, len(taskData[scope]))
 | 
				
			||||||
		return vm.ToValue(taskData[scope][key])
 | 
					// 		i := 0
 | 
				
			||||||
	}
 | 
					// 		for key := range taskData[scope] {
 | 
				
			||||||
	return nil
 | 
					// 			keys[i] = key
 | 
				
			||||||
}
 | 
					// 			i++
 | 
				
			||||||
 | 
					// 		}
 | 
				
			||||||
 | 
					// 		return vm.ToValue(keys)
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataKeys(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func DataCount(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	taskDataLock.RLock()
 | 
					// 	taskDataLock.RLock()
 | 
				
			||||||
	defer taskDataLock.RUnlock()
 | 
					// 	defer taskDataLock.RUnlock()
 | 
				
			||||||
	if taskData[scope] != nil {
 | 
					// 	if taskData[scope] != nil {
 | 
				
			||||||
		keys := make([]string, len(taskData[scope]))
 | 
					// 		return vm.ToValue(len(taskData[scope]))
 | 
				
			||||||
		i := 0
 | 
					// 	}
 | 
				
			||||||
		for key := range taskData[scope] {
 | 
					// 	return vm.ToValue(0)
 | 
				
			||||||
			keys[i] = key
 | 
					// }
 | 
				
			||||||
			i++
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return vm.ToValue(keys)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataCount(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func DataFetch(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	taskDataLock.RLock()
 | 
					// 	taskDataLock.RLock()
 | 
				
			||||||
	defer taskDataLock.RUnlock()
 | 
					// 	defer taskDataLock.RUnlock()
 | 
				
			||||||
	if taskData[scope] != nil {
 | 
					// 	if taskData[scope] != nil {
 | 
				
			||||||
		return vm.ToValue(len(taskData[scope]))
 | 
					// 		all := make(map[string]any)
 | 
				
			||||||
	}
 | 
					// 		for k, v := range taskData[scope] {
 | 
				
			||||||
	return vm.ToValue(0)
 | 
					// 			all[k] = v
 | 
				
			||||||
}
 | 
					// 		}
 | 
				
			||||||
 | 
					// 		return vm.ToValue(all)
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataFetch(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func DataRemove(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	taskDataLock.RLock()
 | 
					// 	key := args.Str(1)
 | 
				
			||||||
	defer taskDataLock.RUnlock()
 | 
					// 	taskDataLock.Lock()
 | 
				
			||||||
	if taskData[scope] != nil {
 | 
					// 	defer taskDataLock.Unlock()
 | 
				
			||||||
		all := make(map[string]any)
 | 
					// 	if taskData[scope] != nil {
 | 
				
			||||||
		for k, v := range taskData[scope] {
 | 
					// 		if key != "" {
 | 
				
			||||||
			all[k] = v
 | 
					// 			delete(taskData[scope], key)
 | 
				
			||||||
		}
 | 
					// 		} else {
 | 
				
			||||||
		return vm.ToValue(all)
 | 
					// 			delete(taskData, scope)
 | 
				
			||||||
	}
 | 
					// 		}
 | 
				
			||||||
	return nil
 | 
					// 	}
 | 
				
			||||||
}
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DataRemove(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func ListPush(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	key := args.Str(1)
 | 
					// 	value := args.Any(1)
 | 
				
			||||||
	taskDataLock.Lock()
 | 
					// 	fromHead := args.Bool(2)
 | 
				
			||||||
	defer taskDataLock.Unlock()
 | 
					// 	taskListLock.Lock()
 | 
				
			||||||
	if taskData[scope] != nil {
 | 
					// 	defer taskListLock.Unlock()
 | 
				
			||||||
		if key != "" {
 | 
					// 	list1 := taskList[scope]
 | 
				
			||||||
			delete(taskData[scope], key)
 | 
					// 	if list1 == nil {
 | 
				
			||||||
		} else {
 | 
					// 		list1 = list.New()
 | 
				
			||||||
			delete(taskData, scope)
 | 
					// 		taskList[scope] = list1
 | 
				
			||||||
		}
 | 
					// 	}
 | 
				
			||||||
	}
 | 
					// 	if fromHead {
 | 
				
			||||||
	return nil
 | 
					// 		list1.PushFront(value)
 | 
				
			||||||
}
 | 
					// 	} else {
 | 
				
			||||||
 | 
					// 		list1.PushBack(value)
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ListPush(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func ListPop(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(2)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	value := args.Any(1)
 | 
					// 	fromEnd := args.Bool(1)
 | 
				
			||||||
	fromHead := args.Bool(2)
 | 
					// 	taskListLock.Lock()
 | 
				
			||||||
	taskListLock.Lock()
 | 
					// 	var item *list.Element
 | 
				
			||||||
	defer taskListLock.Unlock()
 | 
					// 	defer taskListLock.Unlock()
 | 
				
			||||||
	list1 := taskList[scope]
 | 
					// 	list1 := taskList[scope]
 | 
				
			||||||
	if list1 == nil {
 | 
					// 	if list1 != nil {
 | 
				
			||||||
		list1 = list.New()
 | 
					// 		if fromEnd {
 | 
				
			||||||
		taskList[scope] = list1
 | 
					// 			item = list1.Front()
 | 
				
			||||||
	}
 | 
					// 		} else {
 | 
				
			||||||
	if fromHead {
 | 
					// 			item = list1.Back()
 | 
				
			||||||
		list1.PushFront(value)
 | 
					// 		}
 | 
				
			||||||
	} else {
 | 
					// 		if item != nil {
 | 
				
			||||||
		list1.PushBack(value)
 | 
					// 			list1.Remove(item)
 | 
				
			||||||
	}
 | 
					// 			return vm.ToValue(item.Value)
 | 
				
			||||||
	return nil
 | 
					// 		}
 | 
				
			||||||
}
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	return nil
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ListPop(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func ListCount(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	fromEnd := args.Bool(1)
 | 
					// 	taskListLock.RLock()
 | 
				
			||||||
	taskListLock.Lock()
 | 
					// 	defer taskListLock.RUnlock()
 | 
				
			||||||
	var item *list.Element
 | 
					// 	if taskList[scope] != nil {
 | 
				
			||||||
	defer taskListLock.Unlock()
 | 
					// 		return vm.ToValue(taskList[scope].Len())
 | 
				
			||||||
	list1 := taskList[scope]
 | 
					// 	}
 | 
				
			||||||
	if list1 != nil {
 | 
					// 	return vm.ToValue(0)
 | 
				
			||||||
		if fromEnd {
 | 
					// }
 | 
				
			||||||
			item = list1.Front()
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			item = list1.Back()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if item != nil {
 | 
					 | 
				
			||||||
			list1.Remove(item)
 | 
					 | 
				
			||||||
			return vm.ToValue(item.Value)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ListCount(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					// func ListRemove(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					// 	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
				
			||||||
	scope := args.Str(0)
 | 
					// 	scope := args.Str(0)
 | 
				
			||||||
	taskListLock.RLock()
 | 
					// 	taskListLock.Lock()
 | 
				
			||||||
	defer taskListLock.RUnlock()
 | 
					// 	defer taskListLock.Unlock()
 | 
				
			||||||
	if taskList[scope] != nil {
 | 
					// 	delete(taskList, scope)
 | 
				
			||||||
		return vm.ToValue(taskList[scope].Len())
 | 
					// 	return nil
 | 
				
			||||||
	}
 | 
					// }
 | 
				
			||||||
	return vm.ToValue(0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func ListRemove(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
 | 
					 | 
				
			||||||
	args := gojs.MakeArgs(&argsIn, vm).Check(1)
 | 
					 | 
				
			||||||
	scope := args.Str(0)
 | 
					 | 
				
			||||||
	taskListLock.Lock()
 | 
					 | 
				
			||||||
	defer taskListLock.Unlock()
 | 
					 | 
				
			||||||
	delete(taskList, scope)
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,12 @@
 | 
				
			|||||||
import service from "apigo.cc/gojs/service"
 | 
					import service from "apigo.cc/gojs/service"
 | 
				
			||||||
import co from "apigo.cc/gojs/console"
 | 
					import rt from "apigo.cc/gojs/runtime"
 | 
				
			||||||
import u from "apigo.cc/gojs/util"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function main() {
 | 
					function main() {
 | 
				
			||||||
    service.register({ path: '/echo2', noLog200: true }, ({ args, response }) => {
 | 
					    service.register({ path: '/echo2', noLog200: true }, ({ args, response }) => {
 | 
				
			||||||
        // setTimeout(() => {
 | 
					        // setTimeout(() => {
 | 
				
			||||||
        //     response.end(args.name)
 | 
					        //     response.end(args.name)
 | 
				
			||||||
        // }, 10)
 | 
					        // }, 10)
 | 
				
			||||||
        u.sleep(10)
 | 
					        rt.sleep(10)
 | 
				
			||||||
        return args.name
 | 
					        return args.name
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import s from "apigo.cc/gojs/service"
 | 
					import s from "apigo.cc/gojs/service"
 | 
				
			||||||
import co from "apigo.cc/gojs/console"
 | 
					import co from "apigo.cc/gojs/console"
 | 
				
			||||||
 | 
					import task from "apigo.cc/gojs/task"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function main() {
 | 
					function main() {
 | 
				
			||||||
    s.register({
 | 
					    s.register({
 | 
				
			||||||
@ -9,11 +10,13 @@ function main() {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        onClose: ({ client }) => {
 | 
					        onClose: ({ client }) => {
 | 
				
			||||||
            co.info('ws closed', client.id)
 | 
					            co.info('ws closed', client.id)
 | 
				
			||||||
            s.dataRemove('wsTest', client.id)
 | 
					            // s.dataRemove('wsTest', client.id)
 | 
				
			||||||
 | 
					            task.remove('wsTest_' + client.id)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }, ({ client }) => {
 | 
					    }, ({ client }) => {
 | 
				
			||||||
        co.info('ws connected', client.id)
 | 
					        co.info('ws connected', client.id)
 | 
				
			||||||
        s.dataSet('wsTest', client.id, client)
 | 
					        // s.dataSet('wsTest', client.id, client)
 | 
				
			||||||
 | 
					        task.set('wsTest_' + client.id, client)
 | 
				
			||||||
        client.write('Hello, World!')
 | 
					        client.write('Hello, World!')
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,12 +2,14 @@ package service_test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"apigo.cc/gojs"
 | 
						"apigo.cc/gojs"
 | 
				
			||||||
	_ "apigo.cc/gojs/console"
 | 
						_ "apigo.cc/gojs/console"
 | 
				
			||||||
	_ "apigo.cc/gojs/http"
 | 
						_ "apigo.cc/gojs/http"
 | 
				
			||||||
 | 
						_ "apigo.cc/gojs/runtime"
 | 
				
			||||||
	"apigo.cc/gojs/service"
 | 
						"apigo.cc/gojs/service"
 | 
				
			||||||
	_ "apigo.cc/gojs/service"
 | 
						_ "apigo.cc/gojs/service"
 | 
				
			||||||
	_ "apigo.cc/gojs/util"
 | 
						_ "apigo.cc/gojs/util"
 | 
				
			||||||
@ -38,6 +40,7 @@ func TestStartByPool(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	gojs.ExportForDev()
 | 
						gojs.ExportForDev()
 | 
				
			||||||
	rt2 = gojs.New()
 | 
						rt2 = gojs.New()
 | 
				
			||||||
 | 
						u.CopyFile("api/echo.js", "api/echo_tmp.js")
 | 
				
			||||||
	err := rt2.StartFromFile("start.js")
 | 
						err := rt2.StartFromFile("start.js")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal("start failed", err)
 | 
							t.Fatal("start failed", err)
 | 
				
			||||||
@ -216,7 +219,7 @@ func TestStopByPool(t *testing.T) {
 | 
				
			|||||||
		t.Fatal("stop failed", err)
 | 
							t.Fatal("stop failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gojs.WaitAll()
 | 
						gojs.WaitAll()
 | 
				
			||||||
 | 
						os.Remove("api/echo_tmp.js")
 | 
				
			||||||
	runtime.GC()
 | 
						runtime.GC()
 | 
				
			||||||
	ms3 := runtime.MemStats{}
 | 
						ms3 := runtime.MemStats{}
 | 
				
			||||||
	runtime.ReadMemStats(&ms3)
 | 
						runtime.ReadMemStats(&ms3)
 | 
				
			||||||
 | 
				
			|||||||
@ -2,12 +2,16 @@ package service_test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"apigo.cc/gojs"
 | 
						"apigo.cc/gojs"
 | 
				
			||||||
	_ "apigo.cc/gojs/console"
 | 
						_ "apigo.cc/gojs/console"
 | 
				
			||||||
 | 
						_ "apigo.cc/gojs/file"
 | 
				
			||||||
	_ "apigo.cc/gojs/http"
 | 
						_ "apigo.cc/gojs/http"
 | 
				
			||||||
 | 
						_ "apigo.cc/gojs/runtime"
 | 
				
			||||||
	_ "apigo.cc/gojs/service"
 | 
						_ "apigo.cc/gojs/service"
 | 
				
			||||||
	_ "apigo.cc/gojs/util"
 | 
						_ "apigo.cc/gojs/util"
 | 
				
			||||||
	"github.com/ssgo/httpclient"
 | 
						"github.com/ssgo/httpclient"
 | 
				
			||||||
@ -22,6 +26,7 @@ const runTimes = 100
 | 
				
			|||||||
func TestStart(t *testing.T) {
 | 
					func TestStart(t *testing.T) {
 | 
				
			||||||
	gojs.ExportForDev()
 | 
						gojs.ExportForDev()
 | 
				
			||||||
	rt = gojs.New()
 | 
						rt = gojs.New()
 | 
				
			||||||
 | 
						u.CopyFile("api/echo.js", "api/echo_tmp.js")
 | 
				
			||||||
	err := rt.StartFromFile("start.js")
 | 
						err := rt.StartFromFile("start.js")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal("start failed", err)
 | 
							t.Fatal("start failed", err)
 | 
				
			||||||
@ -55,6 +60,19 @@ func TestJsEcho(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestJsEcho2(t *testing.T) {
 | 
				
			||||||
 | 
						for i := 0; i < runTimes; i++ {
 | 
				
			||||||
 | 
							name := u.UniqueId()
 | 
				
			||||||
 | 
							r, err := rt.RunCode("test2('" + name + "')")
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal("test2 js get failed, got error", err)
 | 
				
			||||||
 | 
							} else if r != name {
 | 
				
			||||||
 | 
								t.Fatal("test2 js get failed, name not match", r, name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u.WriteFile("api/echo_tmp.js", strings.Replace(u.ReadFileN("api/echo.js"), "return args.name", "return args.name+'!!'", 1))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGoEcho(t *testing.T) {
 | 
					func TestGoEcho(t *testing.T) {
 | 
				
			||||||
	hc := httpclient.GetClientH2C(0)
 | 
						hc := httpclient.GetClientH2C(0)
 | 
				
			||||||
	for i := 0; i < runTimes; i++ {
 | 
						for i := 0; i < runTimes; i++ {
 | 
				
			||||||
@ -118,6 +136,19 @@ func TestGoAsyncEcho(t *testing.T) {
 | 
				
			|||||||
	fmt.Println(u.BGreen("last name:"), lastName, lastResult)
 | 
						fmt.Println(u.BGreen("last name:"), lastName, lastResult)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestJsEcho2WithHotLoad(t *testing.T) {
 | 
				
			||||||
 | 
						time.Sleep(time.Second)
 | 
				
			||||||
 | 
						for i := 0; i < runTimes; i++ {
 | 
				
			||||||
 | 
							name := u.UniqueId()
 | 
				
			||||||
 | 
							r, err := rt.RunCode("test2('" + name + "')")
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal("test2 js get failed, got error", err)
 | 
				
			||||||
 | 
							} else if r != name+"!!" {
 | 
				
			||||||
 | 
								t.Fatal("test2 js get failed, name not match", r, name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestStop(t *testing.T) {
 | 
					func TestStop(t *testing.T) {
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		time.Sleep(100 * time.Millisecond)
 | 
							time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
@ -125,6 +156,7 @@ func TestStop(t *testing.T) {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
	gojs.WaitAll()
 | 
						gojs.WaitAll()
 | 
				
			||||||
	time.Sleep(100 * time.Millisecond)
 | 
						time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
 | 
						os.Remove("api/echo_tmp.js")
 | 
				
			||||||
	// if err != nil {
 | 
						// if err != nil {
 | 
				
			||||||
	// 	t.Fatal("stop failed", err)
 | 
						// 	t.Fatal("stop failed", err)
 | 
				
			||||||
	// }
 | 
						// }
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,9 @@ import (
 | 
				
			|||||||
	"apigo.cc/gojs"
 | 
						"apigo.cc/gojs"
 | 
				
			||||||
	_ "apigo.cc/gojs/console"
 | 
						_ "apigo.cc/gojs/console"
 | 
				
			||||||
	_ "apigo.cc/gojs/http"
 | 
						_ "apigo.cc/gojs/http"
 | 
				
			||||||
 | 
						_ "apigo.cc/gojs/runtime"
 | 
				
			||||||
	_ "apigo.cc/gojs/service"
 | 
						_ "apigo.cc/gojs/service"
 | 
				
			||||||
 | 
						_ "apigo.cc/gojs/task"
 | 
				
			||||||
	_ "apigo.cc/gojs/util"
 | 
						_ "apigo.cc/gojs/util"
 | 
				
			||||||
	"github.com/ssgo/u"
 | 
						"github.com/ssgo/u"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,7 +45,7 @@ func TestWS(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestStopWSByPool(t *testing.T) {
 | 
					func TestStopWSByPool(t *testing.T) {
 | 
				
			||||||
	_, err := rt3.RunCode("s.stop()")
 | 
						_, err := rt3.RunCode("s.stop();task.stop();")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal("stop failed", err)
 | 
							t.Fatal("stop failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
import s from "apigo.cc/gojs/service"
 | 
					import s from "apigo.cc/gojs/service"
 | 
				
			||||||
import http from "apigo.cc/gojs/http"
 | 
					import http from "apigo.cc/gojs/http"
 | 
				
			||||||
import u from "apigo.cc/gojs/util"
 | 
					import rt from "apigo.cc/gojs/runtime"
 | 
				
			||||||
import co from "apigo.cc/gojs/console"
 | 
					import co from "apigo.cc/gojs/console"
 | 
				
			||||||
 | 
					import file from "apigo.cc/gojs/file"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let h2c = http
 | 
					let h2c = http
 | 
				
			||||||
let urlPrefix
 | 
					let urlPrefix
 | 
				
			||||||
@ -33,16 +34,17 @@ function main() {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        rewrite: {
 | 
					        rewrite: {
 | 
				
			||||||
            '/echo2.js': '/echo.js'
 | 
					            '/echo2.js': '/echo.js'
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
 | 
					        hotLoad: 1,
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    s.register({ path: '/echo', noLog200: true }, ({ args, response }) => {
 | 
					    s.register({ path: '/echo', noLog200: true }, ({ args, response }) => {
 | 
				
			||||||
        // setTimeout(() => {
 | 
					        // setTimeout(() => {
 | 
				
			||||||
        //     response.end(args.name)
 | 
					        //     response.end(args.name)
 | 
				
			||||||
        // }, 1)
 | 
					        // }, 1)
 | 
				
			||||||
        u.sleep(1)
 | 
					        rt.sleep(1)
 | 
				
			||||||
        return args.name
 | 
					        return args.name
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    s.load('api/echo.js', { min: 20, max: 1000, idle: 100 })
 | 
					    s.load('api/echo_tmp.js', { min: 20, max: 1000, idle: 100 })
 | 
				
			||||||
    s.load('api/user.js')
 | 
					    s.load('api/user.js')
 | 
				
			||||||
    let host = s.start()
 | 
					    let host = s.start()
 | 
				
			||||||
    h2c = http.newH2C({
 | 
					    h2c = http.newH2C({
 | 
				
			||||||
@ -89,7 +91,7 @@ function testUser() {
 | 
				
			|||||||
        if (r.statusCode != 429) {
 | 
					        if (r.statusCode != 429) {
 | 
				
			||||||
            return r
 | 
					            return r
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        u.sleep(100)
 | 
					        rt.sleep(100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 测试限流器过期后允许的 1 次请求
 | 
					        // 测试限流器过期后允许的 1 次请求
 | 
				
			||||||
        r = h2c.get('/userInfo').object()
 | 
					        r = h2c.get('/userInfo').object()
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,16 @@
 | 
				
			|||||||
import s from "apigo.cc/gojs/service"
 | 
					import s from "apigo.cc/gojs/service"
 | 
				
			||||||
import http from "apigo.cc/gojs/http"
 | 
					import http from "apigo.cc/gojs/http"
 | 
				
			||||||
import u from "apigo.cc/gojs/util"
 | 
					import rt from "apigo.cc/gojs/runtime"
 | 
				
			||||||
import co from "apigo.cc/gojs/console"
 | 
					import co from "apigo.cc/gojs/console"
 | 
				
			||||||
 | 
					import task from "apigo.cc/gojs/task"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let hc = http
 | 
					let hc = http
 | 
				
			||||||
let urlPrefix
 | 
					let urlPrefix
 | 
				
			||||||
function main() {
 | 
					function main() {
 | 
				
			||||||
    s.load('api/ws.js')
 | 
					    s.load('api/ws.js')
 | 
				
			||||||
    s.task('task.js', 100)
 | 
					    // s.task('task.js', 100)
 | 
				
			||||||
 | 
					    task.addTask("@every 1s", 'task.js')
 | 
				
			||||||
 | 
					    task.start()
 | 
				
			||||||
    let host = s.start()
 | 
					    let host = s.start()
 | 
				
			||||||
    hc = http.new({ baseURL: 'http://' + host })
 | 
					    hc = http.new({ baseURL: 'http://' + host })
 | 
				
			||||||
    return host
 | 
					    return host
 | 
				
			||||||
@ -31,7 +34,7 @@ function testWS() {
 | 
				
			|||||||
    co.info('test ws abc ok')
 | 
					    co.info('test ws abc ok')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ws.ping()
 | 
					    // ws.ping()
 | 
				
			||||||
    u.sleep(10)
 | 
					    rt.sleep(10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let pc = ws.pingCount()
 | 
					    let pc = ws.pingCount()
 | 
				
			||||||
    co.info('test ws ping ok', pc.pingTimes, pc.pongTimes)
 | 
					    co.info('test ws ping ok', pc.pingTimes, pc.pongTimes)
 | 
				
			||||||
@ -51,15 +54,13 @@ function testWS() {
 | 
				
			|||||||
        return r
 | 
					        return r
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    co.info('test ws json ok')
 | 
					    co.info('test ws json ok')
 | 
				
			||||||
 | 
					    rt.sleep(2000)
 | 
				
			||||||
    u.sleep(1000)
 | 
					 | 
				
			||||||
    for (let i = 0; i < 5; i++) {
 | 
					    for (let i = 0; i < 5; i++) {
 | 
				
			||||||
        let j = ws.read()
 | 
					        let j = ws.read()
 | 
				
			||||||
        if (i !== j.data) {
 | 
					        if (i !== j.data) {
 | 
				
			||||||
            return j
 | 
					            return j
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ws.close()
 | 
					    ws.close()
 | 
				
			||||||
    return true
 | 
					    return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import s from 'apigo.cc/gojs/service'
 | 
					import s from 'apigo.cc/gojs/service'
 | 
				
			||||||
import co from 'apigo.cc/gojs/console'
 | 
					import co from 'apigo.cc/gojs/console'
 | 
				
			||||||
 | 
					import task from 'apigo.cc/gojs/task'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function onStart() {
 | 
					function onStart() {
 | 
				
			||||||
    co.info('task start')
 | 
					    co.info('task start')
 | 
				
			||||||
@ -7,24 +8,27 @@ function onStart() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let i = 0
 | 
					let i = 0
 | 
				
			||||||
function onRun() {
 | 
					function onRun() {
 | 
				
			||||||
    let connCount = s.dataCount('wsTest')
 | 
					    let keys = task.keys('wsTest_')
 | 
				
			||||||
    if (connCount > 0) {
 | 
					    // let connCount = s.dataCount('wsTest')
 | 
				
			||||||
        let conns = s.dataFetch('wsTest')
 | 
					    if (keys.length > 0) {
 | 
				
			||||||
 | 
					        // let conns = s.dataFetch('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 {
 | 
					            try {
 | 
				
			||||||
                conn.write(i++)
 | 
					                conn.write(i++)
 | 
				
			||||||
            } catch (e) {
 | 
					            } catch (e) {
 | 
				
			||||||
                co.error(e)
 | 
					                co.error(e)
 | 
				
			||||||
                s.dataRemove('wsTest', id)
 | 
					                task.remove(id)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    co.info('task run', connCount)
 | 
					    co.info('task run', keys.length)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function onStop() {
 | 
					function onStop() {
 | 
				
			||||||
    s.dataRemove('wsTest')
 | 
					    // s.dataRemove('wsTest')
 | 
				
			||||||
    co.info('task stop', s.dataCount('wsTest'))
 | 
					    task.removeAll('wsTest_')
 | 
				
			||||||
 | 
					    co.info('task stop')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user