-
-
Notifications
You must be signed in to change notification settings - Fork 129
Location streaming fixes #8351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Location streaming fixes #8351
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -521,10 +521,9 @@ pub(crate) async fn delete_orphaned_poi(context: &Context) -> Result<()> { | |
| Ok(()) | ||
| } | ||
|
|
||
| /// Returns `location.kml` contents. | ||
| #[expect(clippy::arithmetic_side_effects)] | ||
| pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(String, u32)>> { | ||
| let mut last_added_location_id = 0; | ||
| /// Returns `location.kml` contents and the largest location timestamp, if any. | ||
| pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(String, i64)>> { | ||
| let mut last_added_location_timestamp: Option<i64> = None; | ||
|
|
||
| let self_addr = context.get_primary_self_addr().await?; | ||
|
|
||
|
|
@@ -540,7 +539,6 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(Strin | |
| .await?; | ||
|
|
||
| let now = time(); | ||
| let mut location_count = 0; | ||
| let mut ret = String::new(); | ||
| if locations_send_begin != 0 && now <= locations_send_until { | ||
| ret += &format!( | ||
|
|
@@ -551,10 +549,10 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(Strin | |
| context | ||
| .sql | ||
| .query_map( | ||
| "SELECT id, latitude, longitude, accuracy, timestamp \ | ||
| "SELECT latitude, longitude, accuracy, timestamp \ | ||
| FROM locations WHERE from_id=? \ | ||
| AND timestamp>=? \ | ||
| AND (timestamp>=? OR \ | ||
| AND (timestamp>? OR \ | ||
| timestamp=(SELECT MAX(timestamp) FROM locations WHERE from_id=?)) \ | ||
| AND independent=0 \ | ||
| GROUP BY timestamp \ | ||
|
|
@@ -566,25 +564,24 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(Strin | |
| ContactId::SELF | ||
| ), | ||
| |row| { | ||
| let location_id: i32 = row.get(0)?; | ||
| let latitude: f64 = row.get(1)?; | ||
| let longitude: f64 = row.get(2)?; | ||
| let accuracy: f64 = row.get(3)?; | ||
| let timestamp = get_kml_timestamp(row.get(4)?); | ||
| let latitude: f64 = row.get(0)?; | ||
| let longitude: f64 = row.get(1)?; | ||
| let accuracy: f64 = row.get(2)?; | ||
| let timestamp: i64 = row.get(3)?; | ||
|
|
||
| Ok((location_id, latitude, longitude, accuracy, timestamp)) | ||
| Ok((latitude, longitude, accuracy, timestamp)) | ||
| }, | ||
| |rows| { | ||
| for row in rows { | ||
| let (location_id, latitude, longitude, accuracy, timestamp) = row?; | ||
| let (latitude, longitude, accuracy, timestamp) = row?; | ||
| let kml_timestamp = get_kml_timestamp(timestamp); | ||
| ret += &format!( | ||
| "<Placemark>\ | ||
| <Timestamp><when>{timestamp}</when></Timestamp>\ | ||
| <Timestamp><when>{kml_timestamp}</when></Timestamp>\ | ||
| <Point><coordinates accuracy=\"{accuracy}\">{longitude},{latitude}</coordinates></Point>\ | ||
| </Placemark>\n" | ||
| ); | ||
| location_count += 1; | ||
| last_added_location_id = location_id as u32; | ||
| last_added_location_timestamp = std::cmp::max(last_added_location_timestamp, Some(timestamp)); | ||
| } | ||
| Ok(()) | ||
| }, | ||
|
|
@@ -593,11 +590,7 @@ pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<Option<(Strin | |
| ret += "</Document>\n</kml>"; | ||
| } | ||
|
|
||
| if location_count > 0 { | ||
| Ok(Some((ret, last_added_location_id))) | ||
| } else { | ||
| Ok(None) | ||
| } | ||
| Ok(last_added_location_timestamp.map(|ts| (ret, ts))) | ||
| } | ||
|
|
||
| fn get_kml_timestamp(utc: i64) -> String { | ||
|
|
@@ -1160,4 +1153,44 @@ Content-Disposition: attachment; filename="location.kml" | |
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| #[tokio::test(flavor = "multi_thread", worker_threads = 2)] | ||
| async fn test_last_sent_location_timestamp() -> Result<()> { | ||
| let mut tcm = TestContextManager::new(); | ||
| let alice = &tcm.alice().await; | ||
| let bob = &tcm.bob().await; | ||
|
|
||
| let alice_chat = alice.create_chat(bob).await; | ||
|
|
||
| send_to_chat(alice, alice_chat.id, 600).await?; | ||
| bob.recv_msg(&alice.pop_sent_msg().await).await; | ||
|
|
||
| assert_eq!(set(alice, 10.0, 20.0, 1.0).await?, true); | ||
|
|
||
| SystemTime::shift(Duration::from_secs(60)); | ||
|
|
||
| maybe_send(alice).await?; | ||
| bob.recv_msg_opt(&alice.pop_sent_msg().await).await; | ||
|
|
||
| let alice_locations = get_range(alice, None, None, 0, 0).await?; | ||
| assert_eq!(alice_locations.len(), 1); | ||
| assert_eq!(get_range(bob, None, None, 0, 0).await?.len(), 1); | ||
|
|
||
| let last_sent = alice | ||
| .sql | ||
| .query_row( | ||
| "SELECT locations_last_sent FROM chats WHERE id = ?", | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have not found a better way to test this change. The fix avoids missing locations in a corner case of location arriving right after rendering the message and before evaluating |
||
| (alice_chat.id,), | ||
| |row| { | ||
| let last_sent: i64 = row.get(0)?; | ||
|
|
||
| Ok(last_sent) | ||
| }, | ||
| ) | ||
| .await?; | ||
|
|
||
| assert_eq!(alice_locations[0].timestamp, last_sent); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related to this PR, but this takes an arbitrary row if there are rows with the same timestamp, see https://sqlite.org/lang_select.html#generation_of_the_set_of_result_rows:
I think instead of
GROUP BYit should beORDER BY timestamp, id DESC, then we can skip a row (in Rust) iftimestampis the same as in the previous iteration. Otherwise we can even send different locations in different chats or messages sent in a row to the same chat.