| 760 | /// automatically. |
| 761 | #[expect(clippy::arithmetic_side_effects)] |
| 762 | async fn maybe_send(context: &Context) -> Result<Option<u64>> { |
| 763 | let mut next_event: Option<u64> = None; |
| 764 | |
| 765 | let now = time(); |
| 766 | let rows = context |
| 767 | .sql |
| 768 | .query_map_vec( |
| 769 | "SELECT id, locations_send_begin, locations_send_until, locations_last_sent |
| 770 | FROM chats |
| 771 | WHERE locations_send_until>0", |
| 772 | [], |
| 773 | |row| { |
| 774 | let chat_id: ChatId = row.get(0)?; |
| 775 | let locations_send_begin: i64 = row.get(1)?; |
| 776 | let locations_send_until: i64 = row.get(2)?; |
| 777 | let locations_last_sent: i64 = row.get(3)?; |
| 778 | Ok(( |
| 779 | chat_id, |
| 780 | locations_send_begin, |
| 781 | locations_send_until, |
| 782 | locations_last_sent, |
| 783 | )) |
| 784 | }, |
| 785 | ) |
| 786 | .await |
| 787 | .context("failed to query location streaming chats")?; |
| 788 | |
| 789 | for (chat_id, locations_send_begin, locations_send_until, locations_last_sent) in rows { |
| 790 | if locations_send_begin > 0 && locations_send_until > now { |
| 791 | let can_send = now > locations_last_sent + 60; |
| 792 | let has_locations = context |
| 793 | .sql |
| 794 | .exists( |
| 795 | "SELECT COUNT(id) \ |
| 796 | FROM locations \ |
| 797 | WHERE from_id=? \ |
| 798 | AND timestamp>=? \ |
| 799 | AND timestamp>? \ |
| 800 | AND independent=0", |
| 801 | (ContactId::SELF, locations_send_begin, locations_last_sent), |
| 802 | ) |
| 803 | .await?; |
| 804 | |
| 805 | next_event = next_event |
| 806 | .into_iter() |
| 807 | .chain(u64::try_from(locations_send_until - now)) |
| 808 | .min(); |
| 809 | |
| 810 | if has_locations { |
| 811 | if can_send { |
| 812 | // Send location-only message. |
| 813 | // Pending locations are attached automatically to every message, |
| 814 | // so also to this empty text message. |
| 815 | info!( |
| 816 | context, |
| 817 | "Chat {} has pending locations, sending them.", chat_id |
| 818 | ); |
| 819 | let mut msg = Message::new(Viewtype::Text); |