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  }