deltachat/
debug_logging.rs1use crate::chat::ChatId;
3use crate::config::Config;
4use crate::context::Context;
5use crate::events::EventType;
6use crate::message::{Message, MsgId, Viewtype};
7use crate::param::Param;
8use crate::tools::time;
9use crate::webxdc::StatusUpdateItem;
10use async_channel::{self as channel, Receiver, Sender};
11use serde_json::json;
12use tokio::task;
13
14#[derive(Debug)]
15pub(crate) struct DebugLogging {
16 pub(crate) msg_id: MsgId,
18 pub(crate) loop_handle: task::JoinHandle<()>,
20 pub(crate) sender: Sender<DebugEventLogData>,
23}
24
25impl DebugLogging {
26 pub(crate) fn log_event(&self, event: EventType) {
27 let event_data = DebugEventLogData {
28 time: time(),
29 msg_id: self.msg_id,
30 event,
31 };
32
33 self.sender.try_send(event_data).ok();
34 }
35}
36
37pub struct DebugEventLogData {
39 pub time: i64,
40 pub msg_id: MsgId,
41 pub event: EventType,
42}
43
44pub async fn debug_logging_loop(context: &Context, events: Receiver<DebugEventLogData>) {
47 while let Ok(DebugEventLogData {
48 time,
49 msg_id,
50 event,
51 }) = events.recv().await
52 {
53 match context
54 .write_status_update_inner(
55 &msg_id,
56 &StatusUpdateItem {
57 payload: json!({
58 "event": event,
59 "time": time,
60 }),
61 info: None,
62 href: None,
63 summary: None,
64 document: None,
65 uid: None,
66 notify: None,
67 },
68 time,
69 )
70 .await
71 {
72 Err(err) => {
73 eprintln!("Can't log event to webxdc status update: {err:#}");
74 }
75 Ok(serial) => {
76 if let Some(serial) = serial {
77 if !matches!(event, EventType::WebxdcStatusUpdate { .. }) {
78 context.emit_event(EventType::WebxdcStatusUpdate {
79 msg_id,
80 status_update_serial: serial,
81 });
82 }
83 } else {
84 error!(context, "Debug logging update is not created.");
86 };
87 }
88 }
89 }
90}
91
92pub async fn maybe_set_logging_xdc(
94 context: &Context,
95 msg: &Message,
96 chat_id: ChatId,
97) -> anyhow::Result<()> {
98 maybe_set_logging_xdc_inner(
99 context,
100 msg.get_viewtype(),
101 chat_id,
102 msg.param.get(Param::Filename),
103 msg.get_id(),
104 )
105 .await?;
106
107 Ok(())
108}
109
110pub async fn maybe_set_logging_xdc_inner(
112 context: &Context,
113 viewtype: Viewtype,
114 chat_id: ChatId,
115 filename: Option<&str>,
116 msg_id: MsgId,
117) -> anyhow::Result<()> {
118 if viewtype == Viewtype::Webxdc {
119 if let Some(filename) = filename {
120 if filename.starts_with("debug_logging")
121 && filename.ends_with(".xdc")
122 && chat_id.is_self_talk(context).await?
123 {
124 set_debug_logging_xdc(context, Some(msg_id)).await?;
125 }
126 }
127 }
128 Ok(())
129}
130
131pub(crate) async fn set_debug_logging_xdc(ctx: &Context, id: Option<MsgId>) -> anyhow::Result<()> {
134 match id {
135 Some(msg_id) => {
136 ctx.sql
137 .set_raw_config(
138 Config::DebugLogging.as_ref(),
139 Some(msg_id.to_string().as_ref()),
140 )
141 .await?;
142 {
143 let debug_logging = &mut *ctx.debug_logging.write().expect("RwLock is poisoned");
144 match debug_logging {
145 Some(debug_logging) => debug_logging.msg_id = msg_id,
147 None => {
149 let (sender, debug_logging_recv) = channel::bounded(1000);
150 let loop_handle = {
151 let ctx = ctx.clone();
152 task::spawn(async move {
153 debug_logging_loop(&ctx, debug_logging_recv).await
154 })
155 };
156 *debug_logging = Some(DebugLogging {
157 msg_id,
158 loop_handle,
159 sender,
160 });
161 }
162 }
163 }
164 info!(ctx, "replacing logging webxdc");
165 }
166 None => {
168 ctx.sql
169 .set_raw_config(Config::DebugLogging.as_ref(), None)
170 .await?;
171 *ctx.debug_logging.write().expect("RwLock is poisoned") = None;
172 info!(ctx, "removing logging webxdc");
173 }
174 }
175 Ok(())
176}