修复并发执行JsCode时导致的goja map冲突
This commit is contained in:
parent
08092112ee
commit
e8219eb1ec
15
bridge.go
15
bridge.go
@ -241,7 +241,6 @@ func go2js(in any, n int) any {
|
||||
if err, ok := outValue.Interface().(error); ok {
|
||||
panic(vm.NewGoError(err))
|
||||
} else if err, ok := outValue.Interface().(*u.Err); ok {
|
||||
// panic(vm.NewGoError(errors.New(err.Message+"|:|"+u.Json(err.Stack))))
|
||||
panic(vm.NewGoError(err))
|
||||
} else {
|
||||
panic(vm.NewGoError(errors.New(u.String(outValue.Interface()))))
|
||||
@ -253,6 +252,20 @@ func go2js(in any, n int) any {
|
||||
// 如果返回Struct,自动转换为Map(首字母小写)
|
||||
if outType.Kind() == reflect.Struct || (outType.Kind() == reflect.Ptr && outType.Elem().Kind() == reflect.Struct) {
|
||||
outs = append(outs, ToMap(outValue.Interface()))
|
||||
} else if outType.Kind() == reflect.Slice && outType.Elem().Kind() == reflect.Struct {
|
||||
// 如果返回[]Struct,自动转换为[]Map(首字母小写)
|
||||
sliceMap := make([]map[string]any, 0)
|
||||
for i := 0; i < outValue.Len(); i++ {
|
||||
sliceMap = append(sliceMap, ToMap(outValue.Index(i).Interface()))
|
||||
}
|
||||
outs = append(outs, sliceMap)
|
||||
} else if outType.Kind() == reflect.Map && outType.Elem().Kind() == reflect.Struct {
|
||||
// 如果返回map[string]Struct,自动转换为map[string]Map(首字母小写)
|
||||
mapMap := make(map[string]map[string]any)
|
||||
for _, key := range outValue.MapKeys() {
|
||||
mapMap[key.String()] = ToMap(outValue.MapIndex(key).Interface())
|
||||
}
|
||||
outs = append(outs, mapMap)
|
||||
} else {
|
||||
outs = append(outs, outValue.Interface())
|
||||
}
|
||||
|
@ -559,8 +559,11 @@ func (r *Runtime) NewGoError(err error) *Object {
|
||||
if strings.Contains(stack, "/goja/") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(stack, "/gojs") {
|
||||
stack = "**" + stack[strings.LastIndex(stack, "/gojs"):]
|
||||
if strings.Contains(stack, "/gojs@") {
|
||||
stack = "**" + stack[strings.LastIndex(stack, "/gojs@"):]
|
||||
}
|
||||
if strings.Contains(stack, "/gojs/") {
|
||||
stack = "**" + stack[strings.LastIndex(stack, "/gojs/"):]
|
||||
}
|
||||
callStacks = append(callStacks, stack)
|
||||
}
|
||||
@ -582,15 +585,19 @@ func (r *Runtime) NewGoError(err error) *Object {
|
||||
if strings.Contains(file, "/goja/") {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(file, "/gojs") {
|
||||
file = "**" + file[strings.LastIndex(file, "/gojs"):]
|
||||
if strings.Contains(file, "/gojs@") {
|
||||
file = "**" + file[strings.LastIndex(file, "/gojs@"):]
|
||||
} else if strings.Contains(file, "/gojs/") {
|
||||
file = "**" + file[strings.LastIndex(file, "/gojs/"):]
|
||||
} else if strings.Contains(file, "/ssgo") {
|
||||
file = "**" + file[strings.LastIndex(file, "/ssgo"):]
|
||||
}
|
||||
callStacks = append(callStacks, fmt.Sprintf("%s:%d", file, line))
|
||||
}
|
||||
}
|
||||
e := r.newError(r.getGoError(), err.Error()+"|:|"+u.Json(callStacks)).(*Object)
|
||||
errStr := err.Error() + "|:|" + u.Json(callStacks)
|
||||
// errStr = strings.ReplaceAll(errStr, "GoError: ", "")
|
||||
e := r.newError(r.getGoError(), errStr).(*Object)
|
||||
e.Set("value", err)
|
||||
return e
|
||||
}
|
||||
|
44
gojs.go
44
gojs.go
@ -79,27 +79,33 @@ func MakeError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var newErr *Error
|
||||
if gojsErr, ok := err.(*Error); ok {
|
||||
return gojsErr
|
||||
newErr = gojsErr
|
||||
} else if gojaErr, ok := err.(*goja.Exception); ok {
|
||||
stack := make([]string, len(gojaErr.Stack()))
|
||||
for i, v := range gojaErr.Stack() {
|
||||
stack[i] = fmt.Sprintf("%s @%s", v.Position().String(), v.FuncName())
|
||||
}
|
||||
msg, fullMsg, stack1 := parseMessageAndStack(gojaErr.Value().String(), stack)
|
||||
return &Error{Message: msg, fullMessage: fullMsg, Stack: stack1, err: err, exceprion: gojaErr}
|
||||
newErr = &Error{Message: msg, fullMessage: fullMsg, Stack: stack1, err: err, exceprion: gojaErr}
|
||||
} else {
|
||||
msg, fullMsg, stack := parseMessageAndStack(err.Error(), []string{})
|
||||
return &Error{Message: msg, fullMessage: fullMsg, Stack: stack, err: err, exceprion: nil}
|
||||
newErr = &Error{Message: msg, fullMessage: fullMsg, Stack: stack, err: err, exceprion: nil}
|
||||
}
|
||||
// newErr.Message = strings.ReplaceAll(newErr.Message, "GoError: ", "")
|
||||
newErr.fullMessage = strings.ReplaceAll(newErr.fullMessage, "GoError: ", "")
|
||||
return newErr
|
||||
}
|
||||
|
||||
func parseMessageAndStack(msg string, stack []string) (string, string, []string) {
|
||||
if strings.Contains(msg, "|:|") {
|
||||
a := strings.SplitN(msg, "|:|", 2)
|
||||
stack1 := []string{}
|
||||
u.UnJson(a[1], &stack1)
|
||||
stack = append(stack, stack1...)
|
||||
a := strings.Split(msg, "|:|")
|
||||
for i := 1; i < len(a); i++ {
|
||||
stack1 := []string{}
|
||||
u.UnJson(a[i], &stack1)
|
||||
stack = append(stack, stack1...)
|
||||
}
|
||||
fullMsg := a[0]
|
||||
if len(stack) > 0 {
|
||||
fullMsg += "\n" + strings.Join(stack, "\n")
|
||||
@ -107,7 +113,7 @@ func parseMessageAndStack(msg string, stack []string) (string, string, []string)
|
||||
if curDir, err := os.Getwd(); err == nil && curDir != "" {
|
||||
fullMsg = strings.ReplaceAll(fullMsg, curDir, ".")
|
||||
}
|
||||
fullMsg = strings.ReplaceAll(fullMsg, "SyntaxError: SyntaxError:", "SyntaxError:")
|
||||
// fullMsg = strings.ReplaceAll(fullMsg, "SyntaxError: SyntaxError:", "SyntaxError:")
|
||||
return a[0], fullMsg, stack
|
||||
}
|
||||
return msg, msg, []string{}
|
||||
@ -301,10 +307,12 @@ type Runtime struct {
|
||||
}
|
||||
|
||||
func (rt *Runtime) lock() {
|
||||
// fmt.Println(u.Cyan(">>>>Lock"), u.BCyan(u.String(rt.GetGoData("vmId"))))
|
||||
rt.vm.Locker.Lock()
|
||||
}
|
||||
|
||||
func (rt *Runtime) unlock() {
|
||||
// fmt.Println(u.Green("\u200B <<<<UnLock"), u.BGreen(u.String(rt.GetGoData("vmId"))))
|
||||
rt.vm.Locker.Unlock()
|
||||
}
|
||||
|
||||
@ -328,6 +336,8 @@ func (rt *Runtime) GetCallStack() []string {
|
||||
return callStacks
|
||||
}
|
||||
|
||||
var jsCodeLock = sync.Mutex{} // goja有bug,vm已经lock了,当还是会报错 fatal error: concurrent map read and map write @object_gomap.go:45 vm.go:2225
|
||||
|
||||
func (rt *Runtime) requireMod(modName, realModName string, inVM bool) error {
|
||||
if rt.required[modName] {
|
||||
return nil
|
||||
@ -350,7 +360,9 @@ func (rt *Runtime) requireMod(modName, realModName string, inVM bool) error {
|
||||
err = rt.vm.Set(realModName, mod.Object)
|
||||
}
|
||||
if mod.JsCode != "" {
|
||||
jsCodeLock.Lock()
|
||||
_, err = rt.SafeRunString(strings.ReplaceAll(mod.JsCode, "$MOD$.", realModName+"."))
|
||||
jsCodeLock.Unlock()
|
||||
}
|
||||
if !inVM {
|
||||
rt.unlock()
|
||||
@ -495,6 +507,9 @@ func (rt *Runtime) StartFromFile(file string) error {
|
||||
}
|
||||
}
|
||||
|
||||
var vmId = 0
|
||||
var vmIdLock = sync.Mutex{}
|
||||
|
||||
func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||
if refFile != "" {
|
||||
rt.file = refFile
|
||||
@ -507,6 +522,12 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||
rt.file = absFile
|
||||
}
|
||||
refPath := filepath.Dir(refFile)
|
||||
|
||||
vmIdLock.Lock()
|
||||
vmId++
|
||||
vmId1 := vmId
|
||||
vmIdLock.Unlock()
|
||||
rt.SetGoData("vmId", u.String(vmId1))
|
||||
rt.SetGoData("startFile", refFile)
|
||||
rt.SetGoData("startPath", refPath)
|
||||
rt.vm.Set("__startFile", refFile)
|
||||
@ -614,6 +635,13 @@ func (rt *Runtime) StartFromProgram(prg *Program) error {
|
||||
if modErr != nil {
|
||||
return modErr
|
||||
}
|
||||
vmIdLock.Lock()
|
||||
vmId++
|
||||
vmId1 := vmId
|
||||
vmIdLock.Unlock()
|
||||
rt.SetGoData("vmId", u.String(vmId1))
|
||||
|
||||
rt.SetGoData("vmId", u.String(vmId1))
|
||||
rt.SetGoData("startFile", prg.startFile)
|
||||
rt.SetGoData("startPath", filepath.Dir(prg.startFile))
|
||||
rt.lock()
|
||||
|
Loading…
x
Reference in New Issue
Block a user