@@ -6,6 +6,7 @@ use chrono::Utc;
66use grammers_client:: InputMessage ;
77use grammers_session:: defs:: PeerRef ;
88use grammers_tl_types as tl;
9+ use rand:: Rng ;
910
1011/// Decode a file_id string back to its components.
1112/// Returns (doc_id, access_hash, file_reference)
@@ -55,6 +56,117 @@ impl App {
5556 Ok ( msg. id ( ) as i64 )
5657 }
5758
59+ /// Send a text message to a specific forum topic by ID, returns the message ID.
60+ /// Uses raw TL invocation to set top_msg_id for topic support.
61+ pub async fn send_text_to_topic (
62+ & mut self ,
63+ chat_id : i64 ,
64+ topic_id : i32 ,
65+ text : & str ,
66+ ) -> Result < i64 > {
67+ let peer_ref = self . resolve_peer_ref ( chat_id) . await ?;
68+ let input_peer: tl:: enums:: InputPeer = peer_ref. into ( ) ;
69+
70+ let random_id: i64 = rand:: rng ( ) . random ( ) ;
71+
72+ let request = tl:: functions:: messages:: SendMessage {
73+ no_webpage : true ,
74+ silent : false ,
75+ background : false ,
76+ clear_draft : false ,
77+ noforwards : false ,
78+ update_stickersets_order : false ,
79+ invert_media : false ,
80+ allow_paid_floodskip : false ,
81+ peer : input_peer,
82+ reply_to : Some (
83+ tl:: types:: InputReplyToMessage {
84+ reply_to_msg_id : topic_id,
85+ top_msg_id : Some ( topic_id) ,
86+ reply_to_peer_id : None ,
87+ quote_text : None ,
88+ quote_entities : None ,
89+ quote_offset : None ,
90+ monoforum_peer_id : None ,
91+ todo_item_id : None ,
92+ }
93+ . into ( ) ,
94+ ) ,
95+ message : text. to_string ( ) ,
96+ random_id,
97+ reply_markup : None ,
98+ entities : None ,
99+ schedule_date : None ,
100+ send_as : None ,
101+ quick_reply_shortcut : None ,
102+ effect : None ,
103+ allow_paid_stars : None ,
104+ suggested_post : None ,
105+ } ;
106+
107+ let updates = self . tg . client . invoke ( & request) . await ?;
108+
109+ // Extract message ID from updates
110+ let msg_id = Self :: extract_message_id_from_updates ( & updates) ?;
111+
112+ let now = Utc :: now ( ) ;
113+ self . store
114+ . upsert_message ( UpsertMessageParams {
115+ id : msg_id,
116+ chat_id,
117+ sender_id : 0 ,
118+ ts : now,
119+ edit_ts : None ,
120+ from_me : true ,
121+ text : text. to_string ( ) ,
122+ media_type : None ,
123+ media_path : None ,
124+ reply_to_id : None ,
125+ topic_id : Some ( topic_id as i64 ) ,
126+ } )
127+ . await ?;
128+
129+ // Update chat's last_message_ts
130+ self . store
131+ . upsert_chat ( chat_id, "user" , "" , None , Some ( now) , false )
132+ . await ?;
133+
134+ Ok ( msg_id)
135+ }
136+
137+ /// Extract message ID from Updates response
138+ fn extract_message_id_from_updates ( updates : & tl:: enums:: Updates ) -> Result < i64 > {
139+ match updates {
140+ tl:: enums:: Updates :: Updates ( u) => {
141+ for update in & u. updates {
142+ if let tl:: enums:: Update :: NewMessage ( m) = update {
143+ if let tl:: enums:: Message :: Message ( msg) = & m. message {
144+ return Ok ( msg. id as i64 ) ;
145+ }
146+ }
147+ if let tl:: enums:: Update :: NewChannelMessage ( m) = update {
148+ if let tl:: enums:: Message :: Message ( msg) = & m. message {
149+ return Ok ( msg. id as i64 ) ;
150+ }
151+ }
152+ }
153+ anyhow:: bail!( "No message ID found in Updates response" )
154+ }
155+ tl:: enums:: Updates :: UpdateShort ( u) => {
156+ if let tl:: enums:: Update :: NewMessage ( m) = & u. update {
157+ if let tl:: enums:: Message :: Message ( msg) = & m. message {
158+ return Ok ( msg. id as i64 ) ;
159+ }
160+ }
161+ anyhow:: bail!( "No message ID found in UpdateShort response" )
162+ }
163+ tl:: enums:: Updates :: UpdateShortMessage ( u) => Ok ( u. id as i64 ) ,
164+ tl:: enums:: Updates :: UpdateShortChatMessage ( u) => Ok ( u. id as i64 ) ,
165+ tl:: enums:: Updates :: UpdateShortSentMessage ( u) => Ok ( u. id as i64 ) ,
166+ _ => anyhow:: bail!( "Unexpected Updates type" ) ,
167+ }
168+ }
169+
58170 /// Mark a chat as read.
59171 pub async fn mark_read ( & mut self , chat_id : i64 ) -> Result < ( ) > {
60172 let peer_ref = self . resolve_peer_ref ( chat_id) . await ?;
0 commit comments