diff --git a/Cargo.lock b/Cargo.lock index 0747c7df..ed07f06e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3680,7 +3680,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.13.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "assign", "js_int", @@ -3699,7 +3699,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.13.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "js_int", "ruma-common", @@ -3711,7 +3711,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.21.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "as_variant", "assign", @@ -3736,7 +3736,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.16.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "as_variant", "base64", @@ -3770,7 +3770,7 @@ dependencies = [ [[package]] name = "ruma-events" version = "0.31.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "as_variant", "indexmap", @@ -3797,7 +3797,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.12.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "bytes", "headers", @@ -3820,7 +3820,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.11.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "js_int", "thiserror 2.0.18", @@ -3829,7 +3829,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.16.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "cfg-if", "proc-macro-crate", @@ -3844,7 +3844,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.12.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "js_int", "ruma-common", @@ -3856,7 +3856,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.18.0" -source = "git+https://github.com/matrix-construct/ruma?rev=ff66bdd9975152f0382d753120dddddf3577ad51#ff66bdd9975152f0382d753120dddddf3577ad51" +source = "git+https://github.com/matrix-construct/ruma?rev=54f56d7df454f7b4036386ff2ade6e11ab8af7de#54f56d7df454f7b4036386ff2ade6e11ab8af7de" dependencies = [ "base64", "ed25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 108adb14..73b041bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -327,7 +327,7 @@ default-features = false [workspace.dependencies.ruma] git = "https://github.com/matrix-construct/ruma" -rev = "ff66bdd9975152f0382d753120dddddf3577ad51" +rev = "54f56d7df454f7b4036386ff2ade6e11ab8af7de" features = [ "__compat", "appservice-api-c", diff --git a/src/admin/user/commands.rs b/src/admin/user/commands.rs index 7d13b2c7..3f961d60 100644 --- a/src/admin/user/commands.rs +++ b/src/admin/user/commands.rs @@ -1,6 +1,6 @@ -use std::collections::BTreeMap; +use std::{cmp, collections::BTreeMap}; -use futures::{FutureExt, StreamExt}; +use futures::{FutureExt, StreamExt, TryStreamExt}; use ruma::{ Int, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, UserId, events::{ @@ -11,11 +11,12 @@ use ruma::{ }, tag::{TagEvent, TagEventContent, TagInfo}, }, + uint, }; use tuwunel_core::{ Err, Result, debug_warn, info, matrix::{Event, pdu::PduBuilder}, - utils::{self, ReadyExt}, + utils::{self, ReadyExt, stream::IterStream}, }; use tuwunel_service::{Services, users::Register}; @@ -885,3 +886,39 @@ pub(super) async fn redact_event(&self, event_id: OwnedEventId) -> Result { )) .await } + +#[admin_command] +pub(super) async fn last_active(&self, limit: Option) -> Result { + self.services + .users + .list_local_users() + .map(ToOwned::to_owned) + .then(async |user_id| { + self.services + .users + .all_devices_metadata(&user_id) + .ready_filter_map(|device| device.last_seen_ts) + .ready_fold_default(cmp::max) + .map(|last_seen_ts| (last_seen_ts, user_id.clone())) + .await + }) + .ready_filter(|(ts, _)| ts.get() > uint!(0)) + .collect::>() + .map(|mut vec| { + vec.sort_by(|a, b| b.0.cmp(&a.0)); + vec + }) + .map(Vec::into_iter) + .map(IterStream::try_stream) + .flatten_stream() + .take(limit.unwrap_or(48)) + .try_for_each(async |(last_seen_ts, user_id)| { + let ago = last_seen_ts; + let user_id = user_id.localpart(); + let line = format!("{ago:?} {user_id}\n"); + + self.write_str(&line).await + }) + .boxed() + .await +} diff --git a/src/admin/user/mod.rs b/src/admin/user/mod.rs index fcbc8cd8..45b315a9 100644 --- a/src/admin/user/mod.rs +++ b/src/admin/user/mod.rs @@ -65,6 +65,12 @@ pub(super) enum UserCommand { device_id: OwnedDeviceId, }, + /// - List local users by recent activity. + LastActive { + #[arg(short, long)] + limit: Option, + }, + /// - List local users in the database #[clap(alias = "list")] ListUsers,