package message import ( "context" "io" "github.com/go-faster/errors" "github.com/gotd/td/internal/crypto" "github.com/gotd/td/telegram/message/peer" "github.com/gotd/td/telegram/uploader" "github.com/gotd/td/tg" ) // Sender is a message sending helper. type Sender struct { raw *tg.Client rand io.Reader uploader Uploader resolver peer.Resolver } // NewSender creates a new Sender. func NewSender(raw *tg.Client) *Sender { return &Sender{ raw: raw, rand: crypto.DefaultRand(), uploader: uploader.NewUploader(raw), resolver: peer.DefaultResolver(raw), } } // WithUploader sets file uploader to use. func (s *Sender) WithUploader(u Uploader) *Sender { s.uploader = u return s } // WithResolver sets peer resolver to use. func (s *Sender) WithResolver(resolver peer.Resolver) *Sender { s.resolver = resolver return s } // WithRand sets random ID source. func (s *Sender) WithRand(r io.Reader) *Sender { s.rand = r return s } // ClearAllDrafts clears all drafts in all peers. func (s *Sender) ClearAllDrafts(ctx context.Context) error { _, err := s.raw.MessagesClearAllDrafts(ctx) return err } // sendMessage sends message to peer. func (s *Sender) sendMessage(ctx context.Context, req *tg.MessagesSendMessageRequest) (tg.UpdatesClass, error) { if req.RandomID == 0 { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.RandomID = id } return s.raw.MessagesSendMessage(ctx, req) } // sendMedia sends message with single media to peer. func (s *Sender) sendMedia(ctx context.Context, req *tg.MessagesSendMediaRequest) (tg.UpdatesClass, error) { if req.RandomID == 0 { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.RandomID = id } return s.raw.MessagesSendMedia(ctx, req) } // sendMultiMedia sends message with multiple media to peer. func (s *Sender) sendMultiMedia(ctx context.Context, req *tg.MessagesSendMultiMediaRequest) (tg.UpdatesClass, error) { for i := range req.MultiMedia { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.MultiMedia[i].RandomID = id } return s.raw.MessagesSendMultiMedia(ctx, req) } // editMessage edits message. func (s *Sender) editMessage(ctx context.Context, req *tg.MessagesEditMessageRequest) (tg.UpdatesClass, error) { return s.raw.MessagesEditMessage(ctx, req) } // forwardMessages forwards message to peer. func (s *Sender) forwardMessages(ctx context.Context, req *tg.MessagesForwardMessagesRequest) (tg.UpdatesClass, error) { req.RandomID = make([]int64, len(req.ID)) for i := range req.RandomID { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.RandomID[i] = id } return s.raw.MessagesForwardMessages(ctx, req) } // sendInlineBotResult sends inline query result message to peer. func (s *Sender) sendInlineBotResult( ctx context.Context, req *tg.MessagesSendInlineBotResultRequest, ) (tg.UpdatesClass, error) { if req.RandomID == 0 { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.RandomID = id } return s.raw.MessagesSendInlineBotResult(ctx, req) } // uploadMedia uploads file and associate it to a chat (without actually sending it to the chat). func (s *Sender) uploadMedia(ctx context.Context, req *tg.MessagesUploadMediaRequest) (tg.MessageMediaClass, error) { return s.raw.MessagesUploadMedia(ctx, req) } // getDocumentByHash finds document by hash, MIME type and size. func (s *Sender) getDocumentByHash( ctx context.Context, req *tg.MessagesGetDocumentByHashRequest, ) (tg.DocumentClass, error) { return s.raw.MessagesGetDocumentByHash(ctx, req) } // saveDraft saves a message draft associated to a chat. func (s *Sender) saveDraft(ctx context.Context, req *tg.MessagesSaveDraftRequest) error { _, err := s.raw.MessagesSaveDraft(ctx, req) return err } // sendVote votes in a poll. func (s *Sender) sendVote(ctx context.Context, req *tg.MessagesSendVoteRequest) (tg.UpdatesClass, error) { return s.raw.MessagesSendVote(ctx, req) } // setTyping sends a typing event to a conversation partner or group. func (s *Sender) setTyping(ctx context.Context, req *tg.MessagesSetTypingRequest) error { _, err := s.raw.MessagesSetTyping(ctx, req) return err } // report reports a message in a chat for violation of Telegram's Terms of Service. func (s *Sender) report(ctx context.Context, req *tg.MessagesReportRequest) (bool, error) { return s.raw.MessagesReport(ctx, req) } // reportSpam reports a new incoming chat for spam, if the peer settings of the chat allow us to do that. func (s *Sender) reportSpam(ctx context.Context, p tg.InputPeerClass) (bool, error) { return s.raw.MessagesReportSpam(ctx, p) } func (s *Sender) sendReaction( ctx context.Context, p tg.InputPeerClass, msgID int, reaction string, ) (tg.UpdatesClass, error) { return s.raw.MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ Peer: p, MsgID: msgID, Reaction: reaction, }) } // sendScreenshotNotification sends notification about screenshot to peer. func (s *Sender) sendScreenshotNotification( ctx context.Context, req *tg.MessagesSendScreenshotNotificationRequest, ) (tg.UpdatesClass, error) { if req.RandomID == 0 { id, err := crypto.RandInt64(s.rand) if err != nil { return nil, errors.Wrap(err, "generate random_id") } req.RandomID = id } return s.raw.MessagesSendScreenshotNotification(ctx, req) } // getPeerSettings returns peer settings. func (s *Sender) getPeerSettings(ctx context.Context, p tg.InputPeerClass) (*tg.MessagesPeerSettings, error) { return s.raw.MessagesGetPeerSettings(ctx, p) } // sendScheduledMessages sends scheduled messages using given ids. func (s *Sender) sendScheduledMessages( ctx context.Context, req *tg.MessagesSendScheduledMessagesRequest, ) (tg.UpdatesClass, error) { return s.raw.MessagesSendScheduledMessages(ctx, req) } // deleteScheduledMessages deletes scheduled messages using given ids. func (s *Sender) deleteScheduledMessages( ctx context.Context, req *tg.MessagesDeleteScheduledMessagesRequest, ) (tg.UpdatesClass, error) { return s.raw.MessagesDeleteScheduledMessages(ctx, req) } // getScheduledHistory gets scheduled messages history. func (s *Sender) getScheduledHistory( ctx context.Context, req *tg.MessagesGetScheduledHistoryRequest, ) (tg.MessagesMessagesClass, error) { return s.raw.MessagesGetScheduledHistory(ctx, req) } // getScheduledMessages gets scheduled messages using given ids. func (s *Sender) getScheduledMessages( ctx context.Context, req *tg.MessagesGetScheduledMessagesRequest, ) (tg.MessagesMessagesClass, error) { return s.raw.MessagesGetScheduledMessages(ctx, req) } // importChatInvite imports a chat invite and join a private chat/supergroup/channel. func (s *Sender) importChatInvite( ctx context.Context, hash string, ) (tg.UpdatesClass, error) { return s.raw.MessagesImportChatInvite(ctx, hash) } // joinChannel joins a channel/supergroup. func (s *Sender) joinChannel( ctx context.Context, input tg.InputChannelClass, ) (tg.UpdatesClass, error) { return s.raw.ChannelsJoinChannel(ctx, input) } // leaveChannel leaves a channel/supergroup. func (s *Sender) leaveChannel( ctx context.Context, input tg.InputChannelClass, ) (tg.UpdatesClass, error) { return s.raw.ChannelsLeaveChannel(ctx, input) } // deleteChatUser delete user from chat. func (s *Sender) deleteChatUser( ctx context.Context, req *tg.MessagesDeleteChatUserRequest, ) (tg.UpdatesClass, error) { return s.raw.MessagesDeleteChatUser(ctx, req) } // deleteChannelMessages deletes messages in channel. func (s *Sender) deleteChannelMessages( ctx context.Context, req *tg.ChannelsDeleteMessagesRequest, ) (*tg.MessagesAffectedMessages, error) { return s.raw.ChannelsDeleteMessages(ctx, req) } // deleteMessages deletes messages in chat. func (s *Sender) deleteMessages( ctx context.Context, req *tg.MessagesDeleteMessagesRequest, ) (*tg.MessagesAffectedMessages, error) { return s.raw.MessagesDeleteMessages(ctx, req) }