Lines of
src/tg_bot.rs
from check-in 13265e7697
that are changed by the sequence of edits moving toward
check-in 9adc69d514:
1: use serde::{
2: Deserialize,
3: Serialize,
4: };
5: use stacked_errors::{
6: Result,
7: StackableErr,
8: };
9: use tgbot::{
10: api::Client,
11: types::{
12: Bot,
13: ChatPeerId,
14: GetBot,
15: InlineKeyboardButton,
16: InlineKeyboardMarkup,
17: Message,
18: ParseMode,
19: SendMessage,
20: },
21: };
22:
13265e7697 2026-01-10 23: #[derive(Serialize, Deserialize, Debug)]
13265e7697 2026-01-10 24: enum Callback {
13265e7697 2026-01-10 25: // List all feeds (version, name to show)
13265e7697 2026-01-10 26: List(u8, String),
13265e7697 2026-01-10 27: }
13265e7697 2026-01-10 28:
13265e7697 2026-01-10 29: fn get_kb (cb: &Callback) -> Result<InlineKeyboardMarkup> {
13265e7697 2026-01-10 30: let mark = InlineKeyboardMarkup::from(vec![vec![
13265e7697 2026-01-10 31: InlineKeyboardButton::for_callback_data("1",
13265e7697 2026-01-10 32: toml::to_string(&Callback::List(0,"xxx".to_owned())).stack()?),
13265e7697 2026-01-10 33: ]]);
13265e7697 2026-01-10 34: Ok(mark)
35: }
36:
37: #[derive(Clone)]
38: pub struct Tg {
39: pub me: Bot,
40: pub owner: ChatPeerId,
41: pub client: Client,
42: }
43:
44: impl Tg {
45: /// Construct a new `Tg` instance from configuration.
46: ///
47: /// The `settings` must provide the following keys:
48: /// - `"api_key"` (string),
49: /// - `"owner"` (integer chat id),
50: /// - `"api_gateway"` (string).
51: ///
52: /// The function initialises the client, configures the gateway and fetches the bot identity
53: /// before returning the constructed `Tg`.
54: pub async fn new (settings: &config::Config) -> Result<Tg> {
55: let api_key = settings.get_string("api_key").stack()?;
56:
57: let owner = ChatPeerId::from(settings.get_int("owner").stack()?);
58: let client = Client::new(&api_key).stack()?
59: .with_host(settings.get_string("api_gateway").stack()?)
60: .with_max_retries(0);
61: let me = client.execute(GetBot).await.stack()?;
62: Ok(Tg {
63: me,
64: owner,
65: client,
66: })
67: }
68:
69: /// Send a text message to a chat, using an optional target and parse mode.
70: ///
71: /// # Returns
72: /// The sent `Message` on success.
13265e7697 2026-01-10 73: pub async fn send <S>(&self, msg: S, target: Option<ChatPeerId>, mode: Option<ParseMode>) -> Result<Message>
13265e7697 2026-01-10 74: where S: Into<String> {
13265e7697 2026-01-10 75: let msg = msg.into();
13265e7697 2026-01-10 76:
13265e7697 2026-01-10 77: let mode = mode.unwrap_or(ParseMode::Html);
13265e7697 2026-01-10 78: let target = target.unwrap_or(self.owner);
13265e7697 2026-01-10 79: self.client.execute(
13265e7697 2026-01-10 80: SendMessage::new(target, msg)
13265e7697 2026-01-10 81: .with_parse_mode(mode)
13265e7697 2026-01-10 82: ).await.stack()
83: }
84:
85: /// Create a copy of this `Tg` with the owner replaced by the given chat ID.
86: ///
87: /// # Parameters
88: /// - `owner`: The Telegram chat identifier to set as the new owner (expressed as an `i64`).
89: ///
90: /// # Returns
91: /// A new `Tg` instance identical to the original except its `owner` field is set to the provided chat ID.
92: pub fn with_owner <O>(&self, owner: O) -> Tg
93: where O: Into<i64> {
94: Tg {
95: owner: ChatPeerId::from(owner.into()),
96: ..self.clone()
97: }
98: }
99: }