package botlink import ( "context" "errors" "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" botlinkv1 "scrabble/pkg/proto/botlink/v1" telegramv1 "scrabble/pkg/proto/telegram/v1" ) // RelayServer lets the backend's admin console reach the remote bot through the // gateway: it implements the two admin delivery methods of the Telegram service by // forwarding them onto the bot-link and awaiting the bot's Ack. The validation and // out-of-app push methods are intentionally unimplemented here — login validation // runs against the home validator and out-of-app push goes straight to the Hub. type RelayServer struct { telegramv1.UnimplementedTelegramServer hub *Hub deadline time.Duration } // NewRelayServer builds the relay over hub. deadline bounds the wait for the bot's // Ack before reporting the send as not delivered. func NewRelayServer(hub *Hub, deadline time.Duration) *RelayServer { return &RelayServer{hub: hub, deadline: deadline} } // SendToUser forwards an admin message for one user to the bot and reports whether // it was delivered. A missing bot maps to Unavailable (parity with an unreachable // connector); a deadline before the Ack reports delivered=false. func (r *RelayServer) SendToUser(ctx context.Context, req *telegramv1.SendToUserRequest) (*telegramv1.SendResponse, error) { delivered, err := r.await(ctx, SendToUserCommand(req.GetExternalId(), req.GetText())) if err != nil { return nil, err } return &telegramv1.SendResponse{Delivered: delivered}, nil } // SendToGameChannel forwards an admin message for the game channel to the bot and // reports whether it was delivered. func (r *RelayServer) SendToGameChannel(ctx context.Context, req *telegramv1.SendToGameChannelRequest) (*telegramv1.SendResponse, error) { delivered, err := r.await(ctx, SendToGameChannelCommand(req.GetText())) if err != nil { return nil, err } return &telegramv1.SendResponse{Delivered: delivered}, nil } // await sends cmd with the relay deadline and translates the Hub outcome into the // gRPC contract the backend client expects. func (r *RelayServer) await(ctx context.Context, cmd *botlinkv1.Command) (bool, error) { cctx, cancel := context.WithTimeout(ctx, r.deadline) defer cancel() delivered, err := r.hub.SendAwait(cctx, cmd) switch { case errors.Is(err, ErrNoBot): return false, status.Error(codes.Unavailable, "no telegram bot connected") case err != nil: return false, status.Error(codes.Internal, err.Error()) default: return delivered, nil } }