Add admin command to list last-active local users.

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2026-01-24 04:35:42 +00:00
parent 885e402e38
commit a3294fe1cf
4 changed files with 57 additions and 14 deletions

20
Cargo.lock generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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<usize>) -> 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::<Vec<_>>()
.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
}

View File

@@ -65,6 +65,12 @@ pub(super) enum UserCommand {
device_id: OwnedDeviceId,
},
/// - List local users by recent activity.
LastActive {
#[arg(short, long)]
limit: Option<usize>,
},
/// - List local users in the database
#[clap(alias = "list")]
ListUsers,