package edge import "context" // The typed operations below each build a request, run Execute and decode the // response. They return the decoded value (where any), the domain result code // ("ok" or a stable error code) and a transport error. The scenario layer times the // call and records the code; a non-"ok" code with a nil error is a domain rejection // (for example "not_your_turn"), not a failure of the harness. // State fetches the caller's private view of a game. func (c *Client) State(ctx context.Context, token, gameID string) (State, string, error) { r, err := c.execute(ctx, token, msgState, stateReq(gameID, false)) if err != nil || r.Code != "ok" { return State{}, r.Code, err } return decodeState(r.Payload), r.Code, nil } // History fetches a game's decoded move journal (the board-replay source). func (c *Client) History(ctx context.Context, token, gameID string) ([]Move, string, error) { r, err := c.execute(ctx, token, msgHistory, gameAction(gameID)) if err != nil || r.Code != "ok" { return nil, r.Code, err } return decodeHistory(r.Payload), r.Code, nil } // SubmitPlay commits a play and returns the post-move game. func (c *Client) SubmitPlay(ctx context.Context, token, gameID, dir string, tiles []PlayTile) (Game, string, error) { r, err := c.execute(ctx, token, msgSubmitPlay, submitPlay(gameID, dir, tiles)) if err != nil || r.Code != "ok" { return Game{}, r.Code, err } return decodeMoveResultGame(r.Payload), r.Code, nil } // Pass forfeits the turn and returns the post-move game. func (c *Client) Pass(ctx context.Context, token, gameID string) (Game, string, error) { r, err := c.execute(ctx, token, msgPass, gameAction(gameID)) if err != nil || r.Code != "ok" { return Game{}, r.Code, err } return decodeMoveResultGame(r.Payload), r.Code, nil } // Exchange swaps the listed rack tiles and returns the post-move game. func (c *Client) Exchange(ctx context.Context, token, gameID string, tiles []byte) (Game, string, error) { r, err := c.execute(ctx, token, msgExchange, exchange(gameID, tiles)) if err != nil || r.Code != "ok" { return Game{}, r.Code, err } return decodeMoveResultGame(r.Payload), r.Code, nil } // Nudge prods the opponent whose turn it is. func (c *Client) Nudge(ctx context.Context, token, gameID string) (string, error) { r, err := c.execute(ctx, token, msgNudge, gameAction(gameID)) return r.Code, err } // ChatPost posts a per-game chat line. func (c *Client) ChatPost(ctx context.Context, token, gameID, body string) (string, error) { r, err := c.execute(ctx, token, msgChatPost, chatPost(gameID, body)) return r.Code, err } // CheckWord looks a word up in the game's pinned dictionary. func (c *Client) CheckWord(ctx context.Context, token, gameID string, word []byte) (string, error) { r, err := c.execute(ctx, token, msgCheckWord, checkWord(gameID, word)) return r.Code, err } // DraftSave stores the player's client-side composition. func (c *Client) DraftSave(ctx context.Context, token, gameID, jsonStr string) (string, error) { r, err := c.execute(ctx, token, msgDraftSave, draftSave(gameID, jsonStr)) return r.Code, err } // DraftGet retrieves the player's stored composition. func (c *Client) DraftGet(ctx context.Context, token, gameID string) (string, error) { r, err := c.execute(ctx, token, msgDraftGet, gameAction(gameID)) return r.Code, err } // ProfileUpdate overwrites the profile, resending the marker display name. func (c *Client) ProfileUpdate(ctx context.Context, token, displayName, lang string) (string, error) { r, err := c.execute(ctx, token, msgProfileUpd, updateProfile(displayName, lang)) return r.Code, err } // Stats reads the caller's lifetime statistics. func (c *Client) Stats(ctx context.Context, token string) (string, error) { r, err := c.execute(ctx, token, msgStatsGet, nil) return r.Code, err } // GamesList lists the caller's games (active and finished). func (c *Client) GamesList(ctx context.Context, token string) ([]Game, string, error) { r, err := c.execute(ctx, token, msgGamesList, nil) if err != nil || r.Code != "ok" { return nil, r.Code, err } return decodeGameList(r.Payload), r.Code, nil } // CreateInvitation proposes a 2-4 player friend game to the named invitees. func (c *Client) CreateInvitation(ctx context.Context, token string, inviteeIDs []string, variant string) (string, error) { r, err := c.execute(ctx, token, msgInvCreate, createInvitation(inviteeIDs, variant, 0)) return r.Code, err } // AcceptInvitation accepts an invitation by id (the completing accept starts the game). func (c *Client) AcceptInvitation(ctx context.Context, token, invitationID string) (string, error) { r, err := c.execute(ctx, token, msgInvAccept, invitationAction(invitationID)) return r.Code, err } // ListInvitations lists the caller's open invitations. func (c *Client) ListInvitations(ctx context.Context, token string) ([]Invitation, string, error) { r, err := c.execute(ctx, token, msgInvList, nil) if err != nil || r.Code != "ok" { return nil, r.Code, err } return decodeInvitationList(r.Payload), r.Code, nil } // Enqueue joins the per-variant auto-match pool and reports any immediate pairing. func (c *Client) Enqueue(ctx context.Context, token, variant string) (bool, Game, string, error) { r, err := c.execute(ctx, token, msgEnqueue, enqueueReq(variant)) if err != nil || r.Code != "ok" { return false, Game{}, r.Code, err } matched, game := decodeMatch(r.Payload) return matched, game, r.Code, nil }