github.com/0chain/gosdk@v1.17.11/wasmsdk/jsbridge/input.go (about) 1 //go:build js && wasm 2 // +build js,wasm 3 4 package jsbridge 5 6 import ( 7 "fmt" 8 "reflect" 9 "syscall/js" 10 ) 11 12 // InputBinder convert inputs from js.Value to reflect.Value 13 type InputBinder func([]js.Value) ([]reflect.Value, error) 14 15 // InputBuilder binder builder 16 type InputBuilder struct { 17 fn reflect.Type 18 numIn int 19 IsVariadic bool 20 binders []func(jv js.Value) (reflect.Value, error) 21 } 22 23 // NewInputBuilder create InputBuilder 24 func NewInputBuilder(fn reflect.Type) *InputBuilder { 25 return &InputBuilder{ 26 fn: fn, 27 numIn: fn.NumIn(), 28 IsVariadic: fn.IsVariadic(), 29 } 30 } 31 32 // Build build InputBinder 33 // js.ValueOf returns x as a JavaScript value: 34 // 35 // | Go | JavaScript | 36 // | ---------------------- | ---------------------- | 37 // | js.Value | [its value] | 38 // | js.Func | function | 39 // | nil | null | 40 // | bool | boolean | 41 // | integers and floats | number | 42 // | string | string | 43 // | []interface{} | new array | 44 // | map[string]interface{} | new object | 45 // 46 // Panics if x is not one of the expected types. 47 func (b *InputBuilder) Build() (InputBinder, error) { 48 defer func() { 49 if r := recover(); r != nil { 50 fmt.Println("[recover]InputBuilder.Build: ", r) 51 } 52 }() 53 54 b.binders = make([]func(jv js.Value) (reflect.Value, error), b.numIn) 55 56 if b.IsVariadic { 57 b.numIn-- 58 } 59 60 for i := 0; i < b.numIn; i++ { 61 inputType := b.fn.In(i) 62 63 v := reflect.New(inputType).Interface() 64 65 switch v.(type) { 66 case *string: 67 b.binders[i] = jsValueToString 68 69 case *int: 70 b.binders[i] = jsValueToInt 71 case *int32: 72 b.binders[i] = jsValueToInt32 73 case *int64: 74 b.binders[i] = jsValueToInt64 75 case *uint64: 76 b.binders[i] = jsValueToUInt64 77 case *float32: 78 b.binders[i] = jsValueToFloat32 79 case *float64: 80 b.binders[i] = jsValueToFloat64 81 case *bool: 82 b.binders[i] = jsValueToBool 83 case *[]string: 84 b.binders[i] = jsValueToStringSlice 85 case *[]byte: 86 b.binders[i] = jsValueToBytes 87 default: 88 fmt.Printf("TYPE: %#v\n", reflect.TypeOf(v)) 89 return nil, ErrBinderNotImplemented 90 } 91 92 } 93 94 return b.Bind, nil 95 } 96 97 // Bind bind js inputs to reflect values 98 func (b *InputBuilder) Bind(args []js.Value) ([]reflect.Value, error) { 99 if len(args) != b.numIn { 100 fmt.Println("args:", args) 101 return nil, ErrMismatchedInputLength 102 } 103 104 values := make([]reflect.Value, b.numIn) 105 for i := 0; i < b.numIn; i++ { 106 val, err := b.binders[i](args[i]) 107 if err != nil { 108 return nil, err 109 } 110 values[i] = val 111 } 112 113 return values, nil 114 } 115 116 func jsValueToString(jv js.Value) (val reflect.Value, err error) { 117 defer func() { 118 if r := recover(); r != nil { 119 err = fmt.Errorf("input: %s", r) 120 } 121 }() 122 123 i := "" 124 if jv.Truthy() { 125 i = jv.String() 126 } 127 128 val = reflect.ValueOf(i) 129 return 130 } 131 132 func jsValueToInt(jv js.Value) (val reflect.Value, err error) { 133 defer func() { 134 if r := recover(); r != nil { 135 err = fmt.Errorf("input: %s", r) 136 } 137 }() 138 i := 0 139 if jv.Truthy() { 140 i = jv.Int() 141 } 142 143 val = reflect.ValueOf(i) 144 return 145 } 146 147 func jsValueToInt32(jv js.Value) (val reflect.Value, err error) { 148 149 defer func() { 150 if r := recover(); r != nil { 151 err = fmt.Errorf("input: %s", r) 152 } 153 }() 154 i := 0 155 if jv.Truthy() { 156 i = jv.Int() 157 } 158 159 val = reflect.ValueOf(int32(i)) 160 return 161 } 162 163 func jsValueToInt64(jv js.Value) (val reflect.Value, err error) { 164 165 defer func() { 166 if r := recover(); r != nil { 167 err = fmt.Errorf("input: %s", r) 168 } 169 }() 170 i := 0 171 if jv.Truthy() { 172 i = jv.Int() 173 } 174 175 val = reflect.ValueOf(int64(i)) 176 return 177 } 178 179 func jsValueToUInt64(jv js.Value) (val reflect.Value, err error) { 180 181 defer func() { 182 if r := recover(); r != nil { 183 err = fmt.Errorf("input: %s", r) 184 } 185 }() 186 i := 0 187 if jv.Truthy() { 188 i = jv.Int() 189 } 190 191 val = reflect.ValueOf(uint64(i)) 192 return 193 } 194 195 func jsValueToBool(jv js.Value) (val reflect.Value, err error) { 196 197 defer func() { 198 if r := recover(); r != nil { 199 err = fmt.Errorf("input: %s", r) 200 } 201 }() 202 i := false 203 if jv.Truthy() { 204 i = jv.Bool() 205 } 206 207 val = reflect.ValueOf(i) 208 return 209 } 210 211 func jsValueToFloat32(jv js.Value) (val reflect.Value, err error) { 212 213 defer func() { 214 if r := recover(); r != nil { 215 err = fmt.Errorf("input: %s", r) 216 } 217 }() 218 var i float64 219 if jv.Truthy() { 220 i = jv.Float() 221 } 222 223 val = reflect.ValueOf(float32(i)) 224 return 225 } 226 227 func jsValueToFloat64(jv js.Value) (val reflect.Value, err error) { 228 229 defer func() { 230 if r := recover(); r != nil { 231 err = fmt.Errorf("input: %s", r) 232 } 233 }() 234 var i float64 235 if jv.Truthy() { 236 i = jv.Float() 237 } 238 239 val = reflect.ValueOf(i) 240 return 241 } 242 243 func jsValueToStringSlice(jv js.Value) (val reflect.Value, err error) { 244 245 defer func() { 246 if r := recover(); r != nil { 247 err = fmt.Errorf("input: %s", r) 248 } 249 }() 250 var list []string 251 252 if jv.Truthy() { 253 if js.Global().Get("Array").Call("isArray", jv).Bool() { 254 list = make([]string, jv.Length()) 255 for i := 0; i < len(list); i++ { 256 it := jv.Index(i) 257 if it.Truthy() { 258 list[i] = it.String() 259 } 260 } 261 } 262 } 263 264 val = reflect.ValueOf(list) 265 return 266 } 267 268 func jsValueToBytes(jv js.Value) (val reflect.Value, err error) { 269 270 defer func() { 271 if r := recover(); r != nil { 272 err = fmt.Errorf("input: %s", r) 273 } 274 }() 275 276 var buf []byte 277 278 if jv.Truthy() { 279 buf = make([]byte, jv.Length()) 280 js.CopyBytesToGo(buf, jv) 281 } 282 283 val = reflect.ValueOf(buf) 284 return 285 }