Skip to content
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

factor out notification token handling #2080

Merged
merged 5 commits into from
Mar 6, 2024
Merged

Conversation

r10s
Copy link
Member

@r10s r10s commented Feb 19, 2024

this PR moves the handling of the notification token to DcAccounts and DcContext objects using the new core API that supports real push notifications (correct core PR needs to be checked out at deltachat-ios/libraries/deltachat-core-rust manually to make this PR work)

Overview of related PRs:

EDIT: apart from the expected issues wrt "mute chat" and "mute all" the PRs play well together and things are working nicely (idea for "mute all" is to drop that switch and just open system notifications setting where you can "mute all" as well. or, if per-account-mute is needed, a revoke api. for "mute chat", maybe this is doable by a notification service exetension as well; i started a branch with that. that could also be used for "mute all". we'll see :) both, however should not block merging this pr)

there are two new API that will be replaced by the following core implementation soon:
- dc_accounts_set_notify_token(token) - passes the token received from apple to the core. core will forward it to supported (chatmail) server or, as a fallback, use it for heartbeat. as we have only one token for all accounts, core will do that for all accounts. the method may be called on every app start as the tokens may be short-living. the function may take a while (we should decide if UI needs to call it in a thread or core does that) there is no need for a return value, UI will check the state using the following method.
- dc_context_get_notify_state(context) - returns NOT_CONNECTED (0), HEARTBEAT (1) or PUSH (2) - this is a per-context method as some accounts may use chatmail while others not. the method is used by the UI mainly to show the state to the user
the PR adapts flow and connectivity view already to these new calls, however, still uses a "dummy" UI implementation. i also did this PR to make myself clear what is actually and really needed for UI :) (@hpk42 and me are first thinking that we can just use a set_config(), however, this does not work nicely as the token is same for all accounts)
@link2xt @zeitschlag if this roughly makes sense to you, i suggest to merge this PR already in, we can then focus on the core EDIT: we decided to go for changing core directly

@r10s r10s added the notify label Feb 19, 2024
@r10s r10s requested review from zeitschlag and link2xt February 19, 2024 22:37
@link2xt
Copy link
Contributor

link2xt commented Feb 23, 2024

Core part started here: deltachat/deltachat-core-rust#5286

@zeitschlag
Copy link
Collaborator

I'd suggest to do nothing for now and wait until Core implemented this. Then we can remove lots of code and just call the core.

@r10s
Copy link
Member Author

r10s commented Feb 23, 2024

I'd suggest to do nothing for now and wait until Core implemented this. Then we can remove lots of code and just call the core.

makes sense as well, esp. as the core part is already in the making :)

@link2xt
Copy link
Contributor

link2xt commented Feb 23, 2024

What do we need dc_context_get_notify_state for? It makes sense to know whether the server supports push (i.e. whether it is a recent chatmail or not), but do we really need to know for an account (single context) whether we have registered for heartbeat or not?

I am still not sure how heartbeat registration should happen. On the one hand it is not per-context because if user has 2 accounts we don't need to register twice with the same device token. On the other hand if user has a single account configured with SOCKS5 to use Tor, we definitely don't want to register by connecting directly to notification server bypassing Tor. How should we register for heartbeats if we have two accounts, one configured with SOCKS5 and the other not?

@r10s
Copy link
Member Author

r10s commented Feb 23, 2024

What do we need dc_context_get_notify_state for? It makes sense to know whether the server supports push (i.e. whether it is a recent chatmail or not), but do we really need to know for an account (single context) whether we have registered for heartbeat or not?

indeed my idea was to know for an account (single context) to know if heartbeat was registered or not and show that to the user (as "Not Connected" - as it may also mean the token is pending or the device is really not connected or just about to connect)

i think, this is useful for debugging.

I am still not sure how heartbeat registration should happen. On the one hand it is not per-context because if user has 2 accounts we don't need to register twice with the same device token.

yes. i'd loop over the account list and register for "real PUSH" where possible. only if there are accounts left, register one time for heartbeat.

so, we have the following pseudeo code (EDIT: refined):

pub struct Accounts {
    registered_for_heartbeat: bool;
    ...
}

pub struct Context {
    registered_for_real_push: bool;
    ...
}

fn set_notify_token(accounts: &Accounts, token: &str) {
    needs_heartbeat: bool = false;
    for context in accounts {
        if context.register_for_push_if_possible(token) {
            context.registered_for_real_push = true
        } else {
            needs_heartbeat = true
        }
    }
    if needs_heartbeat {
        if accounts.register_for_heartbeat(token) {
            accounts.registered_for_heartbeat = true;
        }
    }
}

