diff --git a/CHANGELOG.md b/CHANGELOG.md index a7953363fe3e0ee93ee0a07445e47abe135f3a44..f72fa27c6d476e7c0f98893e505125beffdaa251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr ## [Unreleased] ### Added - Add ctx field to access http request headers in the runtimes. +- New JS runtime stringToBinary and binaryToString functions. ### Fixed - Gracefully close Lua matches when call queue fills up. @@ -15,6 +16,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr ### Changed - Set JS runtime custom error message as the returned payload message in RPC requests. +- JS runtime match data changed to Uint8Array. ## [3.9.0] - 2021-10-29 ### Added diff --git a/server/runtime_javascript_match_core.go b/server/runtime_javascript_match_core.go index e5c72661a6a2726eefdf95e419f834944ca9b350..7c03998706d55942c415949d7614b0eaef434bbb 100644 --- a/server/runtime_javascript_match_core.go +++ b/server/runtime_javascript_match_core.go @@ -393,10 +393,10 @@ func (rm *RuntimeJavaScriptMatchCore) MatchLoop(tick int64, state interface{}, i msgMap := make(map[string]interface{}, 5) msgMap["sender"] = presenceMap msgMap["opCode"] = msg.OpCode - if msg.Data != nil { - msgMap["data"] = string(msg.Data) - } else { + if msg.Data == nil { msgMap["data"] = goja.Null() + } else { + msgMap["data"] = rm.vm.NewArrayBuffer(msg.Data) } msgMap["reliable"] = msg.Reliable msgMap["receiveTimeMs"] = msg.ReceiveTime @@ -563,11 +563,15 @@ func (rm *RuntimeJavaScriptMatchCore) validateBroadcast(r *goja.Runtime, f goja. var dataBytes []byte data := f.Argument(1) if !goja.IsUndefined(data) && !goja.IsNull(data) { - dataStr, ok := data.Export().(string) - if !ok { - panic(r.NewTypeError("expects data to be a string or nil")) + dataExport := data.Export() + switch dataExport.(type) { + case string: + dataBytes = []byte(dataExport.(string)) + case goja.ArrayBuffer: + dataBytes = dataExport.(goja.ArrayBuffer).Bytes() + default: + panic(r.NewTypeError("expects data to be an Uint8Array, a string or nil")) } - dataBytes = []byte(dataStr) } filter := f.Argument(2) diff --git a/server/runtime_javascript_nakama.go b/server/runtime_javascript_nakama.go index b7bce33d060e0468bc195b7ca977785599262d41..a482aad10c9bf102b4631f86527d5542fca1837d 100644 --- a/server/runtime_javascript_nakama.go +++ b/server/runtime_javascript_nakama.go @@ -39,6 +39,7 @@ import ( "net/http" "strings" "time" + "unicode/utf8" "github.com/dop251/goja" "github.com/gofrs/uuid" @@ -250,6 +251,42 @@ func (n *runtimeJavascriptNakamaModule) mappings(r *goja.Runtime) map[string]fun "channelMessageSend": n.channelMessageSend(r), "channelMessageUpdate": n.channelMessageUpdate(r), "channeldIdBuild": n.channelIdBuild(r), + "binaryToString": n.binaryToString(r), + "stringToBinary": n.stringToBinary(r), + } +} + +func (n *runtimeJavascriptNakamaModule) binaryToString(r *goja.Runtime) func(goja.FunctionCall) goja.Value { + return func(f goja.FunctionCall) goja.Value { + if goja.IsUndefined(f.Argument(0)) || goja.IsNull(f.Argument(0)) { + panic(r.NewTypeError("expects a Uint8Array object")) + } + + data, ok := f.Argument(0).Export().(goja.ArrayBuffer) + if !ok { + panic(r.NewTypeError("expects a Uint8Array object")) + } + + if !utf8.Valid(data.Bytes()) { + panic(r.NewTypeError("expects data to be UTF-8 encoded")) + } + + return r.ToValue(string(data.Bytes())) + } +} + +func (n *runtimeJavascriptNakamaModule) stringToBinary(r *goja.Runtime) func(goja.FunctionCall) goja.Value { + return func(f goja.FunctionCall) goja.Value { + if goja.IsUndefined(f.Argument(0)) || goja.IsNull(f.Argument(0)) { + panic(r.NewTypeError("expects a string")) + } + + str, ok := f.Argument(0).Export().(string) + if !ok { + panic(r.NewTypeError("expects a string")) + } + + return r.ToValue([]byte(str)) } }