many update
support pool
This commit is contained in:
parent
205c4f20dc
commit
f37b64c2df
117
args.go
117
args.go
@ -15,6 +15,13 @@ type Args struct {
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
type Obj struct {
|
||||
This goja.Value
|
||||
VM *goja.Runtime
|
||||
Logger *log.Logger
|
||||
O *goja.Object
|
||||
}
|
||||
|
||||
func GetLogger(vm *goja.Runtime) *log.Logger {
|
||||
var logger *log.Logger
|
||||
if vm.GoData["logger"] != nil {
|
||||
@ -174,9 +181,117 @@ func (args *Args) Func(index int) goja.Callable {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (args *Args) Obj(index int) *goja.Object {
|
||||
func (args *Args) Obj(index int) *Obj {
|
||||
if len(args.Arguments) > index {
|
||||
return &Obj{
|
||||
This: args.This,
|
||||
VM: args.VM,
|
||||
Logger: args.Logger,
|
||||
O: args.Arguments[index].ToObject(args.VM),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (args *Args) Object(index int) *goja.Object {
|
||||
if len(args.Arguments) > index {
|
||||
return args.Arguments[index].ToObject(args.VM)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// -------- Object
|
||||
|
||||
func (obj *Obj) Get(name string) goja.Value {
|
||||
return obj.O.Get(name)
|
||||
}
|
||||
|
||||
func (obj *Obj) Int(name string) int {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return u.Int(v.Export())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (obj *Obj) Int64(name string) int64 {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return u.Int64(v.Export())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (obj *Obj) Any(name string) any {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return v.Export()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *Obj) Str(name string) string {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return u.String(v.Export())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (obj *Obj) Bytes(name string) []byte {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return u.Bytes(v.Export())
|
||||
}
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (obj *Obj) Bool(name string) bool {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return u.Bool(v.Export())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (obj *Obj) Map(name string) map[string]any {
|
||||
v := obj.O.Get(name)
|
||||
out := map[string]any{}
|
||||
if v != nil {
|
||||
u.Convert(v.Export(), &out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (obj *Obj) Path(name string) string {
|
||||
return FindPath(obj.VM, obj.Str(name))
|
||||
}
|
||||
|
||||
func (obj *Obj) Func(name string) goja.Callable {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return GetFunc(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *Obj) Object(name string) *goja.Object {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
return v.ToObject(obj.VM)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *Obj) Arr(name string) []any {
|
||||
v := obj.O.Get(name)
|
||||
if v != nil {
|
||||
arr := make([]any, 0)
|
||||
obj.VM.ForOf(v, func(v goja.Value) bool {
|
||||
arr = append(arr, v.Export())
|
||||
return true
|
||||
})
|
||||
return arr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
50
common.go
Normal file
50
common.go
Normal file
@ -0,0 +1,50 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"apigo.cc/apigo/gojs/dop251/goja"
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func MakeLogger(logger *log.Logger) Map {
|
||||
return map[string]any{
|
||||
"info": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(1)
|
||||
logger.Info(args.Str(0), args.Map2Arr(1)...)
|
||||
return nil
|
||||
},
|
||||
"warn": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(1)
|
||||
logger.Warning(args.Str(0), args.Map2Arr(1)...)
|
||||
return nil
|
||||
},
|
||||
"error": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(1)
|
||||
logger.Error(args.Str(0), args.Map2Arr(1)...)
|
||||
return nil
|
||||
},
|
||||
"debug": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(1)
|
||||
logger.Debug(args.Str(0), args.Map2Arr(1)...)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeMap(structObj any) Map {
|
||||
m := Map{}
|
||||
from := u.RealValue(reflect.ValueOf(structObj))
|
||||
if from.Kind() == reflect.Struct {
|
||||
st := u.FlatStruct(structObj)
|
||||
for k, v := range st.Values {
|
||||
k = u.GetLowerName(k)
|
||||
m[k] = v.Interface()
|
||||
}
|
||||
for k, v := range st.MethodValues {
|
||||
k = u.GetLowerName(k)
|
||||
m[k] = v.Interface()
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
@ -13,6 +13,7 @@ import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/collate"
|
||||
@ -179,6 +180,8 @@ type Now func() time.Time
|
||||
|
||||
type Runtime struct {
|
||||
GoData map[string]any
|
||||
Locker sync.Mutex
|
||||
CallbackLocker sync.Mutex
|
||||
global global
|
||||
globalObject *Object
|
||||
stringSingleton *stringObject
|
||||
|
10
go.mod
10
go.mod
@ -8,12 +8,12 @@ require (
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904
|
||||
github.com/ssgo/dao v0.1.5
|
||||
github.com/ssgo/db v1.7.9
|
||||
github.com/ssgo/httpclient v1.7.7
|
||||
github.com/ssgo/httpclient v1.7.8
|
||||
github.com/ssgo/log v1.7.7
|
||||
github.com/ssgo/tool v0.4.27
|
||||
github.com/ssgo/u v1.7.7
|
||||
golang.org/x/net v0.29.0
|
||||
golang.org/x/text v0.18.0
|
||||
github.com/ssgo/u v1.7.9
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/text v0.19.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@ -24,5 +24,5 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/ssgo/config v1.7.7 // indirect
|
||||
github.com/ssgo/standard v1.7.7 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
)
|
||||
|
372
gojs.go
372
gojs.go
@ -29,6 +29,12 @@ type Module struct {
|
||||
Example string
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
prg *goja.Program
|
||||
startFile string
|
||||
imports map[string]string
|
||||
}
|
||||
|
||||
var modules = map[string]Module{}
|
||||
var modulesLock = sync.RWMutex{}
|
||||
|
||||
@ -39,7 +45,11 @@ func Register(name string, mod Module) {
|
||||
}
|
||||
|
||||
func RunFile(file string, args ...any) (any, error) {
|
||||
return Run(u.ReadFileN(file), file, args...)
|
||||
if code, err := u.ReadFile(file); err == nil {
|
||||
return Run(code, file, args...)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func Run(code string, refFile string, args ...any) (any, error) {
|
||||
@ -52,6 +62,39 @@ func Run(code string, refFile string, args ...any) (any, error) {
|
||||
return r, err
|
||||
}
|
||||
|
||||
func RunProgram(plg *Program, args ...any) (any, error) {
|
||||
rt := New()
|
||||
var r any
|
||||
err := rt.StartFromProgram(plg)
|
||||
if err == nil {
|
||||
r, err = rt.RunMain(args...)
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func CompileFile(file string) (*Program, error) {
|
||||
if code, err := u.ReadFile(file); err == nil {
|
||||
return CompileMain(code, file)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func CompileMain(code string, refFile string) (*Program, error) {
|
||||
imports := makeImports(&code)
|
||||
if !checkMainMatcher.MatchString(code) {
|
||||
code = "function main(...Args){" + code + "}"
|
||||
}
|
||||
p, err := goja.Compile(refFile, code, false)
|
||||
return &Program{prg: p, imports: imports, startFile: refFile}, err
|
||||
}
|
||||
|
||||
func CompileCode(code string, refFile string) (*Program, error) {
|
||||
imports := makeImports(&code)
|
||||
p, err := goja.Compile(refFile, code, false)
|
||||
return &Program{prg: p, imports: imports, startFile: refFile}, err
|
||||
}
|
||||
|
||||
var importModMatcher = regexp.MustCompile(`(?im)^\s*import\s+(.+?)\s+from\s+['"](.+?)['"]`)
|
||||
var requireModMatcher = regexp.MustCompile(`(?im)^\s*(const|let|var)\s+(.+?)\s*=\s*require\s*\(\s*['"](.+?)['"]\s*\)`)
|
||||
|
||||
@ -60,52 +103,113 @@ var requireModMatcher = regexp.MustCompile(`(?im)^\s*(const|let|var)\s+(.+?)\s*=
|
||||
var checkMainMatcher = regexp.MustCompile(`(?im)^\s*function\s+main\s*\(`)
|
||||
|
||||
type Runtime struct {
|
||||
VM *goja.Runtime
|
||||
vm *goja.Runtime
|
||||
required map[string]bool
|
||||
file string
|
||||
srcCode string
|
||||
code string
|
||||
moduleLoader func(string) string
|
||||
started bool
|
||||
dataLock sync.RWMutex
|
||||
}
|
||||
|
||||
func (rt *Runtime) lock() {
|
||||
rt.vm.Locker.Lock()
|
||||
}
|
||||
|
||||
func (rt *Runtime) unlock() {
|
||||
rt.vm.Locker.Unlock()
|
||||
}
|
||||
|
||||
//func (rt *Runtime) Free() {
|
||||
// rt.vm.GoData = nil
|
||||
// rt.vm = nil
|
||||
//}
|
||||
|
||||
func (rt *Runtime) SetModuleLoader(fn func(filename string) string) {
|
||||
rt.moduleLoader = fn
|
||||
}
|
||||
|
||||
func (rt *Runtime) GetCallStack() []string {
|
||||
callStacks := make([]string, 0)
|
||||
for _, stack := range rt.VM.CaptureCallStack(0, nil) {
|
||||
rt.lock()
|
||||
stacks := rt.vm.CaptureCallStack(0, nil)
|
||||
rt.unlock()
|
||||
for _, stack := range stacks {
|
||||
callStacks = append(callStacks, stack.Position().String())
|
||||
}
|
||||
return callStacks
|
||||
}
|
||||
|
||||
func (rt *Runtime) requireMod(name, realModName string) error {
|
||||
if name != "" {
|
||||
func (rt *Runtime) requireSpecialMod(name string) error {
|
||||
if rt.required[name] {
|
||||
return nil
|
||||
}
|
||||
modulesLock.RLock()
|
||||
mod, ok := modules[name]
|
||||
modulesLock.RUnlock()
|
||||
if !ok {
|
||||
if name == "setTimeout" {
|
||||
rt.required["setTimeout"] = true
|
||||
fn := func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(1)
|
||||
callback := args.Func(0)
|
||||
timeout := time.Duration(args.Int64(1)) * time.Millisecond
|
||||
//locked := vm.Locker.TryLock()
|
||||
//vm.Locker.Unlock()
|
||||
//locked2 := vm.CallbackLocker.TryLock()
|
||||
//vm.CallbackLocker.Unlock()
|
||||
if callback != nil {
|
||||
go func() {
|
||||
if timeout > 0 {
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
//if !locked {
|
||||
// vm.Locker.Lock()
|
||||
//}
|
||||
//if !locked2 {
|
||||
// vm.CallbackLocker.Lock()
|
||||
//}
|
||||
if _, err := callback(args.This, args.Arguments[2:]...); err != nil {
|
||||
//panic(vm.NewGoError(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
rt.lock()
|
||||
err := rt.vm.Set("setTimeout", fn)
|
||||
rt.unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.New("module not found: " + name)
|
||||
}
|
||||
|
||||
var err error
|
||||
if mod.ObjectMaker != nil {
|
||||
err = rt.VM.Set(realModName, mod.ObjectMaker(rt.VM))
|
||||
} else {
|
||||
err = rt.VM.Set(realModName, mod.Object)
|
||||
func (rt *Runtime) requireMod(modName, realModName string) error {
|
||||
if rt.required[modName] {
|
||||
return nil
|
||||
}
|
||||
modulesLock.RLock()
|
||||
mod, ok := modules[modName]
|
||||
modulesLock.RUnlock()
|
||||
if !ok {
|
||||
// 不在注册的模块中,尝试引入特殊模块
|
||||
return rt.requireSpecialMod(modName)
|
||||
}
|
||||
|
||||
var err error
|
||||
rt.lock()
|
||||
if mod.ObjectMaker != nil {
|
||||
err = rt.vm.Set(realModName, mod.ObjectMaker(rt.vm))
|
||||
} else {
|
||||
err = rt.vm.Set(realModName, mod.Object)
|
||||
}
|
||||
rt.unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rt.required[name] = true
|
||||
rt.required[modName] = true
|
||||
return nil
|
||||
} else {
|
||||
// 使用所有模块
|
||||
}
|
||||
|
||||
func (rt *Runtime) requireAllMod() error {
|
||||
var allModules = map[string]Module{}
|
||||
modulesLock.RLock()
|
||||
for k, v := range modules {
|
||||
@ -113,22 +217,36 @@ func (rt *Runtime) requireMod(name, realModName string) error {
|
||||
}
|
||||
modulesLock.RUnlock()
|
||||
|
||||
for k, v := range allModules {
|
||||
if !rt.required[k] {
|
||||
if err := rt.VM.Set(k, v); err != nil {
|
||||
for modName, mod := range allModules {
|
||||
if !rt.required[modName] {
|
||||
var err error
|
||||
realModName := modName
|
||||
if strings.ContainsRune(modName, '/') {
|
||||
realModName = strings.ReplaceAll(realModName, "/", "_")
|
||||
}
|
||||
rt.lock()
|
||||
if mod.ObjectMaker != nil {
|
||||
err = rt.vm.Set(realModName, mod.ObjectMaker(rt.vm))
|
||||
} else {
|
||||
err = rt.vm.Set(realModName, mod.Object)
|
||||
}
|
||||
rt.unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rt.required[k] = true
|
||||
rt.required[modName] = true
|
||||
}
|
||||
}
|
||||
if err := rt.requireSpecialMod("setTimeout"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) makeImport(code string) (string, int, error) {
|
||||
var modErr error
|
||||
importCount := 0
|
||||
code = requireModMatcher.ReplaceAllStringFunc(code, func(str string) string {
|
||||
func makeImports(code *string) map[string]string {
|
||||
importModules := map[string]string{}
|
||||
*code = importModMatcher.ReplaceAllString(*code, "let $1 = require('$2')")
|
||||
*code = requireModMatcher.ReplaceAllStringFunc(*code, func(str string) string {
|
||||
if m := requireModMatcher.FindStringSubmatch(str); m != nil && len(m) > 3 {
|
||||
optName := m[1]
|
||||
varName := m[2]
|
||||
@ -143,12 +261,7 @@ func (rt *Runtime) makeImport(code string) (string, int, error) {
|
||||
if !ok {
|
||||
return str
|
||||
}
|
||||
importCount++
|
||||
if modErr == nil {
|
||||
if err := rt.requireMod(modName, realModName); err != nil {
|
||||
modErr = err
|
||||
}
|
||||
}
|
||||
importModules[modName] = realModName
|
||||
if varName != realModName {
|
||||
return fmt.Sprintf("%s %s = %s", optName, varName, realModName)
|
||||
} else {
|
||||
@ -158,43 +271,36 @@ func (rt *Runtime) makeImport(code string) (string, int, error) {
|
||||
return str
|
||||
})
|
||||
|
||||
if !rt.required["setTimeout"] && strings.Contains(code, "setTimeout") {
|
||||
rt.required["setTimeout"] = true
|
||||
err := rt.VM.Set("setTimeout", func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := MakeArgs(&argsIn, vm).Check(2)
|
||||
callback := args.Func(0)
|
||||
timeout := time.Duration(args.Int64(1)) * time.Millisecond
|
||||
if callback != nil {
|
||||
go func() {
|
||||
if timeout > 0 {
|
||||
time.Sleep(timeout)
|
||||
if strings.Contains(*code, "setTimeout") {
|
||||
importModules["setTimeout"] = "setTimeout"
|
||||
}
|
||||
if _, err := callback(args.This, args.Arguments[2:]...); err != nil {
|
||||
//panic(vm.NewGoError(err))
|
||||
return importModules
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
func (rt *Runtime) setImports(importModules map[string]string) error {
|
||||
var modErr error
|
||||
for k, v := range importModules {
|
||||
if modErr == nil {
|
||||
if err := rt.requireMod(k, v); err != nil {
|
||||
modErr = err
|
||||
}
|
||||
}
|
||||
|
||||
return code, importCount, modErr
|
||||
}
|
||||
return modErr
|
||||
}
|
||||
|
||||
func New() *Runtime {
|
||||
vm := goja.New()
|
||||
vm.GoData = map[string]any{
|
||||
"logger": log.New(u.ShortUniqueId()),
|
||||
}
|
||||
|
||||
rt := &Runtime{
|
||||
VM: vm,
|
||||
vm: vm,
|
||||
required: map[string]bool{},
|
||||
}
|
||||
|
||||
vm.GoData = map[string]any{
|
||||
"logger": log.New(u.ShortUniqueId()),
|
||||
}
|
||||
|
||||
// 处理模块引用
|
||||
require.NewRegistryWithLoader(func(path string) ([]byte, error) {
|
||||
modFile := path
|
||||
@ -215,16 +321,22 @@ func New() *Runtime {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
modCode = importModMatcher.ReplaceAllString(modCode, "let $1 = require('$2')")
|
||||
modCode, _, _ = rt.makeImport(modCode)
|
||||
imports := makeImports(&modCode)
|
||||
if err := rt.setImports(imports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(modCode), nil
|
||||
}).Enable(rt.VM)
|
||||
}).Enable(rt.vm)
|
||||
|
||||
return rt
|
||||
}
|
||||
|
||||
func (rt *Runtime) StartFromFile(file string) error {
|
||||
return rt.StartFromCode(u.ReadFileN(file), file)
|
||||
if code, err := u.ReadFile(file); err == nil {
|
||||
return rt.StartFromCode(code, file)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||
@ -239,25 +351,29 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||
rt.file = absFile
|
||||
}
|
||||
refPath := filepath.Dir(refFile)
|
||||
rt.VM.GoData["startPath"] = refPath
|
||||
rt.SetGoData("startFile", refFile)
|
||||
rt.SetGoData("startPath", refPath)
|
||||
|
||||
if rt.srcCode == "" {
|
||||
rt.srcCode = code
|
||||
}
|
||||
rt.code = code
|
||||
|
||||
// 将 import 转换为 require
|
||||
rt.code = importModMatcher.ReplaceAllString(rt.code, "let $1 = require('$2')")
|
||||
|
||||
// 按需加载引用
|
||||
var importCount int
|
||||
//var importCount int
|
||||
var modErr error
|
||||
rt.code, importCount, modErr = rt.makeImport(rt.code)
|
||||
|
||||
// 如果没有import,默认import所有
|
||||
if modErr == nil && importCount == 0 {
|
||||
modErr = rt.requireMod("", "")
|
||||
//rt.code, importCount, modErr = rt.makeImport(rt.code)
|
||||
imports := makeImports(&rt.code)
|
||||
if len(imports) == 0 {
|
||||
modErr = rt.requireAllMod()
|
||||
} else {
|
||||
modErr = rt.setImports(imports)
|
||||
}
|
||||
|
||||
//// 如果没有import,默认import所有
|
||||
//if modErr == nil && importCount == 0 {
|
||||
// modErr = rt.requireMod("", "")
|
||||
//}
|
||||
if modErr != nil {
|
||||
return modErr
|
||||
}
|
||||
@ -266,9 +382,35 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||
|
||||
// 初始化主函数
|
||||
if !checkMainMatcher.MatchString(rt.code) {
|
||||
rt.code = "function main(...args){" + rt.code + "}"
|
||||
rt.code = "function main(...Args){" + rt.code + "}"
|
||||
}
|
||||
if _, err := rt.VM.RunScript(rt.file, rt.code); err != nil {
|
||||
rt.lock()
|
||||
_, err := rt.vm.RunScript(rt.file, rt.code)
|
||||
rt.unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
rt.started = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) StartFromProgram(plg *Program) error {
|
||||
var modErr error
|
||||
if len(plg.imports) == 0 {
|
||||
modErr = rt.requireAllMod()
|
||||
} else {
|
||||
modErr = rt.setImports(plg.imports)
|
||||
}
|
||||
if modErr != nil {
|
||||
return modErr
|
||||
}
|
||||
rt.SetGoData("startFile", plg.startFile)
|
||||
rt.SetGoData("startPath", filepath.Dir(plg.startFile))
|
||||
rt.lock()
|
||||
_, err := rt.vm.RunProgram(plg.prg)
|
||||
rt.unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
rt.started = true
|
||||
@ -291,64 +433,102 @@ func (rt *Runtime) RunMain(args ...any) (any, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := rt.VM.Set("__args", args); err != nil {
|
||||
rt.lock()
|
||||
err := rt.vm.Set("__args", args)
|
||||
rt.unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsResult, err := rt.VM.RunScript("main", "main(...__args)")
|
||||
rt.lock()
|
||||
r, err := rt.vm.RunScript("main", "main(...__args)")
|
||||
rt.unlock()
|
||||
return makeResult(r, err)
|
||||
}
|
||||
|
||||
var result any
|
||||
if err == nil {
|
||||
if jsResult != nil && !jsResult.Equals(goja.Undefined()) {
|
||||
result = jsResult.Export()
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
func (rt *Runtime) RunVM(callback func(vm *goja.Runtime) (any, error)) (any, error) {
|
||||
rt.lock()
|
||||
r, err := callback(rt.vm)
|
||||
rt.unlock()
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (rt *Runtime) SetGoData(name string, value any) {
|
||||
rt.VM.GoData[name] = value
|
||||
rt.dataLock.Lock()
|
||||
rt.vm.GoData[name] = value
|
||||
rt.dataLock.Unlock()
|
||||
}
|
||||
|
||||
func (rt *Runtime) GetGoData(name string) any {
|
||||
return rt.VM.GoData[name]
|
||||
rt.dataLock.RLock()
|
||||
defer rt.dataLock.RUnlock()
|
||||
return rt.vm.GoData[name]
|
||||
}
|
||||
|
||||
func (rt *Runtime) Set(name string, value any) error {
|
||||
return rt.VM.Set(name, value)
|
||||
rt.lock()
|
||||
defer rt.unlock()
|
||||
return rt.vm.Set(name, value)
|
||||
}
|
||||
|
||||
func (rt *Runtime) SetGlobal(global Map) error {
|
||||
var err error
|
||||
rt.lock()
|
||||
defer rt.unlock()
|
||||
for k, v := range global {
|
||||
if err = rt.VM.Set(k, v); err != nil {
|
||||
if err = rt.vm.Set(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rt *Runtime) RunFile(file string) (any, error) {
|
||||
if code, err := u.ReadFile(file); err == nil {
|
||||
imports := makeImports(&code)
|
||||
if err := rt.setImports(imports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rt.lock()
|
||||
r, err := rt.vm.RunScript(file, code)
|
||||
rt.unlock()
|
||||
return makeResult(r, err)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) RunCode(code string) (any, error) {
|
||||
//if !rt.started {
|
||||
// return nil, errors.New("runtime not started")
|
||||
//}
|
||||
imports := makeImports(&code)
|
||||
if err := rt.setImports(imports); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rt.lock()
|
||||
r, err := rt.vm.RunScript("anonymous", code)
|
||||
rt.unlock()
|
||||
return makeResult(r, err)
|
||||
}
|
||||
|
||||
code = importModMatcher.ReplaceAllString(code, "let $1 = require('$2')")
|
||||
code, _, _ = rt.makeImport(code)
|
||||
func (rt *Runtime) RunProgram(prg *Program) (any, error) {
|
||||
var r goja.Value
|
||||
err := rt.setImports(prg.imports)
|
||||
if err == nil {
|
||||
rt.lock()
|
||||
r, err = rt.vm.RunProgram(prg.prg)
|
||||
rt.unlock()
|
||||
}
|
||||
return makeResult(r, err)
|
||||
}
|
||||
|
||||
jsResult, err := rt.VM.RunScript(rt.file, code)
|
||||
func makeResult(r goja.Value, err error) (any, error) {
|
||||
var result any
|
||||
if err == nil {
|
||||
if jsResult != nil && !jsResult.Equals(goja.Undefined()) {
|
||||
result = jsResult.Export()
|
||||
if r != nil && !r.Equals(goja.Undefined()) {
|
||||
result = r.Export()
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
//func RunFile(file string, args ...any) (any, error) {
|
||||
// return Run(u.ReadFileN(file), file, args...)
|
||||
//}
|
||||
|
||||
type WatchRunner struct {
|
||||
w *watcher.Watcher
|
||||
}
|
||||
|
20
gojs_test.go
20
gojs_test.go
@ -53,14 +53,16 @@ func (obj *Object) SetPlusFunc2(argsIn goja.FunctionCall, vm *goja.Runtime) goja
|
||||
//obj.plus = conf.Action
|
||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
||||
o := args.Obj(0)
|
||||
baseNumber := o.Get("baseNumber")
|
||||
if baseNumber != nil {
|
||||
obj.baseNumber = int(baseNumber.ToInteger())
|
||||
}
|
||||
action := o.Get("action")
|
||||
if action != nil {
|
||||
obj.plus = gojs.GetFunc(action)
|
||||
}
|
||||
//baseNumber := o.Get("baseNumber")
|
||||
//if baseNumber != nil {
|
||||
// obj.baseNumber = int(baseNumber.ToInteger())
|
||||
//}
|
||||
obj.baseNumber = o.Int("baseNumber")
|
||||
//action := o.Get("action")
|
||||
//if action != nil {
|
||||
// obj.plus = gojs.GetFunc(action)
|
||||
//}
|
||||
obj.plus = o.Func("action")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -165,7 +167,7 @@ func init() {
|
||||
// return &Object{id: id}
|
||||
//},
|
||||
"test1": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
//args := gojs.MakeArgs(&argsIn, VM).Check(3)
|
||||
//Args := gojs.MakeArgs(&argsIn, vm).Check(3)
|
||||
return nil
|
||||
},
|
||||
//"test1": func(id int, id2 uint16, id3 float64) *TestUser {
|
||||
|
77
lb.go
Normal file
77
lb.go
Normal file
@ -0,0 +1,77 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type LB struct {
|
||||
args []any
|
||||
pool []*Runtime
|
||||
logger *log.Logger
|
||||
debug bool
|
||||
lock sync.RWMutex
|
||||
num int
|
||||
}
|
||||
|
||||
type LBConfig struct {
|
||||
Num uint
|
||||
Args []any
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (p *LB) Get() *Runtime {
|
||||
p.lock.RLock()
|
||||
i := u.GlobalRand1.Intn(p.num)
|
||||
rt := p.pool[i]
|
||||
p.lock.RUnlock()
|
||||
return rt
|
||||
}
|
||||
|
||||
func NewLB(plg *Program, opt LBConfig, logger *log.Logger) *LB {
|
||||
if opt.Num == 0 {
|
||||
opt.Num = uint(runtime.NumCPU())
|
||||
}
|
||||
if opt.Num > uint(runtime.NumCPU())*2 {
|
||||
opt.Num = uint(runtime.NumCPU()) * 2
|
||||
}
|
||||
p := &LB{
|
||||
pool: make([]*Runtime, opt.Num),
|
||||
args: opt.Args,
|
||||
logger: logger,
|
||||
debug: opt.Debug,
|
||||
num: int(opt.Num),
|
||||
}
|
||||
p.lock.Lock()
|
||||
for i := 0; i < int(opt.Num); i++ {
|
||||
rt := New()
|
||||
err := rt.StartFromProgram(plg)
|
||||
if err == nil {
|
||||
_, err = rt.RunMain(p.args...)
|
||||
}
|
||||
if err != nil {
|
||||
p.logger.Error(err.Error())
|
||||
}
|
||||
p.pool[i] = rt
|
||||
}
|
||||
p.lock.Unlock()
|
||||
return p
|
||||
}
|
||||
|
||||
func NewLBByFile(file string, opt LBConfig, logger *log.Logger) *LB {
|
||||
if plg, err := CompileFile(file); err == nil {
|
||||
return NewLB(plg, opt, logger)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewLBByCode(code, refFile string, opt LBConfig, logger *log.Logger) *LB {
|
||||
if plg, err := CompileCode(code, refFile); err == nil {
|
||||
return NewLB(plg, opt, logger)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
@ -6,4 +6,13 @@ toolchain go1.22.5
|
||||
|
||||
require github.com/ssgo/u v1.7.7
|
||||
|
||||
require gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
require (
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 // indirect
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2 // indirect
|
||||
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
@ -1,5 +1,19 @@
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 h1:16iT9CBDOniJwFGPI41MbUDfEk74hFaKTqudrX8kenY=
|
||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217/go.mod h1:eIb+f24U+eWQCIsj9D/ah+MD9UP+wdxuqzsdLD+mhGM=
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2 h1:Ux9RXuPQmTB4C1MKagNLme0krvq8ulewfor+ORO/QL4=
|
||||
github.com/dop251/goja v0.0.0-20240927123429-241b342198c2/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc h1:MKYt39yZJi0Z9xEeRmDX2L4ocE0ETKcHKw6MVL3R+co=
|
||||
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc/go.mod h1:VULptt4Q/fNzQUJlqY/GP3qHyU7ZH46mFkBZe0ZTokU=
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d h1:Jaz2JzpQaQXyET0AjLBXShrthbpqMkhGiEfkcQAiAUs=
|
||||
github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/ssgo/u v1.7.7 h1:d8PlbLDbDNZw2ILprLQemQ3UBCMEwix/q64j5S3c940=
|
||||
github.com/ssgo/u v1.7.7/go.mod h1:dUG/PBG5k9fSM7SOp8RZLsK0KytNxhtenpoLgjhfxpY=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
@ -91,7 +91,8 @@ func replacePackage(root string) {
|
||||
if strings.Contains(str, "github.com/dop251/") {
|
||||
str = strings.ReplaceAll(str, "github.com/dop251/", "apigo.cc/apigo/gojs/dop251/")
|
||||
if strings.HasSuffix(f.FullName, "/dop251/goja/runtime.go") {
|
||||
str = strings.ReplaceAll(str, "type Runtime struct {", "type Runtime struct {\n\tGoData map[string]any")
|
||||
str = strings.ReplaceAll(str, "\"strconv\"", "\"strconv\"\n\t\"sync\"")
|
||||
str = strings.ReplaceAll(str, "type Runtime struct {", "type Runtime struct {\n\tGoData map[string]any\n\tLocker sync.Mutex\n\tCallbackLocker sync.Mutex")
|
||||
}
|
||||
_ = u.WriteFile(f.FullName, str)
|
||||
fmt.Println(u.BGreen("文件更新"), u.Green(f.FullName))
|
||||
|
@ -225,6 +225,21 @@ func init() {
|
||||
}
|
||||
return vm.ToValue(buf.String())
|
||||
},
|
||||
"sleep": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
||||
//locked := vm.Locker.TryLock()
|
||||
//vm.Locker.Unlock()
|
||||
//locked2 := vm.CallbackLocker.TryLock()
|
||||
//vm.CallbackLocker.Unlock()
|
||||
time.Sleep(time.Duration(args.Int64(0)) * time.Millisecond)
|
||||
//if !locked {
|
||||
// vm.Locker.Lock()
|
||||
//}
|
||||
//if !locked2 {
|
||||
// vm.CallbackLocker.Lock()
|
||||
//}
|
||||
return nil
|
||||
},
|
||||
"shell": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
||||
a := make([]string, len(args.Arguments)-1)
|
||||
|
@ -26,6 +26,7 @@ export default {
|
||||
sha256,
|
||||
sha512,
|
||||
tpl,
|
||||
sleep,
|
||||
shell,
|
||||
toDatetime,
|
||||
fromDatetime,
|
||||
@ -58,6 +59,7 @@ function sha1(data:any): string {return ''}
|
||||
function sha256(data:any): string {return ''}
|
||||
function sha512(data:any): string {return ''}
|
||||
function tpl(text:string, data:any, functions?:Object): string {return ''}
|
||||
function sleep(ms:number): void {}
|
||||
function shell(cmd:string, ...args:string[]): string[] {return []}
|
||||
function toDatetime(timestamp:number): string {return ''}
|
||||
function fromDatetime(datetimeStr:string): number {return 0}
|
||||
|
209
pool.go
Normal file
209
pool.go
Normal file
@ -0,0 +1,209 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Pool struct {
|
||||
plg *Program
|
||||
args []any
|
||||
pool *list.List
|
||||
lock sync.Mutex
|
||||
cond *sync.Cond
|
||||
//waitChan chan bool
|
||||
min uint
|
||||
max uint
|
||||
idle uint
|
||||
total uint
|
||||
maxTotal uint
|
||||
free uint
|
||||
waiting uint
|
||||
maxWaiting uint
|
||||
createTimes uint
|
||||
logger *log.Logger
|
||||
debug bool
|
||||
}
|
||||
|
||||
type PoolConfig struct {
|
||||
Min, Idle, Max uint
|
||||
Args []any
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (p *Pool) Count() (total, maxTotal, maxWaiting, createTimes uint) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
return p.total, p.maxTotal, p.maxWaiting, p.createTimes
|
||||
}
|
||||
|
||||
func (p *Pool) Get() *Runtime {
|
||||
//t1 := time.Now().UnixMicro()
|
||||
p.lock.Lock()
|
||||
waiting := false
|
||||
//fmt.Println(u.BBlue("check wait"), p.total, p.max, p.free)
|
||||
if p.max != 0 && p.free == 0 && p.total > p.max {
|
||||
waiting = true
|
||||
p.waiting++
|
||||
if p.maxWaiting < p.waiting {
|
||||
p.maxWaiting = p.waiting
|
||||
}
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] waiting " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
for p.free == 0 {
|
||||
p.cond.Wait()
|
||||
}
|
||||
//p.lock.Unlock()
|
||||
//<-p.waitChan
|
||||
//p.lock.Lock()
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] wait over " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
}
|
||||
|
||||
var rt *Runtime
|
||||
item := p.pool.Front()
|
||||
if item != nil {
|
||||
p.pool.Remove(item)
|
||||
if rt1, ok := item.Value.(*Runtime); ok {
|
||||
rt = rt1
|
||||
}
|
||||
}
|
||||
if rt != nil {
|
||||
p.free--
|
||||
if waiting {
|
||||
p.waiting--
|
||||
}
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] get " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
} else {
|
||||
//fmt.Println("new", p.total, p.free)
|
||||
rt = p.new()
|
||||
p.total++
|
||||
p.createTimes++
|
||||
if p.maxTotal < p.total {
|
||||
p.maxTotal = p.total
|
||||
}
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] new " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
}
|
||||
p.lock.Unlock()
|
||||
//t2 := time.Now().UnixMicro() - t1
|
||||
//fmt.Println("get", u.BRed(t2))
|
||||
return rt
|
||||
}
|
||||
|
||||
func (p *Pool) Put(rt *Runtime) {
|
||||
p.lock.Lock()
|
||||
//t1 := time.Now().UnixMicro()
|
||||
if p.idle != 0 && p.free >= p.idle {
|
||||
p.total--
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] put out " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
p.lock.Unlock()
|
||||
|
||||
//r, err := rt.RunCode("Object.keys(globalThis)")
|
||||
//if vars, ok := r.([]any); ok {
|
||||
// for _, k := range vars {
|
||||
// _ = rt.vm.Set(u.String(k), goja.Undefined())
|
||||
// }
|
||||
// r, err = rt.RunCode("Object.keys(globalThis)")
|
||||
//}
|
||||
//rt.RunCode("for(let k of Object.keys(globalThis)) delete globalThis[k]")
|
||||
//r, err := rt.RunCode("Object.keys(globalThis)")
|
||||
//fmt.Println(r, err)
|
||||
//rt.Free()
|
||||
return
|
||||
}
|
||||
p.pool.PushBack(rt)
|
||||
p.free++
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] put " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
//t2 := time.Now().UnixMicro() - t1
|
||||
//fmt.Println("put", u.BYellow(t2))
|
||||
p.lock.Unlock()
|
||||
if p.waiting > 0 {
|
||||
p.cond.Signal()
|
||||
//p.waitChan <- true
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool) new() *Runtime {
|
||||
rt := New()
|
||||
err := rt.StartFromProgram(p.plg)
|
||||
if err == nil {
|
||||
_, err = rt.RunMain(p.args...)
|
||||
}
|
||||
if err != nil {
|
||||
p.logger.Error(err.Error())
|
||||
return nil
|
||||
}
|
||||
return rt
|
||||
}
|
||||
|
||||
func NewPool(plg *Program, opt PoolConfig, logger *log.Logger) *Pool {
|
||||
if opt.Min == 0 {
|
||||
opt.Min = 1
|
||||
}
|
||||
if opt.Max != 0 && opt.Max < opt.Min {
|
||||
opt.Max = opt.Min
|
||||
}
|
||||
if opt.Idle != 0 && opt.Idle < opt.Min {
|
||||
opt.Idle = opt.Min
|
||||
}
|
||||
if opt.Idle != 0 && opt.Idle > opt.Max {
|
||||
opt.Idle = opt.Max
|
||||
}
|
||||
p := &Pool{
|
||||
pool: list.New(),
|
||||
plg: plg,
|
||||
args: opt.Args,
|
||||
min: opt.Min,
|
||||
max: opt.Max,
|
||||
idle: opt.Idle,
|
||||
logger: logger,
|
||||
debug: opt.Debug,
|
||||
}
|
||||
p.cond = sync.NewCond(&p.lock)
|
||||
//p.waitChan = make(chan bool, opt.Max*10)
|
||||
p.lock.Lock()
|
||||
//t1 := time.Now().UnixMicro()
|
||||
for i := 0; i < int(opt.Min); i++ {
|
||||
item := p.new()
|
||||
p.pool.PushBack(item)
|
||||
p.total++
|
||||
p.free++
|
||||
p.createTimes++
|
||||
}
|
||||
//t2 := time.Now().UnixMicro() - t1
|
||||
//fmt.Println("init", u.BBlue(t2))
|
||||
p.lock.Unlock()
|
||||
if p.debug {
|
||||
p.logger.Info("[go js pool] init " + fmt.Sprintln(u.BYellow(p.total), u.BYellow(p.pool.Len()), u.BMagenta(p.free), u.Dim(p.waiting)))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func NewPoolByFile(file string, opt PoolConfig, logger *log.Logger) *Pool {
|
||||
if plg, err := CompileFile(file); err == nil {
|
||||
return NewPool(plg, opt, logger)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewPoolByCode(code, refFile string, opt PoolConfig, logger *log.Logger) *Pool {
|
||||
if plg, err := CompileCode(code, refFile); err == nil {
|
||||
return NewPool(plg, opt, logger)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user