fn get_notify_state(context: &Context) {
    if context.registered_for_real_push {
        return DC_NOTIFY_REAL_PUSH;
    }
    return accounts.registered_for_heartbeat ? DC_NOTIFY_HEARTBEAT : DC_NOTIFY_NOT_CONNECTED;
}

On the other hand if user has a single account configured with SOCKS5 to use Tor, we definitely don't want to register by connecting directly to notification server bypassing Tor. How should we register for heartbeats if we have two accounts, one configured with SOCKS5 and the other not?

i think, SOCKS5 and tor is nothing we should worry about currently. there are not even the corresponding options and on apple devices, not sure, how useful in general this is.

but to the question: if somehow any account is using SOCKS5 or Tor, i'd skip the whole registeration for all contexts

@link2xt
Copy link
Contributor

link2xt commented Feb 23, 2024

if somehow any account is using SOCKS5 or Tor, i'd skip the whole registeration for all contexts

Makes sense, sending device id over Tor is dangerous, better not register for push at all in this case.

@Simon-Laux
Copy link
Member

Simon-Laux commented Feb 23, 2024

dc_accounts_set_notify_token(token)

should also include the url or just take "url+token" (edit: makes sense to have them separate, if we want to keep transmitting the token in the body of the request) so we can both easily support sandbox and production tokens

@Simon-Laux
Copy link
Member

I think you can register the heartbeat even when using tor for single accounts, tor on iOS likely means a vpn for everything anyways?
also heatbeat is not that sensitive of an information anyway, you would just learn that a user uses deltachat when monitoring the non-tor traffic.

@link2xt
Copy link
Contributor

link2xt commented Feb 23, 2024

the function may take a while (we should decide if UI needs to call it in a thread or core does that)

set_notify_token should be immediate, it will just store the token in memory. We are only going to actually register only once we connect to some IMAP server and get its capabilities, so we know the server does not support actual push notifications.

@link2xt
Copy link
Contributor

link2xt commented Feb 25, 2024

dc_accounts_set_notify_token(token)

should also include the url or just take "url+token" (edit: makes sense to have them separate, if we want to keep transmitting the token in the body of the request) so we can both easily support sandbox and production tokens

Even notifiers server does not deal with the URL directly, they are hidden inside a2 crate: https://docs.rs/a2/0.8.0/a2/client/enum.Endpoint.html

Hostname of notifications.delta.chat I am going to hardcode into the core and chatmail service because otherwise we will need a mechanism similar to PushVerification in JMAP to make sure nobody can subscribe arbitrary URLs to our notifications. We can add API to set URL alternative to notifications.delta.chat later if needed.

From the core point of view device token is completely opaque, core will only forward the token to notifications.delta.chat or chatmail server via IMAP METADATA and never look into the token itself. I don't know when api.sandbox.push.apple.com is needed, but if we want to support it for developer builds I suggest that we remove --sandbox flag from notifiers and instead connect to both Apple endpoints from a single process. notifiers then can look at the token and forward notifications to one server or another based on the token itself, e.g. we can add sandbox: prefix to tokens that are registered with the sandbox server.

@r10s
Copy link
Member Author

r10s commented Feb 25, 2024

i adapted the PR so that it uses deltachat/deltachat-core-rust#5286 directly now

@r10s r10s force-pushed the r10s/factor-out-token-handling branch 3 times, most recently from 531eb34 to ee43946 Compare March 1, 2024 15:25
@r10s r10s force-pushed the r10s/factor-out-token-handling branch from 3efe04a to dbded35 Compare March 3, 2024 14:47
Copy link
Member

@Simon-Laux Simon-Laux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works nicely

@r10s
Copy link
Member Author

r10s commented Mar 6, 2024

k, merging that in.

"in-app muting chats" is not working for c20/nine.testrun.org when notifications are enabled in the system, however, the advantage of having reliable push notifications makes that a minor - and a fix for muting & co is already on its way with #2105 (but needs some more time so that it should not block ongoing release efforts)

r10s added 5 commits March 6, 2024 14:06
DEBUG-buils are only builds from us devs (testflight have DEBUG=0)
and can only receive remote push notification from the sandbox-apns.

still, it makes sense to get the PUSH notifications,
esp. during development, but also later to see if sth. goes wrong.

this commit reverts the change done at
#1773 ,
however, server-side, we aimt to have only one notifications.delta.chat
(that then calls sandbox or not based on the token)
@r10s r10s force-pushed the r10s/factor-out-token-handling branch from dbded35 to a846052 Compare March 6, 2024 13:10
@r10s r10s merged commit 2c8d650 into main Mar 6, 2024
@r10s r10s deleted the r10s/factor-out-token-handling branch March 6, 2024 13:11
@r10s r10s mentioned this pull request Mar 6, 2024
13 tasks
@zeitschlag zeitschlag removed their request for review January 15, 2025 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants