Commit 8deab9e7 authored by Andrei Mihu's avatar Andrei Mihu
Browse files

New runtime function to get a single match by ID.

parent 92d944ff
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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.
+42 −22
Original line number Diff line number Diff line
@@ -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")
)
@@ -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.
@@ -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) {
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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
+30 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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)