cortexfs_channels/platform/
slack.rs1use serde_json::json;
2
3use super::{ChannelCodec, OutboundRequest, object, participant, string, text};
4use crate::{
5 ChannelError, ChannelId, ConversationId, InboundMessage, MessageTarget, OutboundMessage,
6};
7
8#[derive(Clone, Copy, Debug, Default)]
10pub struct SlackCodec;
11
12impl ChannelCodec for SlackCodec {
13 fn channel(&self) -> ChannelId {
14 ChannelId::from_static("slack")
15 }
16
17 fn challenge(&self, payload: &str) -> Option<String> {
18 let root = serde_json::from_str::<serde_json::Value>(payload).ok()?;
19 (root.get("type").and_then(serde_json::Value::as_str) == Some("url_verification"))
20 .then(|| root.get("challenge").and_then(serde_json::Value::as_str))
21 .flatten()
22 .map(str::to_owned)
23 }
24
25 fn decode(&self, payload: &str) -> Result<Option<InboundMessage>, ChannelError> {
26 let root = object(payload)?;
27 let event = root.get("event").unwrap_or(&root);
28 if event.get("type").and_then(serde_json::Value::as_str) != Some("message")
29 || event.get("subtype").is_some()
30 || event.get("bot_id").is_some()
31 {
32 return Ok(None);
33 }
34 let id = string(event.get("ts"), "event.ts")?;
35 let conversation = ConversationId::new(string(event.get("channel"), "event.channel")?)?;
36 let sender_id = string(event.get("user"), "event.user")?;
37 Ok(Some(InboundMessage {
38 id,
39 target: MessageTarget {
40 channel: self.channel(),
41 conversation,
42 thread: event
43 .get("thread_ts")
44 .map(|value| string(Some(value), "event.thread_ts"))
45 .transpose()?,
46 reply_to: None,
47 },
48 sender: participant(None, sender_id),
49 body: text(event.get("text"))?,
50 timestamp_ms: None,
51 metadata: std::collections::BTreeMap::new(),
52 }))
53 }
54
55 fn encode(&self, message: &OutboundMessage) -> Result<OutboundRequest, ChannelError> {
56 message.body.validate()?;
57 if !message.body.attachments.is_empty() {
58 return Err(ChannelError::Unsupported(
59 "slack media attachments".to_owned(),
60 ));
61 }
62 let mut fields = serde_json::Map::new();
63 fields.insert(
64 "channel".to_owned(),
65 json!(message.target.conversation.as_str()),
66 );
67 fields.insert("text".to_owned(), json!(message.body.text));
68 if let Some(thread) = message.target.thread.as_deref() {
69 fields.insert("thread_ts".to_owned(), json!(thread));
70 }
71 Ok(OutboundRequest {
72 method: "POST".to_owned(),
73 path: "chat.postMessage".to_owned(),
74 content_type: "application/json".to_owned(),
75 body: serde_json::Value::Object(fields).to_string(),
76 headers: std::collections::BTreeMap::new(),
77 })
78 }
79}