修复并发执行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 {
|
if err, ok := outValue.Interface().(error); ok {
|
||||||
panic(vm.NewGoError(err))
|
panic(vm.NewGoError(err))
|
||||||
} else if err, ok := outValue.Interface().(*u.Err); ok {
|
} else if err, ok := outValue.Interface().(*u.Err); ok {
|
||||||
// panic(vm.NewGoError(errors.New(err.Message+"|:|"+u.Json(err.Stack))))
|
|
||||||
panic(vm.NewGoError(err))
|
panic(vm.NewGoError(err))
|
||||||
} else {
|
} else {
|
||||||
panic(vm.NewGoError(errors.New(u.String(outValue.Interface()))))
|
panic(vm.NewGoError(errors.New(u.String(outValue.Interface()))))
|
||||||
@ -253,6 +252,20 @@ func go2js(in any, n int) any {
|
|||||||
// 如果返回Struct,自动转换为Map(首字母小写)
|
// 如果返回Struct,自动转换为Map(首字母小写)
|
||||||
if outType.Kind() == reflect.Struct || (outType.Kind() == reflect.Ptr && outType.Elem().Kind() == reflect.Struct) {
|
if outType.Kind() == reflect.Struct || (outType.Kind() == reflect.Ptr && outType.Elem().Kind() == reflect.Struct) {
|
||||||
outs = append(outs, ToMap(outValue.Interface()))
|
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 {
|
} else {
|
||||||
outs = append(outs, outValue.Interface())
|
outs = append(outs, outValue.Interface())
|
||||||
}
|
}
|
||||||
|
@ -559,8 +559,11 @@ func (r *Runtime) NewGoError(err error) *Object {
|
|||||||
if strings.Contains(stack, "/goja/") {
|
if strings.Contains(stack, "/goja/") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(stack, "/gojs") {
|
if strings.Contains(stack, "/gojs@") {
|
||||||
stack = "**" + stack[strings.LastIndex(stack, "/gojs"):]
|
stack = "**" + stack[strings.LastIndex(stack, "/gojs@"):]
|
||||||
|
}
|
||||||
|
if strings.Contains(stack, "/gojs/") {
|
||||||
|
stack = "**" + stack[strings.LastIndex(stack, "/gojs/"):]
|
||||||
}
|
}
|
||||||
callStacks = append(callStacks, stack)
|
callStacks = append(callStacks, stack)
|
||||||
}
|
}
|
||||||
@ -582,15 +585,19 @@ func (r *Runtime) NewGoError(err error) *Object {
|
|||||||
if strings.Contains(file, "/goja/") {
|
if strings.Contains(file, "/goja/") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(file, "/gojs") {
|
if strings.Contains(file, "/gojs@") {
|
||||||
file = "**" + file[strings.LastIndex(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") {
|
} else if strings.Contains(file, "/ssgo") {
|
||||||
file = "**" + file[strings.LastIndex(file, "/ssgo"):]
|
file = "**" + file[strings.LastIndex(file, "/ssgo"):]
|
||||||
}
|
}
|
||||||
callStacks = append(callStacks, fmt.Sprintf("%s:%d", file, line))
|
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)
|
e.Set("value", err)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
44
gojs.go
44
gojs.go
@ -79,27 +79,33 @@ func MakeError(err error) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
var newErr *Error
|
||||||
if gojsErr, ok := err.(*Error); ok {
|
if gojsErr, ok := err.(*Error); ok {
|
||||||
return gojsErr
|
newErr = gojsErr
|
||||||
} else if gojaErr, ok := err.(*goja.Exception); ok {
|
} else if gojaErr, ok := err.(*goja.Exception); ok {
|
||||||
stack := make([]string, len(gojaErr.Stack()))
|
stack := make([]string, len(gojaErr.Stack()))
|
||||||
for i, v := range gojaErr.Stack() {
|
for i, v := range gojaErr.Stack() {
|
||||||
stack[i] = fmt.Sprintf("%s @%s", v.Position().String(), v.FuncName())
|
stack[i] = fmt.Sprintf("%s @%s", v.Position().String(), v.FuncName())
|
||||||
}
|
}
|
||||||
msg, fullMsg, stack1 := parseMessageAndStack(gojaErr.Value().String(), stack)
|
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 {
|
} else {
|
||||||
msg, fullMsg, stack := parseMessageAndStack(err.Error(), []string{})
|
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) {
|
func parseMessageAndStack(msg string, stack []string) (string, string, []string) {
|
||||||
if strings.Contains(msg, "|:|") {
|
if strings.Contains(msg, "|:|") {
|
||||||
a := strings.SplitN(msg, "|:|", 2)
|
a := strings.Split(msg, "|:|")
|
||||||
stack1 := []string{}
|
for i := 1; i < len(a); i++ {
|
||||||
u.UnJson(a[1], &stack1)
|
stack1 := []string{}
|
||||||
stack = append(stack, stack1...)
|
u.UnJson(a[i], &stack1)
|
||||||
|
stack = append(stack, stack1...)
|
||||||
|
}
|
||||||
fullMsg := a[0]
|
fullMsg := a[0]
|
||||||
if len(stack) > 0 {
|
if len(stack) > 0 {
|
||||||
fullMsg += "\n" + strings.Join(stack, "\n")
|
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 != "" {
|
if curDir, err := os.Getwd(); err == nil && curDir != "" {
|
||||||
fullMsg = strings.ReplaceAll(fullMsg, 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 a[0], fullMsg, stack
|
||||||
}
|
}
|
||||||
return msg, msg, []string{}
|
return msg, msg, []string{}
|
||||||
@ -301,10 +307,12 @@ type Runtime struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) lock() {
|
func (rt *Runtime) lock() {
|
||||||
|
// fmt.Println(u.Cyan(">>>>Lock"), u.BCyan(u.String(rt.GetGoData("vmId"))))
|
||||||
rt.vm.Locker.Lock()
|
rt.vm.Locker.Lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Runtime) unlock() {
|
func (rt *Runtime) unlock() {
|
||||||
|
// fmt.Println(u.Green("\u200B <<<<UnLock"), u.BGreen(u.String(rt.GetGoData("vmId"))))
|
||||||
rt.vm.Locker.Unlock()
|
rt.vm.Locker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,6 +336,8 @@ func (rt *Runtime) GetCallStack() []string {
|
|||||||
return callStacks
|
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 {
|
func (rt *Runtime) requireMod(modName, realModName string, inVM bool) error {
|
||||||
if rt.required[modName] {
|
if rt.required[modName] {
|
||||||
return nil
|
return nil
|
||||||
@ -350,7 +360,9 @@ func (rt *Runtime) requireMod(modName, realModName string, inVM bool) error {
|
|||||||
err = rt.vm.Set(realModName, mod.Object)
|
err = rt.vm.Set(realModName, mod.Object)
|
||||||
}
|
}
|
||||||
if mod.JsCode != "" {
|
if mod.JsCode != "" {
|
||||||
|
jsCodeLock.Lock()
|
||||||
_, err = rt.SafeRunString(strings.ReplaceAll(mod.JsCode, "$MOD$.", realModName+"."))
|
_, err = rt.SafeRunString(strings.ReplaceAll(mod.JsCode, "$MOD$.", realModName+"."))
|
||||||
|
jsCodeLock.Unlock()
|
||||||
}
|
}
|
||||||
if !inVM {
|
if !inVM {
|
||||||
rt.unlock()
|
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 {
|
func (rt *Runtime) StartFromCode(code, refFile string) error {
|
||||||
if refFile != "" {
|
if refFile != "" {
|
||||||
rt.file = refFile
|
rt.file = refFile
|
||||||
@ -507,6 +522,12 @@ func (rt *Runtime) StartFromCode(code, refFile string) error {
|
|||||||
rt.file = absFile
|
rt.file = absFile
|
||||||
}
|
}
|
||||||
refPath := filepath.Dir(refFile)
|
refPath := filepath.Dir(refFile)
|
||||||
|
|
||||||
|
vmIdLock.Lock()
|
||||||
|
vmId++
|
||||||
|
vmId1 := vmId
|
||||||
|
vmIdLock.Unlock()
|
||||||
|
rt.SetGoData("vmId", u.String(vmId1))
|
||||||
rt.SetGoData("startFile", refFile)
|
rt.SetGoData("startFile", refFile)
|
||||||
rt.SetGoData("startPath", refPath)
|
rt.SetGoData("startPath", refPath)
|
||||||
rt.vm.Set("__startFile", refFile)
|
rt.vm.Set("__startFile", refFile)
|
||||||
@ -614,6 +635,13 @@ func (rt *Runtime) StartFromProgram(prg *Program) error {
|
|||||||
if modErr != nil {
|
if modErr != nil {
|
||||||
return modErr
|
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("startFile", prg.startFile)
|
||||||
rt.SetGoData("startPath", filepath.Dir(prg.startFile))
|
rt.SetGoData("startPath", filepath.Dir(prg.startFile))
|
||||||
rt.lock()
|
rt.lock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user