github.com/0chain/gosdk@v1.17.11/wasmsdk/jsbridge/func.go (about) 1 //go:build js && wasm 2 // +build js,wasm 3 4 package jsbridge 5 6 import ( 7 "fmt" 8 "log" 9 "reflect" 10 "syscall/js" 11 ) 12 13 // BindFunc bind go func to js func in global 14 // only support 15 // - func(...) 16 // - func(...) error 17 // - func(...) T 18 // - func(...) (T,error) 19 func BindFunc(global js.Value, jsFuncName string, fn interface{}) error { 20 21 jsFunc, err := promise(fn) 22 if err != nil { 23 return err 24 } 25 26 global.Set(jsFuncName, jsFunc) 27 28 return nil 29 } 30 31 func BindAsyncFuncs(global js.Value, fnList map[string]interface{}) { 32 33 for jsFuncName, fn := range fnList { 34 if jsFuncName == "registerAuthorizer" || jsFuncName == "callAuth" || jsFuncName == "registerAuthCommon" { 35 global.Set(jsFuncName, fn) 36 } else { 37 jsFunc, err := promise(fn) 38 39 if err != nil { 40 log.Println("bridge promise failed:", jsFuncName, err) 41 } 42 43 global.Set(jsFuncName, jsFunc) 44 } 45 } 46 } 47 48 func BindFuncs(global js.Value, fnList map[string]interface{}) { 49 50 for jsFuncName, fn := range fnList { 51 jsFunc, err := invoke(fn) 52 53 if err != nil { 54 log.Println("[", jsFuncName, "]", err) 55 continue 56 } 57 58 global.Set(jsFuncName, jsFunc) 59 } 60 61 } 62 63 func invoke(fn interface{}) (js.Func, error) { 64 funcType := reflect.TypeOf(fn) 65 66 if funcType.Kind() != reflect.Func { 67 return js.Func{}, ErrIsNotFunc 68 } 69 70 numOut := funcType.NumOut() 71 72 if numOut > 2 { 73 return js.Func{}, ErrFuncNotSupported 74 } 75 76 syncInvoker, err := Sync(funcType) 77 78 if err != nil { 79 return js.Func{}, err 80 } 81 82 invoker := reflect.ValueOf(fn) 83 84 if err != nil { 85 return js.Func{}, err 86 } 87 88 inputBuilder, err := NewInputBuilder(funcType).Build() 89 90 if err != nil { 91 return js.Func{}, err 92 } 93 94 jsFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 95 defer func() { 96 if r := recover(); r != nil { 97 fmt.Println("[recover]", r) 98 } 99 }() 100 101 in, err := inputBuilder(args) 102 if err != nil { 103 return NewJsError(err.Error()) 104 } 105 106 result := syncInvoker(invoker, in) 107 108 return result 109 }) 110 111 jsFuncList = append(jsFuncList, jsFunc) 112 113 return jsFunc, nil 114 } 115 116 func promise(fn interface{}) (js.Func, error) { 117 funcType := reflect.TypeOf(fn) 118 119 if funcType.Kind() != reflect.Func { 120 return js.Func{}, ErrIsNotFunc 121 } 122 123 numOut := funcType.NumOut() 124 125 if numOut > 2 { 126 return js.Func{}, ErrFuncNotSupported 127 } 128 129 awaiter, err := Async(funcType) 130 131 if err != nil { 132 return js.Func{}, err 133 } 134 135 inputBuilder, err := NewInputBuilder(funcType).Build() 136 137 if err != nil { 138 return js.Func{}, err 139 } 140 141 invoker := reflect.ValueOf(fn) 142 143 jsFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 144 145 defer func() { 146 if r := recover(); r != nil { 147 fmt.Println("[recover]", r) 148 } 149 }() 150 151 in, err := inputBuilder(args) 152 153 handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 154 resolve := args[0] 155 reject := args[1] 156 157 go awaiter(resolve, reject, invoker, in, err) 158 159 return nil 160 }) 161 162 jsFuncList = append(jsFuncList, handler) 163 164 promise := js.Global().Get("Promise") 165 return promise.New(handler) 166 }) 167 168 jsFuncList = append(jsFuncList, jsFunc) 169 170 return jsFunc, nil 171 }