cloudillo_action/
forward.rs1use crate::prelude::*;
11use cloudillo_core::ws_broadcast::{BroadcastMessage, DeliveryResult};
12use cloudillo_types::meta_adapter::AttachmentView;
13use cloudillo_types::types::TnId;
14use serde_json::json;
15
16#[derive(Debug, Clone)]
18pub struct ForwardResult {
19 pub delivered: bool,
21 pub connection_count: usize,
23 pub user_offline: bool,
25}
26
27#[derive(Debug, Clone)]
29pub struct ForwardActionParams<'a> {
30 pub action_id: &'a str,
31 pub temp_id: Option<&'a str>,
32 pub issuer_tag: &'a str,
33 pub audience_tag: Option<&'a str>,
34 pub action_type: &'a str,
35 pub sub_type: Option<&'a str>,
36 pub content: Option<&'a serde_json::Value>,
37 pub attachments: Option<&'a [AttachmentView]>,
38 pub status: Option<&'a str>,
39}
40
41pub async fn forward_action(
47 app: &App,
48 tn_id: TnId,
49 params: &ForwardActionParams<'_>,
50) -> ForwardResult {
51 if let Some(audience) = params.audience_tag {
53 let action_msg = build_action_message(params);
54 forward_to_user(app, tn_id, audience, action_msg).await
55 } else {
56 ForwardResult { delivered: false, connection_count: 0, user_offline: false }
58 }
59}
60
61pub async fn forward_outbound_action(
66 app: &App,
67 tn_id: TnId,
68 params: &ForwardActionParams<'_>,
69) -> ForwardResult {
70 forward_action(app, tn_id, params).await
71}
72
73pub async fn forward_inbound_action(
78 app: &App,
79 tn_id: TnId,
80 params: &ForwardActionParams<'_>,
81) -> ForwardResult {
82 let action_msg = build_action_message(params);
83 let delivered = app.broadcast.send_to_tenant(tn_id, action_msg).await;
84
85 ForwardResult {
86 delivered: delivered > 0,
87 connection_count: delivered,
88 user_offline: delivered == 0,
89 }
90}
91
92async fn forward_to_user(
94 app: &App,
95 tn_id: TnId,
96 user_id: &str,
97 msg: BroadcastMessage,
98) -> ForwardResult {
99 match app.broadcast.send_to_user(tn_id, user_id, msg).await {
100 DeliveryResult::Delivered(count) => {
101 tracing::debug!(user_id = %user_id, connections = %count, "Action forwarded to user");
102 ForwardResult { delivered: true, connection_count: count, user_offline: false }
103 }
104 DeliveryResult::UserOffline => {
105 tracing::debug!(user_id = %user_id, "User offline - action not forwarded");
106 ForwardResult { delivered: false, connection_count: 0, user_offline: true }
107 }
108 }
109}
110
111fn build_action_message(params: &ForwardActionParams<'_>) -> BroadcastMessage {
113 BroadcastMessage::new(
114 "ACTION",
115 json!({
116 "actionId": params.action_id,
117 "tempId": params.temp_id,
118 "type": params.action_type,
119 "subType": params.sub_type,
120 "issuer": {
121 "idTag": params.issuer_tag
122 },
123 "audience": params.audience_tag.map(|a| json!({"idTag": a})),
124 "content": params.content,
125 "attachments": params.attachments,
126 "status": params.status,
127 }),
128 "system",
129 )
130}
131
132pub fn should_push_notify(action_type: &str, sub_type: Option<&str>) -> bool {
137 if sub_type.map(|s| s == "DEL").unwrap_or(false) {
139 return false;
140 }
141
142 matches!(
143 action_type,
144 "MSG" | "CONN" | "FSHR" | "CMNT" )
149}
150
151pub fn get_push_setting_key(action_type: &str) -> &'static str {
156 match action_type {
157 "MSG" => "notify.push.message",
158 "CONN" => "notify.push.connection",
159 "FSHR" => "notify.push.file_share",
160 "FLLW" => "notify.push.follow",
161 "CMNT" => "notify.push.comment",
162 "REACT" => "notify.push.reaction",
163 "POST" => "notify.push.post",
164 _ => "notify.push", }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_should_push_notify() {
174 assert!(should_push_notify("MSG", None));
176 assert!(should_push_notify("CONN", None));
177 assert!(should_push_notify("FSHR", None));
178 assert!(should_push_notify("CMNT", None));
179
180 assert!(!should_push_notify("POST", None));
182 assert!(!should_push_notify("FLLW", None));
183 assert!(!should_push_notify("REACT", None));
184
185 assert!(!should_push_notify("MSG", Some("DEL")));
187 assert!(!should_push_notify("CONN", Some("DEL")));
188 }
189
190 #[test]
191 fn test_get_push_setting_key() {
192 assert_eq!(get_push_setting_key("MSG"), "notify.push.message");
193 assert_eq!(get_push_setting_key("CONN"), "notify.push.connection");
194 assert_eq!(get_push_setting_key("FSHR"), "notify.push.file_share");
195 assert_eq!(get_push_setting_key("UNKNOWN"), "notify.push");
196 }
197}
198
199