mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 10:56:29 +03:00
blocking for with_conn
This commit is contained in:
@@ -1225,11 +1225,11 @@ pub(crate) async fn create_or_lookup_by_contact_id(
|
||||
}
|
||||
|
||||
let contact = Contact::load_from_db(context, contact_id).await?;
|
||||
let chat_name = contact.get_display_name();
|
||||
let chat_name = contact.get_display_name().to_string();
|
||||
|
||||
context
|
||||
.sql
|
||||
.with_conn(|mut conn| {
|
||||
.with_conn(move |mut conn| {
|
||||
let conn2 = &mut conn;
|
||||
let tx = conn2.transaction()?;
|
||||
tx.execute(
|
||||
|
||||
@@ -586,13 +586,32 @@ async fn add_parts(
|
||||
// (eg. one per attachment))
|
||||
let icnt = mime_parser.parts.len();
|
||||
|
||||
context
|
||||
.sql
|
||||
.with_conn(|mut conn| {
|
||||
let subject = mime_parser.get_subject().unwrap_or_default();
|
||||
let mut txt_raw = None;
|
||||
let subject = mime_parser.get_subject().unwrap_or_default();
|
||||
|
||||
let mut parts = std::mem::replace(&mut mime_parser.parts, Vec::new());
|
||||
let server_folder = server_folder.as_ref().to_string();
|
||||
let location_kml_is = mime_parser.location_kml.is_some();
|
||||
let is_system_message = mime_parser.is_system_message;
|
||||
let mime_headers = if save_mime_headers {
|
||||
Some(String::from_utf8_lossy(imf_raw).to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let sent_timestamp = *sent_timestamp;
|
||||
let is_hidden = *hidden;
|
||||
let chat_id = *chat_id;
|
||||
|
||||
// TODO: can this clone be avoided?
|
||||
let rfc724_mid = rfc724_mid.to_string();
|
||||
|
||||
let (new_parts, ids, is_hidden) = context
|
||||
.sql
|
||||
.with_conn(move |mut conn| {
|
||||
let mut ids = Vec::with_capacity(parts.len());
|
||||
for part in &mut parts {
|
||||
let mut txt_raw = "".to_string();
|
||||
let mut is_hidden = is_hidden;
|
||||
|
||||
for part in mime_parser.parts.iter_mut() {
|
||||
let mut stmt = conn.prepare_cached(
|
||||
"INSERT INTO msgs \
|
||||
(rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \
|
||||
@@ -601,11 +620,9 @@ async fn add_parts(
|
||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
|
||||
)?;
|
||||
|
||||
if mime_parser.location_kml.is_some()
|
||||
&& icnt == 1
|
||||
&& (part.msg == "-location-" || part.msg.is_empty())
|
||||
if location_kml_is && icnt == 1 && (part.msg == "-location-" || part.msg.is_empty())
|
||||
{
|
||||
*hidden = true;
|
||||
is_hidden = true;
|
||||
if state == MessageState::InFresh {
|
||||
state = MessageState::InNoticed;
|
||||
}
|
||||
@@ -613,57 +630,59 @@ async fn add_parts(
|
||||
|
||||
if part.typ == Viewtype::Text {
|
||||
let msg_raw = part.msg_raw.as_ref().cloned().unwrap_or_default();
|
||||
txt_raw = Some(format!("{}\n\n{}", subject, msg_raw));
|
||||
txt_raw = format!("{}\n\n{}", subject, msg_raw);
|
||||
}
|
||||
if mime_parser.is_system_message != SystemMessage::Unknown {
|
||||
part.param
|
||||
.set_int(Param::Cmd, mime_parser.is_system_message as i32);
|
||||
if is_system_message != SystemMessage::Unknown {
|
||||
part.param.set_int(Param::Cmd, is_system_message as i32);
|
||||
}
|
||||
|
||||
stmt.execute(paramsv![
|
||||
rfc724_mid,
|
||||
server_folder.as_ref().to_string(),
|
||||
server_folder,
|
||||
server_uid as i32,
|
||||
*chat_id,
|
||||
chat_id,
|
||||
from_id as i32,
|
||||
to_id as i32,
|
||||
sort_timestamp,
|
||||
*sent_timestamp,
|
||||
sent_timestamp,
|
||||
rcvd_timestamp,
|
||||
part.typ,
|
||||
state,
|
||||
msgrmsg,
|
||||
part.msg,
|
||||
// txt_raw might contain invalid utf8
|
||||
txt_raw.unwrap_or_default(),
|
||||
txt_raw,
|
||||
part.param.to_string(),
|
||||
part.bytes as isize,
|
||||
*hidden,
|
||||
if save_mime_headers {
|
||||
Some(String::from_utf8_lossy(imf_raw))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
is_hidden,
|
||||
mime_headers,
|
||||
mime_in_reply_to,
|
||||
mime_references,
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
|
||||
// This is okay, as we use a cached prepared statement.
|
||||
drop(stmt);
|
||||
let row_id =
|
||||
crate::sql::get_rowid(context, &mut conn, "msgs", "rfc724_mid", &rfc724_mid)?;
|
||||
*insert_msg_id = MsgId::new(row_id);
|
||||
created_db_entries.push((*chat_id, *insert_msg_id));
|
||||
ids.push(MsgId::new(crate::sql::get_rowid(
|
||||
&mut conn,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
&rfc724_mid,
|
||||
)?));
|
||||
}
|
||||
Ok(())
|
||||
Ok((parts, ids, is_hidden))
|
||||
})
|
||||
.await?;
|
||||
|
||||
if let Some(id) = ids.iter().last() {
|
||||
*insert_msg_id = *id;
|
||||
}
|
||||
|
||||
*hidden = is_hidden;
|
||||
created_db_entries.extend(ids.iter().map(|id| (chat_id, *id)));
|
||||
mime_parser.parts = new_parts;
|
||||
|
||||
info!(
|
||||
context,
|
||||
"Message has {} parts and is assigned to chat #{}.", icnt, *chat_id,
|
||||
"Message has {} parts and is assigned to chat #{}.", icnt, chat_id,
|
||||
);
|
||||
|
||||
// check event to send
|
||||
|
||||
@@ -521,13 +521,15 @@ pub async fn save(
|
||||
) -> Result<u32, Error> {
|
||||
ensure!(!chat_id.is_special(), "Invalid chat id");
|
||||
|
||||
let newest_location_id = context
|
||||
.sql
|
||||
.with_conn(|mut conn| {
|
||||
let mut newest_timestamp = 0;
|
||||
let mut newest_location_id = 0;
|
||||
let mut newest_timestamp = 0;
|
||||
let mut newest_location_id = 0;
|
||||
|
||||
for location in locations {
|
||||
for location in locations {
|
||||
// TODO: can this clone be avoided?
|
||||
let location = location.clone();
|
||||
context
|
||||
.sql
|
||||
.with_conn(move |mut conn| {
|
||||
let mut stmt_test = conn
|
||||
.prepare_cached("SELECT id FROM locations WHERE timestamp=? AND from_id=?")?;
|
||||
let mut stmt_insert = conn.prepare_cached(
|
||||
@@ -555,7 +557,6 @@ pub async fn save(
|
||||
drop(stmt_insert);
|
||||
newest_timestamp = location.timestamp;
|
||||
newest_location_id = crate::sql::get_rowid2(
|
||||
context,
|
||||
&mut conn,
|
||||
"locations",
|
||||
"timestamp",
|
||||
@@ -565,10 +566,11 @@ pub async fn save(
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(newest_location_id)
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(newest_location_id)
|
||||
}
|
||||
|
||||
@@ -580,7 +582,7 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
|
||||
" ----------------- MAYBE_SEND_LOCATIONS -------------- ",
|
||||
);
|
||||
|
||||
if let Ok(ref rows) = context
|
||||
let rows = context
|
||||
.sql
|
||||
.query_map(
|
||||
"SELECT id, locations_send_begin, locations_last_sent \
|
||||
@@ -606,11 +608,14 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
|
||||
.map_err(Into::into)
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
.await;
|
||||
|
||||
if rows.is_ok() {
|
||||
let msgs = context
|
||||
.sql
|
||||
.with_conn(|conn| {
|
||||
.with_conn(move |conn| {
|
||||
let rows = rows.unwrap();
|
||||
|
||||
let mut stmt_locations = conn.prepare_cached(
|
||||
"SELECT id \
|
||||
FROM locations \
|
||||
@@ -621,37 +626,34 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
|
||||
ORDER BY timestamp;",
|
||||
)?;
|
||||
|
||||
let msgs = rows
|
||||
.iter()
|
||||
.filter_map(|(chat_id, locations_send_begin, locations_last_sent)| {
|
||||
if !stmt_locations
|
||||
.exists(paramsv![
|
||||
DC_CONTACT_ID_SELF,
|
||||
*locations_send_begin,
|
||||
*locations_last_sent,
|
||||
])
|
||||
.unwrap_or_default()
|
||||
{
|
||||
// if there is no new location, there's nothing to send.
|
||||
// however, maybe we want to bypass this test eg. 15 minutes
|
||||
None
|
||||
} else {
|
||||
// pending locations are attached automatically to every message,
|
||||
// so also to this empty text message.
|
||||
// DC_CMD_LOCATION is only needed to create a nicer subject.
|
||||
//
|
||||
// for optimisation and to avoid flooding the sending queue,
|
||||
// we could sending these messages only if we're really online.
|
||||
// the easiest way to determine this, is to check for an empty message queue.
|
||||
// (might not be 100%, however, as positions are sent combined later
|
||||
// and dc_set_location() is typically called periodically, this is ok)
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.hidden = true;
|
||||
msg.param.set_cmd(SystemMessage::LocationOnly);
|
||||
Some((chat_id, msg))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut msgs = Vec::new();
|
||||
for (chat_id, locations_send_begin, locations_last_sent) in &rows {
|
||||
if !stmt_locations
|
||||
.exists(paramsv![
|
||||
DC_CONTACT_ID_SELF,
|
||||
*locations_send_begin,
|
||||
*locations_last_sent,
|
||||
])
|
||||
.unwrap_or_default()
|
||||
{
|
||||
// if there is no new location, there's nothing to send.
|
||||
// however, maybe we want to bypass this test eg. 15 minutes
|
||||
} else {
|
||||
// pending locations are attached automatically to every message,
|
||||
// so also to this empty text message.
|
||||
// DC_CMD_LOCATION is only needed to create a nicer subject.
|
||||
//
|
||||
// for optimisation and to avoid flooding the sending queue,
|
||||
// we could sending these messages only if we're really online.
|
||||
// the easiest way to determine this, is to check for an empty message queue.
|
||||
// (might not be 100%, however, as positions are sent combined later
|
||||
// and dc_set_location() is typically called periodically, this is ok)
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.hidden = true;
|
||||
msg.param.set_cmd(SystemMessage::LocationOnly);
|
||||
msgs.push((*chat_id, msg));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(msgs)
|
||||
})
|
||||
@@ -660,11 +662,12 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
|
||||
|
||||
for (chat_id, mut msg) in msgs.into_iter() {
|
||||
// TODO: better error handling
|
||||
chat::send_msg(context, *chat_id, &mut msg)
|
||||
chat::send_msg(context, chat_id, &mut msg)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
if continue_streaming {
|
||||
schedule_maybe_send_locations(context, true).await;
|
||||
}
|
||||
|
||||
@@ -1026,14 +1026,14 @@ async fn delete_poi_location(context: &Context, location_id: u32) -> bool {
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
pub async fn markseen_msgs(context: &Context, msg_ids: &[MsgId]) -> bool {
|
||||
pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> bool {
|
||||
if msg_ids.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let msgs = context
|
||||
.sql
|
||||
.with_conn(|conn| {
|
||||
.with_conn(move |conn| {
|
||||
let mut stmt = conn.prepare_cached(concat!(
|
||||
"SELECT",
|
||||
" m.state AS state,",
|
||||
@@ -1043,8 +1043,8 @@ pub async fn markseen_msgs(context: &Context, msg_ids: &[MsgId]) -> bool {
|
||||
))?;
|
||||
|
||||
let mut msgs = Vec::with_capacity(msg_ids.len());
|
||||
for id in msg_ids.iter() {
|
||||
let query_res = stmt.query_row(paramsv![*id], |row| {
|
||||
for id in msg_ids.into_iter() {
|
||||
let query_res = stmt.query_row(paramsv![id], |row| {
|
||||
Ok((
|
||||
row.get::<_, MessageState>("state")?,
|
||||
row.get::<_, Option<Blocked>>("blocked")?
|
||||
@@ -1070,7 +1070,7 @@ pub async fn markseen_msgs(context: &Context, msg_ids: &[MsgId]) -> bool {
|
||||
for (id, curr_state, curr_blocked) in msgs.into_iter() {
|
||||
if curr_blocked == Blocked::Not {
|
||||
if curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed {
|
||||
update_msg_state(context, *id, MessageState::InSeen).await;
|
||||
update_msg_state(context, id, MessageState::InSeen).await;
|
||||
info!(context, "Seen message {}.", id);
|
||||
|
||||
job::add(
|
||||
@@ -1084,7 +1084,7 @@ pub async fn markseen_msgs(context: &Context, msg_ids: &[MsgId]) -> bool {
|
||||
send_event = true;
|
||||
}
|
||||
} else if curr_state == MessageState::InFresh {
|
||||
update_msg_state(context, *id, MessageState::InNoticed).await;
|
||||
update_msg_state(context, id, MessageState::InNoticed).await;
|
||||
send_event = true;
|
||||
}
|
||||
}
|
||||
@@ -1110,16 +1110,16 @@ pub async fn update_msg_state(context: &Context, msg_id: MsgId, state: MessageSt
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
pub async fn star_msgs(context: &Context, msg_ids: &[MsgId], star: bool) -> bool {
|
||||
pub async fn star_msgs(context: &Context, msg_ids: Vec<MsgId>, star: bool) -> bool {
|
||||
if msg_ids.is_empty() {
|
||||
return false;
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.with_conn(|conn| {
|
||||
.with_conn(move |conn| {
|
||||
let mut stmt = conn.prepare("UPDATE msgs SET starred=? WHERE id=?;")?;
|
||||
for msg_id in msg_ids.iter() {
|
||||
stmt.execute(paramsv![star as i32, *msg_id])?;
|
||||
for msg_id in msg_ids.into_iter() {
|
||||
stmt.execute(paramsv![star as i32, msg_id])?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
||||
32
src/sql.rs
32
src/sql.rs
@@ -162,19 +162,20 @@ impl Sql {
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub async fn with_conn<G, H>(&self, mut g: G) -> Result<H>
|
||||
pub async fn with_conn<G, H>(&self, g: G) -> Result<H>
|
||||
where
|
||||
G: FnMut(r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>) -> Result<H>,
|
||||
H: Send + 'static,
|
||||
G: Send
|
||||
+ 'static
|
||||
+ FnOnce(r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>) -> Result<H>,
|
||||
{
|
||||
let lock = self.pool.read().await;
|
||||
let pool = lock.as_ref().ok_or_else(|| Error::SqlNoConnection)?;
|
||||
let conn = pool.get()?;
|
||||
|
||||
let res = async_std::task::spawn_blocking(move || g(conn)).await;
|
||||
self.in_use.remove();
|
||||
|
||||
let res = {
|
||||
let conn = pool.get()?;
|
||||
let res = g(conn);
|
||||
self.in_use.remove();
|
||||
res
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
@@ -234,9 +235,10 @@ impl Sql {
|
||||
|
||||
pub async fn table_exists(&self, name: impl AsRef<str>) -> Result<bool> {
|
||||
self.start_stmt("table_exists");
|
||||
self.with_conn(|conn| {
|
||||
let name = name.as_ref().to_string();
|
||||
self.with_conn(move |conn| {
|
||||
let mut exists = false;
|
||||
conn.pragma(None, "table_info", &name.as_ref().to_string(), |_row| {
|
||||
conn.pragma(None, "table_info", &name, |_row| {
|
||||
// will only be executed if the info was found
|
||||
exists = true;
|
||||
Ok(())
|
||||
@@ -422,7 +424,7 @@ impl Sql {
|
||||
/// eg. if a Message-ID is split into different messages.
|
||||
pub async fn get_rowid(
|
||||
&self,
|
||||
context: &Context,
|
||||
_context: &Context,
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
value: impl AsRef<str>,
|
||||
@@ -431,7 +433,7 @@ impl Sql {
|
||||
|
||||
let res = {
|
||||
let mut conn = self.get_conn().await?;
|
||||
let res = get_rowid(context, &mut conn, table, field, value);
|
||||
let res = get_rowid(&mut conn, table, field, value);
|
||||
self.in_use.remove();
|
||||
res
|
||||
};
|
||||
@@ -441,7 +443,7 @@ impl Sql {
|
||||
|
||||
pub async fn get_rowid2(
|
||||
&self,
|
||||
context: &Context,
|
||||
_context: &Context,
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
value: i64,
|
||||
@@ -452,7 +454,7 @@ impl Sql {
|
||||
|
||||
let res = {
|
||||
let mut conn = self.get_conn().await?;
|
||||
let res = get_rowid2(context, &mut conn, table, field, value, field2, value2);
|
||||
let res = get_rowid2(&mut conn, table, field, value, field2, value2);
|
||||
self.in_use.remove();
|
||||
res
|
||||
};
|
||||
@@ -462,7 +464,6 @@ impl Sql {
|
||||
}
|
||||
|
||||
pub fn get_rowid(
|
||||
_context: &Context,
|
||||
conn: &mut Connection,
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
@@ -481,7 +482,6 @@ pub fn get_rowid(
|
||||
}
|
||||
|
||||
pub fn get_rowid2(
|
||||
_context: &Context,
|
||||
conn: &mut Connection,
|
||||
table: impl AsRef<str>,
|
||||
field: impl AsRef<str>,
|
||||
|
||||
Reference in New Issue
Block a user