github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/development/wasm/request.go (about) 1 //go:build wasm 2 // +build wasm 3 4 package main 5 6 import ( 7 "context" 8 "fmt" 9 "syscall/js" 10 11 "github.com/authzed/spicedb/pkg/development" 12 13 devinterface "github.com/authzed/spicedb/pkg/proto/developer/v1" 14 "google.golang.org/protobuf/encoding/protojson" 15 ) 16 17 // runDeveloperRequest is the function exported into the WASM environment for invoking 18 // one or more development operations. 19 // 20 // The arguments are: 21 // 22 // 1. Message in the form of a DeveloperRequest containing the context and the operation(s) to 23 // run, in JSON form. 24 // 25 // The function returns: 26 // 27 // A single JSON-encoded string of messages of type DeveloperResponse representing the errors 28 // encountered (if any), or the responses for each operation. 29 // 30 // See example/wasm.html for an example. 31 func runDeveloperRequest(this js.Value, args []js.Value) any { 32 if len(args) != 1 { 33 return respErr(fmt.Errorf("invalid number of arguments specified")) 34 } 35 36 // Unmarshal the developer request. 37 encoded := args[0].String() 38 devRequest := &devinterface.DeveloperRequest{} 39 err := protojson.Unmarshal([]byte(encoded), devRequest) 40 if err != nil { 41 return respErr(fmt.Errorf("could not decode developer request: %w", err)) 42 } 43 44 if devRequest.Context == nil { 45 return respErr(fmt.Errorf("missing required context")) 46 } 47 48 // Construct the developer context. 49 devContext, devErrors, err := development.NewDevContext(context.Background(), devRequest.Context) 50 if err != nil { 51 return respErr(err) 52 } 53 54 if devErrors != nil && len(devErrors.InputErrors) > 0 { 55 return respInputErr(devErrors.InputErrors) 56 } 57 58 // Run operations. 59 results := make(map[uint64]*devinterface.OperationResult, len(devRequest.Operations)) 60 for index, op := range devRequest.Operations { 61 result, err := runOperation(devContext, op) 62 if err != nil { 63 return respErr(err) 64 } 65 66 results[uint64(index)] = result 67 } 68 69 return encode(&devinterface.DeveloperResponse{ 70 OperationsResults: &devinterface.OperationsResults{ 71 Results: results, 72 }, 73 }) 74 } 75 76 func encode(response *devinterface.DeveloperResponse) js.Value { 77 encoded, err := protojson.Marshal(response) 78 if err != nil { 79 panic(err) 80 } 81 82 return js.ValueOf(string(encoded)) 83 } 84 85 func respErr(err error) js.Value { 86 return encode(&devinterface.DeveloperResponse{ 87 InternalError: err.Error(), 88 }) 89 } 90 91 func respInputErr(inputErrors []*devinterface.DeveloperError) js.Value { 92 return encode(&devinterface.DeveloperResponse{ 93 DeveloperErrors: &devinterface.DeveloperErrors{ 94 InputErrors: inputErrors, 95 }, 96 }) 97 }