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  }