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 && let Some(filename) = filename
120 && 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 Ok(())
127}
128
129pub(crate) async fn set_debug_logging_xdc(ctx: &Context, id: Option<MsgId>) -> anyhow::Result<()> {
132 match id {
133 Some(msg_id) => {
134 ctx.sql
135 .set_raw_config(
136 Config::DebugLogging.as_ref(),
137 Some(msg_id.to_string().as_ref()),
138 )
139 .await?;
140 {
141 let debug_logging = &mut *ctx.debug_logging.write().expect("RwLock is poisoned");
142 match debug_logging {
143 Some(debug_logging) => debug_logging.msg_id = msg_id,
145 None => {
147 let (sender, debug_logging_recv) = channel::bounded(1000);
148 let loop_handle = {
149 let ctx = ctx.clone();
150 task::spawn(async move {
151 debug_logging_loop(&ctx, debug_logging_recv).await
152 })
153 };
154 *debug_logging = Some(DebugLogging {
155 msg_id,
156 loop_handle,
157 sender,
158 });
159 }
160 }
161 }
162 info!(ctx, "replacing logging webxdc");
163 }
164 None => {
166 ctx.sql
167 .set_raw_config(Config::DebugLogging.as_ref(), None)
168 .await?;
169 *ctx.debug_logging.write().expect("RwLock is poisoned") = None;
170 info!(ctx, "removing logging webxdc");
171 }
172 }
173 Ok(())
174}