// Package connector is the backend's gRPC client for operator broadcasts: a direct // message to one user, or a post to the game channel. It calls the gateway's // bot-link relay (which forwards the send to the remote bot over the reverse mTLS // link and reports back whether it was delivered). The relay lives on the trusted // internal network, so the connection uses insecure (plaintext) transport // credentials (docs/ARCHITECTURE.md ยง12). It speaks the Telegram service contract, // narrowed to the two broadcast methods the admin surface needs. package connector import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" telegramv1 "scrabble/pkg/proto/telegram/v1" ) // Client wraps the connector's Telegram gRPC service. type Client struct { conn *grpc.ClientConn c telegramv1.TelegramClient } // New dials the connector gRPC endpoint at addr. func New(addr string) (*Client, error) { conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return nil, fmt.Errorf("connector: dial %s: %w", addr, err) } return &Client{conn: conn, c: telegramv1.NewTelegramClient(conn)}, nil } // Close releases the gRPC connection. func (c *Client) Close() error { return c.conn.Close() } // SendToUser sends an operator text message to one user, addressed by their // platform external_id, through the bot. delivered reports whether the connector // actually sent it (false when the user has not started the bot). func (c *Client) SendToUser(ctx context.Context, externalID, text string) (bool, error) { resp, err := c.c.SendToUser(ctx, &telegramv1.SendToUserRequest{ExternalId: externalID, Text: text}) if err != nil { return false, err } return resp.GetDelivered(), nil } // SendToGameChannel posts an operator text message to the bot's game channel. // delivered reports whether the connector sent it (false when the bot has no // channel configured). func (c *Client) SendToGameChannel(ctx context.Context, text string) (bool, error) { resp, err := c.c.SendToGameChannel(ctx, &telegramv1.SendToGameChannelRequest{Text: text}) if err != nil { return false, err } return resp.GetDelivered(), nil }