Skip to content

Commit 251c2c6

Browse files
committed
Remove some bugs from message statistics
1 parent fa6a693 commit 251c2c6

File tree

8 files changed

+167
-71
lines changed

8 files changed

+167
-71
lines changed

deltachat-jsonrpc/src/api.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@ use std::sync::Arc;
55
use std::time::Duration;
66
use std::{collections::HashMap, str::FromStr};
77

8-
use anyhow::{anyhow, bail, ensure, Context, Result};
8+
use anyhow::{Context, Result, anyhow, bail, ensure};
9+
use deltachat::EventEmitter;
910
pub use deltachat::accounts::Accounts;
1011
use deltachat::blob::BlobObject;
1112
use deltachat::chat::{
12-
self, add_contact_to_chat, forward_msgs, get_chat_media, get_chat_msgs, get_chat_msgs_ex,
13-
marknoticed_chat, remove_contact_from_chat, Chat, ChatId, ChatItem, MessageListOptions,
14-
ProtectionStatus,
13+
self, Chat, ChatId, ChatItem, MessageListOptions, ProtectionStatus, add_contact_to_chat,
14+
forward_msgs, get_chat_media, get_chat_msgs, get_chat_msgs_ex, marknoticed_chat,
15+
remove_contact_from_chat,
1516
};
1617
use deltachat::chatlist::Chatlist;
1718
use deltachat::config::Config;
1819
use deltachat::constants::DC_MSG_ID_DAYMARKER;
19-
use deltachat::contact::{may_be_valid_addr, Contact, ContactId, Origin};
20+
use deltachat::contact::{Contact, ContactId, Origin, may_be_valid_addr};
2021
use deltachat::context::get_info;
2122
use deltachat::ephemeral::Timer;
2223
use deltachat::imex;
2324
use deltachat::location;
2425
use deltachat::message::get_msg_read_receipts;
2526
use deltachat::message::{
26-
self, delete_msgs_ex, markseen_msgs, Message, MessageState, MsgId, Viewtype,
27+
self, Message, MessageState, MsgId, Viewtype, delete_msgs_ex, markseen_msgs,
2728
};
2829
use deltachat::peer_channels::{
2930
leave_webxdc_realtime, send_webxdc_realtime_advertisement, send_webxdc_realtime_data,
@@ -35,10 +36,9 @@ use deltachat::reaction::{get_msg_reactions, send_reaction};
3536
use deltachat::securejoin;
3637
use deltachat::stock_str::StockMessage;
3738
use deltachat::webxdc::StatusUpdateSerial;
38-
use deltachat::EventEmitter;
3939
use sanitize_filename::is_sanitized;
4040
use tokio::fs;
41-
use tokio::sync::{watch, Mutex, RwLock};
41+
use tokio::sync::{Mutex, RwLock, watch};
4242
use types::login_param::EnteredLoginParam;
4343
use walkdir::WalkDir;
4444
use yerpc::rpc;
@@ -64,7 +64,7 @@ use self::types::{
6464
JSONRPCMessageListItem, MessageNotificationInfo, MessageSearchResult, MessageViewtype,
6565
},
6666
};
67-
use crate::api::types::chat_list::{get_chat_list_item_by_id, ChatListItemFetchResult};
67+
use crate::api::types::chat_list::{ChatListItemFetchResult, get_chat_list_item_by_id};
6868
use crate::api::types::qr::QrObject;
6969

7070
#[derive(Debug)]
@@ -2017,7 +2017,7 @@ impl CommandApi {
20172017
let message = Message::load_from_db(&ctx, MsgId::new(instance_msg_id)).await?;
20182018
let blob = message.get_webxdc_blob(&ctx, &path).await?;
20192019

2020-
use base64::{engine::general_purpose, Engine as _};
2020+
use base64::{Engine as _, engine::general_purpose};
20212021
Ok(general_purpose::STANDARD_NO_PAD.encode(blob))
20222022
}
20232023

deltachat-jsonrpc/src/api/types/chat.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::time::{Duration, SystemTime};
22

