feat: implement optional support for MSC4495 (Selective Presence) #2034

Open
thetayloredman wants to merge 11 commits from thetayloredman/continuwuity:presence-v2/msc4495 into main
Contributor

This pull request adds experimental support for inbound and outbound MSC4495: Selective Presence (rendered; a component of Presence v2).

This PR is reviewable on a commit-by-commit basis (and I recommend doing so).

Selective Presence allows users to control the recipients of their presence for the sake of substantial performance and privacy improvements.

Currently, this feature is optional as no client has support yet.

Blocked on the following:

Pull request checklist:

  • This pull request targets the main branch, and the branch is named something other than
    main.
  • I have written an appropriate pull request title and my description is clear.
  • I understand I am responsible for the contents of this pull request.
  • I have followed the contributing guidelines:
This pull request adds experimental support for inbound and outbound [MSC4495: Selective Presence](https://github.com/matrix-org/matrix-spec-proposals/pull/4495) ([rendered](https://github.com/thetayloredman/matrix-spec-proposals/blob/presence-v2/selective/proposals/4495-selective-presence.md); a component of [Presence v2](https://ispresencefixedyet.com)). This PR is reviewable on a commit-by-commit basis (and I recommend doing so). Selective Presence allows users to control the recipients of their presence for the sake of substantial performance and privacy improvements. Currently, this feature is optional as no client has support yet. **Blocked on the following:** * [x] PR to Ruma upstream: https://github.com/ruma/ruma/pull/2546 * [x] Ruma `3ad0471` making it into main: #2049 **Pull request checklist:** <!-- You need to complete these before your PR can be considered. If you aren't sure about some, feel free to ask for clarification in #dev:continuwuity.org. --> - [x] This pull request targets the `main` branch, and the branch is named something other than `main`. - [x] I have written an appropriate pull request title and my description is clear. - [x] I understand I am responsible for the contents of this pull request. - I have followed the [contributing guidelines][c1]: - [x] My contribution follows the [code style][c2], if applicable. - [x] I ran [pre-commit checks][c1pc] before opening/drafting this pull request. - [x] I have [tested my contribution][c1t] (or proof-read it for documentation-only changes) myself, if applicable. This includes ensuring code compiles. - [x] My commit messages follow the [commit message format][c1cm] and are descriptive. <!-- Notes on these requirements: - While not required, we encourage you to sign your commits with GPG or SSH to attest the authenticity of your changes. - While we allow LLM-assisted contributions, we do not appreciate contributions that are low quality, which is typical of machine-generated contributions that have not had a lot of love and care from a human. Please do not open a PR if all you have done is asked ChatGPT to tidy up the codebase with a +-100,000 diff. - In the case of code style violations, reviewers may leave review comments/change requests indicating what the ideal change would look like. For example, a reviewer may suggest you lower a log level, or use `match` instead of `if/else` etc. - In the case of code style violations, pre-commit check failures, minor things like typos/spelling errors, and in some cases commit format violations, reviewers may modify your branch directly, typically by making changes and adding a commit. Particularly in the latter case, a reviewer may rebase your commits to squash "spammy" ones (like "fix", "fix", "actually fix"), and reword commit messages that don't satisfy the format. - Pull requests MUST pass the `Checks` CI workflows to be capable of being merged. This can only be bypassed in exceptional circumstances. If your CI flakes, let us know in matrix:r/dev:continuwuity.org. - Pull requests have to be based on the latest `main` commit before being merged. If the main branch changes while you're making your changes, you should make sure you rebase on main before opening a PR. Your branch will be rebased on main before it is merged if it has fallen behind. - We typically only do fast-forward merges, so your entire commit log will be included. Once in main, it's difficult to get out cleanly, so put on your best dress, smile for the cameras! --> [c1]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md [c2]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/docs/development/code_style.mdx [c1pc]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#pre-commit-checks [c1t]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#running-tests-locally [c1cm]: https://forgejo.ellis.link/continuwuation/continuwuity/src/branch/main/CONTRIBUTING.md#commit-messages
@ -1491,0 +1494,4 @@
/// by default. Users will need to use MSC4495-compatible clients to explicitly
/// opt in to presence sharing with other users.
///
/// If this is enabled, you probably also want to set `allow_outgoing_presence`.
Owner

consistency nit:

- /// If this is enabled, you probably also want to set `allow_outgoing_presence`.
+ /// This option has no effect if `allow_outgoing_presence` is not enabled.
consistency nit: ```diff - /// If this is enabled, you probably also want to set `allow_outgoing_presence`. + /// This option has no effect if `allow_outgoing_presence` is not enabled. ```
Author
Contributor

Technically Selective Presence can be used locally only just fine. I've removed the line entirely, there was little point in it

Technically Selective Presence can be used locally only just fine. I've removed the line entirely, there was little point in it
thetayloredman marked this conversation as resolved
thetayloredman force-pushed presence-v2/msc4495 from 62a3f42104
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m9s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m18s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m9s
to 2b04c909e5
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m8s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m20s
Checks / Prek / Clippy and Cargo Tests (pull_request) Has been cancelled
2026-07-22 22:40:13 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 2b04c909e5
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m8s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m20s
Checks / Prek / Clippy and Cargo Tests (pull_request) Has been cancelled
to 5df240c824
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m17s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m14s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m35s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 12s
2026-07-22 22:41:54 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 5df240c824
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m17s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m14s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m35s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 12s
to 32403f67f3
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m9s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m14s
Deploy Element Web / 🏗️ Build and Deploy (pull_request) Failing after 6m43s
Checks / Prek / Clippy and Cargo Tests (pull_request) Has been cancelled
2026-07-27 01:45:47 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 32403f67f3
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m9s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m14s
Deploy Element Web / 🏗️ Build and Deploy (pull_request) Failing after 6m43s
Checks / Prek / Clippy and Cargo Tests (pull_request) Has been cancelled
to 03f2ac12f4
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m9s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m35s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m50s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
2026-07-27 01:55:09 +00:00
Compare
Author
Contributor

This PR is now using upstream Ruma, as merged in #2049.

This PR is now using upstream Ruma, as merged in #2049.
thetayloredman changed title from WIP: feat: implement optional support for MSC4495 (Selective Presence) to feat: implement optional support for MSC4495 (Selective Presence) 2026-07-27 01:55:22 +00:00
Owner

I'm inclined to say we should wait on merging this into main until at least one client supports it, so that we avoid having (temporarily) dead code to keep up with, especially given the size of the change. The PR can still be deployed if a client wishes to use it.

I'm inclined to say we should wait on merging this into main until at least one client supports it, so that we avoid having (temporarily) dead code to keep up with, especially given the size of the change. The PR can still be deployed if a client wishes to use it.
thetayloredman force-pushed presence-v2/msc4495 from 03f2ac12f4
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m9s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m35s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m50s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
to 05637acc6c
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 56s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m21s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 9m13s
2026-07-28 00:48:01 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 05637acc6c
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 56s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m21s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 9m13s
to b553c1f0da
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 12s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m15s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 2m6s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m6s
2026-07-28 01:47:46 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from b553c1f0da
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 12s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m15s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 2m6s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m6s
to 4bb690ecd9
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m12s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m10s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m30s
2026-07-28 03:45:07 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 4bb690ecd9
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m12s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m10s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m30s
to db49e981d7
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 7s
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m17s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m11s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m58s
2026-07-30 20:33:30 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from db49e981d7
All checks were successful
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 7s
Checks / Prek / Check changed files (pull_request) Successful in 5s
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m17s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m11s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 8m58s
to 84c1c09da3
All checks were successful
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 10s
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m37s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m21s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m34s
2026-08-11 22:39:16 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 84c1c09da3
All checks were successful
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 10s
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Pre-commit & Formatting (pull_request) Successful in 1m37s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m21s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m34s
to 36c2985fe9
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 8s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m14s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m24s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m1s
2026-08-22 23:04:12 +00:00
Compare
thetayloredman force-pushed presence-v2/msc4495 from 36c2985fe9
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 8s
Checks / Prek / Check changed files (pull_request) Successful in 6s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m14s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m24s
Checks / Prek / Clippy and Cargo Tests (pull_request) Successful in 11m1s
to 329f491c9e
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 6s
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 9s
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m9s
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m24s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 5m36s
2026-09-06 00:26:39 +00:00
Compare
@ -1400,0 +1405,4 @@
#
# [MSC4495]: https://github.com/matrix-org/matrix-spec-proposals/pull/4495
#
#enable_msc4495_selective_presence = false
Owner

this config option should really go in a new section for MSCs. I know we have other MSC options that didn't do that but I'd rather start doing it now

this config option should really go in a new section for MSCs. I know we have other MSC options that didn't do that but I'd rather start doing it now
@ -1240,0 +1241,4 @@
pub(super) async fn recalculate_presence_recipients(&self, user_id: OwnedUserId) -> Result {
self.bail_restricted()?;
let out = match self
Owner

nit: I would replace this with multiple calls to write!(self, ...)

nit: I would replace this with multiple calls to `write!(self, ...)`
@ -487,2 +488,4 @@
.await?;
// 5.4 Presence Sharing
services
Owner

should the presence sharing hint always be added to new rooms?

should the presence sharing hint _always_ be added to new rooms?
@ -374,0 +396,4 @@
// Incremental update
| Some(prev_id)
if current_recipients.stream_id == <Int as Into<i64>>::into(prev_id) =>
Owner

nit: this would be more clear as i64::from(prev_id)

nit: this would be more clear as `i64::from(prev_id)`
@ -162,2 +162,4 @@
..descriptor::SEQUENTIAL_SMALL
},
Descriptor {
name: "userid_recipients",
Owner

this would be more clear as userid_presencerecipients

this would be more clear as `userid_presencerecipients`
@ -167,0 +238,4 @@
prev_recipients
.stream_id
.try_into()
.expect("js_int overflowed"),
Owner

can the stream ID reasonably overflow a JSInt in normal operation?

can the stream ID reasonably overflow a JSInt in normal operation?
@ -167,0 +250,4 @@
);
},
| Err(e) => {
warn!("Failed to calculate presence recipients for {user_id}: {e}");
Owner

in what situations can this fail? is sending a legacy presence EDU the correct behavior if it does?

in what situations can this fail? is sending a legacy presence EDU the correct behavior if it does?
@ -167,0 +265,4 @@
.chain(update.recipients.delete.iter())
.map(|u| u.server_name().to_owned())
.dedup()
.collect::<Vec<_>>()
Owner

any reason why this can't be a hashset?

any reason why this can't be a hashset?
@ -167,0 +293,4 @@
let mut buf = EduBuf::new();
serde_json::to_writer(
&mut buf,
&Edu::Presence(PresenceContent::new(vec![server_update])),
Owner

why is this being wrapped in a second vec?

why is this being wrapped in a second vec?
@ -278,0 +560,4 @@
.services
.users
.stream_local_users()
.filter(|local_user| {
Owner

any reason why this can't be an async closure?

any reason why this can't be an async closure?
@ -278,0 +618,4 @@
return Ok(None);
}
let stream_id = self.services.globals.next_count()?.cast_signed();
Owner

I really loathe the global count. is there any reason why we can't just use the previous stream ID and increment that?

I really loathe the global count. is there any reason why we can't just use the previous stream ID and increment that?
@ -193,1 +193,4 @@
/// Returns all servers that can see a user by sharing at least one room.
pub async fn servers_seeing_user(&self, user_id: &UserId) -> Vec<OwnedServerName> {
let rooms = self
Owner

any reason why we need to collect this stream before iterating over it?

any reason why we need to collect this stream before iterating over it?
@ -194,0 +197,4 @@
.rooms_joined(user_id)
.collect::<Vec<OwnedRoomId>>()
.await;
let mut servers = Vec::new();
Owner

any reason why this can't be a btreeset?

any reason why this can't be a btreeset?
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Has been skipped
Checks / Prek / Check changed files (pull_request) Successful in 6s
Required
Details
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 9s
Required
Details
Checks / Prek / Pre-commit & Formatting (pull_request) Failing after 1m9s
Required
Details
Update flake hashes / update-flake-hashes (pull_request) Successful in 1m24s
Checks / Prek / Clippy and Cargo Tests (pull_request) Failing after 5m36s
Required
Details
This pull request has changes requested by an official reviewer.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u presence-v2/msc4495:thetayloredman-presence-v2/msc4495
git switch thetayloredman-presence-v2/msc4495
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
continuwuation/continuwuity!2034
No description provided.