修复并发执行JsCode时导致的goja map冲突

This commit is contained in:
Star 2025-07-10 23:17:41 +08:00
parent 08092112ee
commit e8219eb1ec
3 changed files with 62 additions and 14 deletions

View File

@ -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())
}

View File

@ -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
}

40
gojs.go
View File

@ -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)
a := strings.Split(msg, "|:|")
for i := 1; i < len(a); i++ {
stack1 := []string{}
u.UnJson(a[1], &stack1)
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有bugvm已经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()