3-
use anyhow::{bail, Context as _, Result};
4-
use deltachat::chat::{self, get_chat_contacts, get_past_chat_contacts, ChatVisibility};
3+
use anyhow::{Context as _, Result, bail};
4+
use deltachat::chat::{self, ChatVisibility, get_chat_contacts, get_past_chat_contacts};
55
use deltachat::chat::{Chat, ChatId};
66
use deltachat::constants::Chattype;
77
use deltachat::contact::{Contact, ContactId};

deltachat-jsonrpc/src/api/types/chat_list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use deltachat::chatlist::get_last_message_for_chat;
44
use deltachat::constants::*;
55
use deltachat::contact::{Contact, ContactId};
66
use deltachat::{
7-
chat::{get_chat_contacts, ChatVisibility},
7+
chat::{ChatVisibility, get_chat_contacts},
88
chatlist::Chatlist,
99
};
1010
use num_traits::cast::ToPrimitive;

deltachat-jsonrpc/src/api/types/http.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct HttpResponse {
1616

1717
impl From<CoreHttpResponse> for HttpResponse {
1818
fn from(response: CoreHttpResponse) -> Self {
19-
use base64::{engine::general_purpose, Engine as _};
19+
use base64::{Engine as _, engine::general_purpose};
2020
let blob = general_purpose::STANDARD_NO_PAD.encode(response.blob);
2121
let mimetype = response.mimetype;
2222
let encoding = response.encoding;

src/config.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::login_param::ConfiguredLoginParam;
2222
use crate::mimefactory::RECOMMENDED_FILE_SIZE;
2323
use crate::provider::{Provider, get_provider_by_id};
2424
use crate::sync::{self, Sync::*, SyncData};
25-
use crate::tools::{get_abs_path, time};
25+
use crate::tools::get_abs_path;
2626

2727
/// The available configuration keys.
2828
#[derive(
@@ -442,8 +442,11 @@ pub enum Config {
442442
/// without storing the email address
443443
SelfReportingId,
444444

445-
/// Timestamp of enabling SelfReporting.
446-
SelfReportingEnabledTimestamp,
445+
/// The last message id that was already included in the previous report,
446+
/// or that already existed before the user opted in.
447+
/// Only messages with an id larger than this
448+
/// will be counted in the next report.
449+
SelfReportingLastMsgId,
447450

448451
/// MsgId of webxdc map integration.
449452
WebxdcIntegration,
@@ -839,9 +842,7 @@ impl Context {
839842
}
840843
Config::SelfReporting => {
841844
self.sql.set_raw_config(key.as_ref(), value).await?;
842-
self.sql
843-
.set_raw_config_int64(Config::SelfReportingEnabledTimestamp.as_ref(), time())
844-
.await?;
845+
crate::self_reporting::set_last_msgid(self).await?;
845846
}
846847
_ => {
847848
self.sql.set_raw_config(key.as_ref(), value).await?;

src/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,8 +1075,8 @@ impl Context {
10751075
.to_string(),
10761076
);
10771077
res.insert(
1078-
"self_reporting_enabled_timestamp",
1079-
self.get_config_i64(Config::SelfReportingEnabledTimestamp)
1078+
"self_reporting_last_msg_id",
1079+
self.get_config_i64(Config::SelfReportingLastMsgId)
10801080
.await?
10811081
.to_string(),
10821082
);

src/self_reporting.rs

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@ use crate::config::Config;
1212
use crate::constants::{Chattype, DC_CHAT_ID_TRASH};
1313
use crate::contact::{ContactId, Origin, import_vcard, mark_contact_id_as_verified};
1414
use crate::context::{Context, get_version_str};
15-
use crate::download::DownloadState;
1615
use crate::key::load_self_public_key;
1716
use crate::log::LogExt;
1817
use crate::message::{Message, Viewtype};
19-
use crate::param::{Param, Params};
2018
use crate::tools::{create_id, time};
2119

2220
pub(crate) const SELF_REPORTING_BOT_EMAIL: &str = "self_reporting@testrun.org";
@@ -105,8 +103,6 @@ pub async fn maybe_send_self_report(context: &Context) -> Result<Option<ChatId>>
105103
async fn send_self_report(context: &Context) -> Result<ChatId> {
106104
info!(context, "Sending self report.");
107105

108-
let last_selfreport_time = context.get_config_i64(Config::LastSelfReportSent).await?;
109-
110106
// Setting this config at the beginning avoids endless loops when things do not
111107
// work out for whatever reason.
112108
context
@@ -126,7 +122,7 @@ See TODO[blog post] for more information."
126122
.to_string(),
127123
);
128124

129-
let self_report = get_self_report(context, last_selfreport_time).await?;
125+
let self_report = get_self_report(context).await?;
130126

131127
msg.set_file_from_bytes(
132128
context,
@@ -141,10 +137,34 @@ See TODO[blog post] for more information."
141137
.log_err(context)
142138
.ok();
143139

140+
set_last_msgid(context).await?;
141+
144142
Ok(chat_id)
145143
}
146144

147-
async fn get_self_report(context: &Context, last_selfreport_time: i64) -> Result<String> {
145+
pub(crate) async fn set_last_msgid(context: &Context) -> Result<()> {
146+
let last_msgid: u64 = context
147+
.sql
148+
.query_get_value("SELECT MAX(id) FROM msgs", ())
149+
.await?
150+
.context("All messages are gone")?;
151+
152+
context
153+
.sql
154+
.set_raw_config(
155+
Config::SelfReportingLastMsgId.as_ref(),
156+
Some(&last_msgid.to_string()),
157+
)
158+
.await?;
159+
160+
Ok(())
161+
}
162+
163+
async fn get_self_report(context: &Context) -> Result<String> {
164+
let last_msgid = context
165+
.get_config_u64(Config::SelfReportingLastMsgId)
166+
.await?;
167+
148168
let key_created = load_self_public_key(context)
149169
.await?
150170
.primary_key
@@ -161,12 +181,13 @@ async fn get_self_report(context: &Context, last_selfreport_time: i64) -> Result
161181
id
162182
}
163183
};
184+
164185
let statistics = Statistics {
165186
core_version: get_version_str().to_string(),
166187
key_created,
167188
self_reporting_id,
168189
contact_stats: get_contact_stats(context).await?,
169-
message_stats: get_message_stats(context, last_selfreport_time).await?,
190+
message_stats: get_message_stats(context, last_msgid).await?, // TODO
170191
securejoin_source_stats: get_securejoin_source_stats(context).await?,
171192
};
172193

@@ -303,66 +324,89 @@ async fn get_contact_stats(context: &Context) -> Result<Vec<ContactStat>> {
303324
Ok(contacts)
304325
}
305326

306-
async fn get_message_stats(
307-
context: &Context,
308-
mut last_selfreport_time: i64,
309-
) -> Result<MessageStats> {
310-
let enabled_ts: i64 = context
311-
.get_config_i64(Config::SelfReportingEnabledTimestamp)
312-
.await?;
313-
if last_selfreport_time == 0 {
314-
last_selfreport_time = enabled_ts;
315-
}
316-
ensure!(last_selfreport_time > 0, "Enabled Timestamp missing");
327+
async fn get_message_stats(context: &Context, last_msgid: u64) -> Result<MessageStats> {
328+
ensure!(
329+
last_msgid >= 9,
330+
"Last_msgid < 9 would mean including 'special' messages in the report"
331+
);
317332

318333
let selfreporting_bot_chat_id = get_selfreporting_bot(context).await?;
319334

320335
let trans_fn = |t: &mut rusqlite::Transaction| {
321336
t.pragma_update(None, "query_only", "0")?;
337+
338+
// This table will hold all 'protected' chats.
339+
// Protected chats guarantee that all messages in the chat
340+
// are sent with verified encryption
341+
// are marked with a green checkmark in the UI.
322342
t.execute(
323-
"CREATE TEMP TABLE temp.verified_chats (
343+
"CREATE TEMP TABLE temp.protected_chats (
324344
id INTEGER PRIMARY KEY
325345
) STRICT",
326346
(),
327347
)?;
328348

349+
// id>9 because chat ids 0..9 are "special" chats like the trash chat.
329350
t.execute(
330-
"INSERT INTO temp.verified_chats
351+
"INSERT INTO temp.protected_chats
331352
SELECT id FROM chats
332353
WHERE protected=1 AND id>9",
333354
(),
334355
)?;
335356

357+
// In the following SQL statements,
358+
// - we always have the line
359+
// `AND from_id=? AND chat_id<>? AND id>? AND hidden=0 AND chat_id<>?`.
360+
// `from_id=?` is to count only outgoing messages.
361+
// The rest excludes:
362+
// - the chat with the self-reporting bot itself,
363+
// - messages sent with the last report, or before the config was enabled
364+
// - hidden system messages, which are not actually shown to the user
365+
// - messages in the 'Trash' chat, which is an internal chat assigned to messages that are not shown to the user
366+
// - `(param GLOB '*\nc=1*' OR param GLOB 'c=1*')`
367+
// matches all messages that are end-to-end encrypted
336368
let to_verified = t.query_row(
337369
"SELECT COUNT(*) FROM msgs
338-
WHERE chat_id IN temp.verified_chats
339-
AND chat_id<>? AND id>9 AND timestamp>=? AND hidden=0
340-
AND NOT (param GLOB '*\nS=*' OR param GLOB 'S=*')",
341-
(selfreporting_bot_chat_id, last_selfreport_time),
370+
WHERE chat_id IN temp.protected_chats
371+
AND from_id=? AND chat_id<>? AND id>? AND hidden=0 AND chat_id<>?",
372+
(
373+
ContactId::SELF,
374+
selfreporting_bot_chat_id,
375+
last_msgid,
376+
DC_CHAT_ID_TRASH,
377+
),
342378
|row| row.get(0),
343379
)?;
344380

345381
let unverified_encrypted = t.query_row(
346382
"SELECT COUNT(*) FROM msgs
347-
WHERE chat_id not IN temp.verified_chats
383+
WHERE chat_id not IN temp.protected_chats
348384
AND (param GLOB '*\nc=1*' OR param GLOB 'c=1*')
349-
AND chat_id<>? AND id>9 AND timestamp>=? AND hidden=0
350-
AND NOT (param GLOB '*\nS=*' OR param GLOB 'S=*')",
351-
(selfreporting_bot_chat_id, last_selfreport_time),
385+
AND from_id=? AND chat_id<>? AND id>? AND hidden=0 AND chat_id<>?",
386+
(
387+
ContactId::SELF,
388+
selfreporting_bot_chat_id,
389+
last_msgid,
390+
DC_CHAT_ID_TRASH,
391+
),
352392
|row| row.get(0),
353393
)?;
354394

355395
let unencrypted = t.query_row(
356396
"SELECT COUNT(*) FROM msgs
357-
WHERE chat_id not IN temp.verified_chats
397+
WHERE chat_id not IN temp.protected_chats
358398
AND NOT (param GLOB '*\nc=1*' OR param GLOB 'c=1*')
359-
AND chat_id<>? AND id>9 AND timestamp>=? AND hidden=0
360-
AND NOT (param GLOB '*\nS=*' OR param GLOB 'S=*')",
361-
(selfreporting_bot_chat_id, last_selfreport_time),
399+
AND from_id=? AND chat_id<>? AND id>? AND hidden=0 AND chat_id<>?",
400+
(
401+
ContactId::SELF,
402+
selfreporting_bot_chat_id,
403+
last_msgid,
404+
DC_CHAT_ID_TRASH,
405+
),
362406
|row| row.get(0),
363407
)?;
364408

365-
t.execute("DROP TABLE temp.verified_chats", ())?;
409+
t.execute("DROP TABLE temp.protected_chats", ())?;
366410

367411
Ok(MessageStats {
368412
to_verified,

0 commit comments

Comments
 (0)