Loading CHANGELOG.md +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr - Independent config flags for socket read and write buffer sizes. - Expose session fields in authoritative match join attempt contexts. - Add group ID to content of in-app notifications relating to groups. - New runtime function to get a single match by ID. ### Changed - Replace metrics implementation. Loading server/match_registry.go +42 −22 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ var ( MatchLabelMaxBytes = 2048 ErrCannotEncodeParams = errors.New("error creating match: cannot encode params") ErrMatchIdInvalid = errors.New("match id invalid") ErrMatchLabelTooLong = errors.New("match label too long, must be 0-2048 bytes") ErrDeferredBroadcastFull = errors.New("too many deferred message broadcasts per tick") ) Loading @@ -71,13 +72,11 @@ type MatchRegistry interface { CreateMatch(ctx context.Context, logger *zap.Logger, createFn RuntimeMatchCreateFunction, module string, params map[string]interface{}) (string, error) // Register and initialise a match that's ready to run. NewMatch(logger *zap.Logger, id uuid.UUID, core RuntimeMatchCore, stopped *atomic.Bool, params map[string]interface{}) (*MatchHandler, error) // Return a match handler by ID, only from the local node. GetMatch(id uuid.UUID) *MatchHandler // Return a match by ID. GetMatch(ctx context.Context, id string) (*api.Match, error) // Remove a tracked match and ensure all its presences are cleaned up. // Does not ensure the match process itself is no longer running, that must be handled separately. RemoveMatch(id uuid.UUID, stream PresenceStream) // Get the label for a match. GetMatchLabel(ctx context.Context, id uuid.UUID, node string) (string, error) // Update the label entry for a given match. UpdateMatchLabel(id uuid.UUID, label string) error // List (and optionally filter) currently running matches. Loading Loading @@ -191,12 +190,47 @@ func (r *LocalMatchRegistry) NewMatch(logger *zap.Logger, id uuid.UUID, core Run return match, nil } func (r *LocalMatchRegistry) GetMatch(id uuid.UUID) *MatchHandler { mh, ok := r.matches.Load(id) func (r *LocalMatchRegistry) GetMatch(ctx context.Context, id string) (*api.Match, error) { // Validate the match ID. idComponents := strings.SplitN(id, ".", 2) if len(idComponents) != 2 { return nil, ErrMatchIdInvalid } matchID, err := uuid.FromString(idComponents[0]) if err != nil { return nil, ErrMatchIdInvalid } // Relayed match. if idComponents[1] == "" { size := r.tracker.CountByStream(PresenceStream{Mode: StreamModeMatchRelayed, Subject: matchID}) if size == 0 { return nil, nil } return &api.Match{ MatchId: id, Size: int32(size), }, nil } // Authoritative match. if idComponents[1] != r.node { return nil, nil } mh, ok := r.matches.Load(matchID) if !ok { return nil return nil, nil } return mh.(*MatchHandler) handler := mh.(*MatchHandler) return &api.Match{ MatchId: handler.IDStr, Authoritative: true, Label: &wrappers.StringValue{Value: handler.Label()}, Size: int32(handler.PresenceList.Size()), }, nil } func (r *LocalMatchRegistry) RemoveMatch(id uuid.UUID, stream PresenceStream) { Loading @@ -220,20 +254,6 @@ func (r *LocalMatchRegistry) RemoveMatch(id uuid.UUID, stream PresenceStream) { } } func (r *LocalMatchRegistry) GetMatchLabel(ctx context.Context, id uuid.UUID, node string) (string, error) { if node != r.node { // Match does not exist. return "", nil } mh, ok := r.matches.Load(id) if !ok { // Match does not exist, or has already ended. return "", nil } return mh.(*MatchHandler).Label(), nil } func (r *LocalMatchRegistry) UpdateMatchLabel(id uuid.UUID, label string) error { if len(label) > MatchLabelMaxBytes { return ErrMatchLabelTooLong Loading server/runtime_go_nakama.go +4 −0 Original line number Diff line number Diff line Loading @@ -861,6 +861,10 @@ func (n *RuntimeGoNakamaModule) MatchCreate(ctx context.Context, module string, return n.matchRegistry.CreateMatch(ctx, n.logger, fn, module, params) } func (n *RuntimeGoNakamaModule) MatchGet(ctx context.Context, id string) (*api.Match, error) { return n.matchRegistry.GetMatch(ctx, id) } func (n *RuntimeGoNakamaModule) MatchList(ctx context.Context, limit int, authoritative bool, label string, minSize, maxSize *int, query string) ([]*api.Match, error) { authoritativeWrapper := &wrappers.BoolValue{Value: authoritative} var labelWrapper *wrappers.StringValue Loading server/runtime_lua_nakama.go +30 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ func (n *RuntimeLuaNakamaModule) Loader(l *lua.LState) int { "stream_send_raw": n.streamSendRaw, "session_disconnect": n.sessionDisconnect, "match_create": n.matchCreate, "match_get": n.matchGet, "match_list": n.matchList, "notification_send": n.notificationSend, "notifications_send": n.notificationsSend, Loading Loading @@ -3217,6 +3218,35 @@ func (n *RuntimeLuaNakamaModule) matchCreate(l *lua.LState) int { return 1 } func (n *RuntimeLuaNakamaModule) matchGet(l *lua.LState) int { // Parse match ID. id := l.CheckString(1) result, err := n.matchRegistry.GetMatch(l.Context(), id) if err != nil { l.RaiseError(fmt.Sprintf("failed to get match: %s", err.Error())) return 0 } if result == nil { l.Push(lua.LNil) return 1 } match := l.CreateTable(0, 4) match.RawSetString("match_id", lua.LString(result.MatchId)) match.RawSetString("authoritative", lua.LBool(result.Authoritative)) if result.Label == nil { match.RawSetString("label", lua.LNil) } else { match.RawSetString("label", lua.LString(result.Label.Value)) } match.RawSetString("size", lua.LNumber(result.Size)) l.Push(match) return 1 } func (n *RuntimeLuaNakamaModule) matchList(l *lua.LState) int { // Parse limit. limit := l.OptInt(1, 1) Loading Loading
CHANGELOG.md +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr - Independent config flags for socket read and write buffer sizes. - Expose session fields in authoritative match join attempt contexts. - Add group ID to content of in-app notifications relating to groups. - New runtime function to get a single match by ID. ### Changed - Replace metrics implementation. Loading
server/match_registry.go +42 −22 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ var ( MatchLabelMaxBytes = 2048 ErrCannotEncodeParams = errors.New("error creating match: cannot encode params") ErrMatchIdInvalid = errors.New("match id invalid") ErrMatchLabelTooLong = errors.New("match label too long, must be 0-2048 bytes") ErrDeferredBroadcastFull = errors.New("too many deferred message broadcasts per tick") ) Loading @@ -71,13 +72,11 @@ type MatchRegistry interface { CreateMatch(ctx context.Context, logger *zap.Logger, createFn RuntimeMatchCreateFunction, module string, params map[string]interface{}) (string, error) // Register and initialise a match that's ready to run. NewMatch(logger *zap.Logger, id uuid.UUID, core RuntimeMatchCore, stopped *atomic.Bool, params map[string]interface{}) (*MatchHandler, error) // Return a match handler by ID, only from the local node. GetMatch(id uuid.UUID) *MatchHandler // Return a match by ID. GetMatch(ctx context.Context, id string) (*api.Match, error) // Remove a tracked match and ensure all its presences are cleaned up. // Does not ensure the match process itself is no longer running, that must be handled separately. RemoveMatch(id uuid.UUID, stream PresenceStream) // Get the label for a match. GetMatchLabel(ctx context.Context, id uuid.UUID, node string) (string, error) // Update the label entry for a given match. UpdateMatchLabel(id uuid.UUID, label string) error // List (and optionally filter) currently running matches. Loading Loading @@ -191,12 +190,47 @@ func (r *LocalMatchRegistry) NewMatch(logger *zap.Logger, id uuid.UUID, core Run return match, nil } func (r *LocalMatchRegistry) GetMatch(id uuid.UUID) *MatchHandler { mh, ok := r.matches.Load(id) func (r *LocalMatchRegistry) GetMatch(ctx context.Context, id string) (*api.Match, error) { // Validate the match ID. idComponents := strings.SplitN(id, ".", 2) if len(idComponents) != 2 { return nil, ErrMatchIdInvalid } matchID, err := uuid.FromString(idComponents[0]) if err != nil { return nil, ErrMatchIdInvalid } // Relayed match. if idComponents[1] == "" { size := r.tracker.CountByStream(PresenceStream{Mode: StreamModeMatchRelayed, Subject: matchID}) if size == 0 { return nil, nil } return &api.Match{ MatchId: id, Size: int32(size), }, nil } // Authoritative match. if idComponents[1] != r.node { return nil, nil } mh, ok := r.matches.Load(matchID) if !ok { return nil return nil, nil } return mh.(*MatchHandler) handler := mh.(*MatchHandler) return &api.Match{ MatchId: handler.IDStr, Authoritative: true, Label: &wrappers.StringValue{Value: handler.Label()}, Size: int32(handler.PresenceList.Size()), }, nil } func (r *LocalMatchRegistry) RemoveMatch(id uuid.UUID, stream PresenceStream) { Loading @@ -220,20 +254,6 @@ func (r *LocalMatchRegistry) RemoveMatch(id uuid.UUID, stream PresenceStream) { } } func (r *LocalMatchRegistry) GetMatchLabel(ctx context.Context, id uuid.UUID, node string) (string, error) { if node != r.node { // Match does not exist. return "", nil } mh, ok := r.matches.Load(id) if !ok { // Match does not exist, or has already ended. return "", nil } return mh.(*MatchHandler).Label(), nil } func (r *LocalMatchRegistry) UpdateMatchLabel(id uuid.UUID, label string) error { if len(label) > MatchLabelMaxBytes { return ErrMatchLabelTooLong Loading
server/runtime_go_nakama.go +4 −0 Original line number Diff line number Diff line Loading @@ -861,6 +861,10 @@ func (n *RuntimeGoNakamaModule) MatchCreate(ctx context.Context, module string, return n.matchRegistry.CreateMatch(ctx, n.logger, fn, module, params) } func (n *RuntimeGoNakamaModule) MatchGet(ctx context.Context, id string) (*api.Match, error) { return n.matchRegistry.GetMatch(ctx, id) } func (n *RuntimeGoNakamaModule) MatchList(ctx context.Context, limit int, authoritative bool, label string, minSize, maxSize *int, query string) ([]*api.Match, error) { authoritativeWrapper := &wrappers.BoolValue{Value: authoritative} var labelWrapper *wrappers.StringValue Loading
server/runtime_lua_nakama.go +30 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ func (n *RuntimeLuaNakamaModule) Loader(l *lua.LState) int { "stream_send_raw": n.streamSendRaw, "session_disconnect": n.sessionDisconnect, "match_create": n.matchCreate, "match_get": n.matchGet, "match_list": n.matchList, "notification_send": n.notificationSend, "notifications_send": n.notificationsSend, Loading Loading @@ -3217,6 +3218,35 @@ func (n *RuntimeLuaNakamaModule) matchCreate(l *lua.LState) int { return 1 } func (n *RuntimeLuaNakamaModule) matchGet(l *lua.LState) int { // Parse match ID. id := l.CheckString(1) result, err := n.matchRegistry.GetMatch(l.Context(), id) if err != nil { l.RaiseError(fmt.Sprintf("failed to get match: %s", err.Error())) return 0 } if result == nil { l.Push(lua.LNil) return 1 } match := l.CreateTable(0, 4) match.RawSetString("match_id", lua.LString(result.MatchId)) match.RawSetString("authoritative", lua.LBool(result.Authoritative)) if result.Label == nil { match.RawSetString("label", lua.LNil) } else { match.RawSetString("label", lua.LString(result.Label.Value)) } match.RawSetString("size", lua.LNumber(result.Size)) l.Push(match) return 1 } func (n *RuntimeLuaNakamaModule) matchList(l *lua.LState) int { // Parse limit. limit := l.OptInt(1, 1) Loading