Diff
Logged in as anonymous

Differences From Artifact [dfced9c660]:

To Artifact [9de705aadb]:


1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
1
2

3
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31





32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116


-
+



-


















-
+






-
-
-
-
-








-
+





+
















-
+













-
+












-
+




















-
+





use crate::utils::{
	Attachment,
	RE_SPECIAL,
	validate,
};

use std::{
	borrow::Cow,
	collections::HashMap,
	fmt::Debug,
};

use stacked_errors::{
	Result,
	StackableErr,
};
use tgbot::{
	api::Client,
	types::{
		ChatPeerId,
		InputFile,
		InputFileReader,
		InputMediaDocument,
		MediaGroup,
		MediaGroupItem,
		Message,
		ParseMode::MarkdownV2,
		ParseMode::Html,
		SendMediaGroup,
		SendMessage,
		SendDocument,
	},
};

/// Encodes special HTML entities to prevent them interfering with Telegram HTML
pub fn encode (text: &str) -> Cow<'_, str> {
	RE_SPECIAL.replace_all(text, "\\$1")
}

#[derive(Debug)]
pub struct TelegramTransport {
	tg: Client,
	recipients: HashMap<String, ChatPeerId>,
	pub default: ChatPeerId,
}

impl TelegramTransport {

	/// Creates new TelegramTransport object.
	pub fn new (api_key: String, recipients: HashMap<String, i64>, settings: &config::Config) -> Result<TelegramTransport> {
		let default = settings.get_int("default")
			.context("[smtp2tg.toml] missing \"default\" recipient.\n")?;
		let api_gateway = settings.get_string("api_gateway")
			.context("[smtp2tg.toml] missing \"api_gateway\" destination.\n")?;

		let tg = Client::new(api_key)
			.context("Failed to create API.\n")?
			.with_host(api_gateway);
		let recipients = recipients.into_iter()
			.map(|(a, b)| (a, ChatPeerId::from(b))).collect();
		let default = ChatPeerId::from(default);

		Ok(TelegramTransport {
			tg,
			recipients,
			default,
		})
	}

	/// Send message to default user, used for debug/log/info purposes
	pub async fn debug (&self, msg: &str) -> Result<Message> {
		self.send(&self.default, encode(msg)).await
		self.send(&self.default, format!("<pre>{}</pre>", validate(msg).stack()?)).await
	}

	/// Get recipient by address
	pub fn get (&self, name: &str) -> Result<&ChatPeerId> {
		self.recipients.get(name)
			.with_context(|| format!("Recipient \"{name}\" not found in configuration"))
	}

	/// Send message to specified user
	pub async fn send <S> (&self, to: &ChatPeerId, msg: S) -> Result<Message>
	where S: Into<String> + Debug{
		self.tg.execute(
			SendMessage::new(*to, msg)
			.with_parse_mode(MarkdownV2)
			.with_parse_mode(Html)
		).await.stack()
	}

	/// Send media to specified user
	pub async fn sendgroup (&self, to: &ChatPeerId, media: Vec<Attachment>, msg: &str) -> Result<()> {
		if media.len() > 1 {
			let mut attach = vec![];
			let mut pos = media.len();
			for file in media {
				let mut caption = InputMediaDocument::default();
				if pos == 1 {
					caption = caption.with_caption(msg)
						.with_caption_parse_mode(MarkdownV2);
						.with_caption_parse_mode(Html);
				}
				pos -= 1;
				attach.push(
					MediaGroupItem::for_document(
						InputFile::from(
							InputFileReader::from(file.data)
								.with_file_name(file.name)
						),
						caption
					)
				);
			}
			self.tg.execute(SendMediaGroup::new(*to, MediaGroup::new(attach).stack()?)).await.stack()?;
		} else {
			self.tg.execute(
				SendDocument::new(
					*to,
					InputFileReader::from(media[0].data.clone())
					.with_file_name(media[0].name.clone())
				).with_caption(msg)
				.with_caption_parse_mode(MarkdownV2)
				.with_caption_parse_mode(Html)
			).await.stack()?;
		}
		Ok(())
	}
}