Skip to content

[gateway] explicit registration, unregister feature - #430

Open
capcom6 wants to merge 1 commit into
masterfrom
gateway/explicit-registration
Open

capcom6 wants to merge 1 commit into
masterfrom
gateway/explicit-registration

Conversation

@capcom6

@capcom6 capcom6 commented Aug 21, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds explicit cloud register / unregister controls in cloud server settings and reworks the SSE/FCM lifecycle coordination so realtime delivery stays correct across registration, account replacement, and unregister.

Key changes:

  • Cloud settings now expose explicit Register (sign-up / sign-in / sign-in by code) and Unregister actions.
  • GatewayService.registerDevice persists the new identity, then emits DeviceRegisteredEvent.Success; SSE credentials are resolved fresh on every SSEManager.connect (no cached stale token).
  • SSE manager gains synchronous teardown, duplicate-connection prevention, and reconnect suppression via an isDisconnecting flag checked in every callback.
  • RegistrationWorker is narrowed to updating an existing device with the FCM token (background refresh only).
  • CloudServerSettingsFragment stops the gateway pipeline before registering, restores it after, and swallows non-fatal post-success UI errors.
  • Fix: lifecycle cancellation no longer rolls back an already-persisted registration (outer catch now rethrows CancellationException).
  • Unregister clears the local registration and stops the pipeline. It does not detach the device server-side — see "Known limitations".
  • PushService.onMessageReceived and the receiver-side MessagesExportRequestedEvent collector drop cloud commands when registrationInfo == null, so an unregistered device stops acting on commands.
  • Registration in HomeFragment is now single-flight across sign-up / sign-in / sign-in-by-code, and lifecycle cancellation is rethrown instead of being reported as a failure against a detached fragment.

Why

Previously registration was implicit/automatic; users could not intentionally (re)register or unregister, and several lifecycle races could leave SSE bound to a stale account or drop the registration event for SSE-only devices.

Known limitations (deferred)

GatewayService.start() revives the workers and the events receiver but does not start SSE. DeviceRegisteredEvent.Success is emitted while the receiver is stopped, so it has no collector at that moment. SSE therefore resumes only indirectly, when the FCM RegistrationWorker re-runs updateDevice() and re-emits the event to the already-restarted receiver.

This is left as-is for now. The interim workaround is the restart-app hint in device_registered_successfully; the gap is recorded in a comment on the CancellationException branch of registerDeviceInternal and is being tracked separately. Explicitly starting SSEForegroundService on both the success and rollback paths would close it.

Unregister is local-only. The device cannot be detached from its account with the current server contract, verified against the server source:

  • PATCH /mobile/v1/device cannot clear the push token. MobileUpdateRequest.PushToken is a plain string, and lo.EmptyableToPtr(req.PushToken) maps both an absent and an empty value to nil; the repository then omits push_token from the update and answers 204 No Content. Sending "" is a silent no-op that is indistinguishable from success, so it was deliberately not used here.
  • There is no DELETE /mobile/v1/device. Adding one is not an option: devices is the parent of messages, webhooks and inbox via ON DELETE CASCADE, and SoftDeletableModel.DeletedAt is a plain *time.Time rather than gorm.DeletedAt, so removal is a hard delete that would take the device's message history with it.

Consequence: the server keeps the push token and can still deliver commands for the previous registration once the user registers again, because registrationInfo becomes non-null. The entry-point guards close the unregistered window only. Closing this needs a server contract change — an explicit clearPushToken flag on the mobile PATCH request would do it without changing behavior for existing clients — and is tracked as a follow-up.

Test plan

  • ./gradlew test - green on all variants, matching the CI step in .github/workflows/build-apk.yml.
  • SSEManagerTest - not written yet. CI does run unit tests, so the concurrency rework in SSEManager would be guarded by them; the coverage gap is ours to close and is deferred to a follow-up, not blocked by tooling.
  • Manual: register (SSE-only and FCM) -> verify stream starts; replace account -> verify old stream closed; destroy fragment mid-registration -> verify credentials are NOT reverted.
  • Manual: unregister -> verify SSE stops and no cloud events are acted on; tap Start twice quickly on first start -> verify only one signup request is sent.
  • Known gap, expected to reproduce: unregister, then register again -> commands addressed to the previous registration may still be delivered.

RetriggerConfidence Score: 2/5

The PR is not yet safe to merge because SSE teardown can reopen a connection and obsolete authenticated sources can still forward commands after account replacement.

Summary

The PR adds explicit cloud registration and local unregister controls, refreshes FCM registration behavior, and reworks SSE teardown and credential resolution.

  • Adds register, sign-in, and unregister actions to cloud settings.
  • Persists replacement identities before emitting registration success and resolves SSE credentials on each connection.
  • Rejects push and export commands while locally unregistered.
  • Adds single-flight registration handling on the home screen.

Reviews (43) · Last reviewed commit: "[gateway] explicit registration, unregis..." · Reviewed by Greptile

Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
@github-actions

github-actions Bot commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Pull request artifacts

file commit
app-release.apk 13f9dcf
app-release.aab 13f9dcf
app-insecure.apk 13f9dcf
app-insecure.aab 13f9dcf

@capcom6
capcom6 force-pushed the gateway/explicit-registration branch 2 times, most recently from 8c7f581 to f541c0f Compare August 21, 2026 12:00
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch 2 times, most recently from 87c23d4 to 565a464 Compare August 25, 2026 02:00
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
capcom6 added a commit that referenced this pull request Aug 26, 2026
When explicit registration completes with a null FCM token, SSE starts as the
fallback transport. The later FCM token update via RegistrationWorker set the
token but never tore down the SSE stream, leaving both transports active and
causing duplicate cloud-event delivery. Tear down SSE in updateDevice when a
non-null push token is set.

Fixes Greptile review blocker on PR #430.
capcom6 added a commit that referenced this pull request Aug 26, 2026
…M token

Symmetrize SSE management in EventsReceiver: when a DeviceRegisteredEvent is
processed after the FCM token has been recorded, stop the SSE foreground
service instead of leaving it running alongside FCM. Prevents duplicate
cloud-event delivery reported by Greptile on PR #430.
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
capcom6 added a commit that referenced this pull request Aug 26, 2026
Capture the application context up front and use nullable activity access for
the progress bar so an in-flight explicit registration no longer throws from
requireContext()/requireActivity() if the user navigates away, which would
abort SSE startup and service.start() for an already-registered device.

Addresses Greptile P1 'Fragment detachment aborts SSE startup' on PR #430.
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 78258ec to 60d3114 Compare August 26, 2026 07:05
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 0c955cf to ded47f7 Compare August 29, 2026 00:02
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch 2 times, most recently from f470387 to 4fd3ab9 Compare August 31, 2026 07:44
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from f409d7b to cde7b68 Compare September 2, 2026 01:02
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch 2 times, most recently from 66ddd2b to 98643d2 Compare September 4, 2026 00:08
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 98643d2 to 7b4ea1b Compare September 8, 2026 01:17
Comment thread app/src/main/java/me/capcom/smsgateway/helpers/SSEManager.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 737b291 to e91c1fd Compare September 10, 2026 03:05
@capcom6 capcom6 added the ready label Sep 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 7 days with no activity.

@github-actions github-actions Bot added the stale label Sep 20, 2026
@capcom6 capcom6 removed the stale label Sep 21, 2026
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from e91c1fd to e6f3568 Compare September 25, 2026 01:45
@github-actions github-actions Bot removed the ready label Sep 25, 2026
@greptile-apps

This comment has been minimized.

@capcom6
capcom6 force-pushed the gateway/explicit-registration branch 3 times, most recently from 2a863f2 to 3de2a03 Compare October 1, 2026 07:57
@capcom6 capcom6 added the ready label Oct 2, 2026
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 7 days with no activity.

@github-actions github-actions Bot added the stale label Oct 9, 2026
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 3de2a03 to f939ba7 Compare October 9, 2026 03:36
@github-actions github-actions Bot removed the ready label Oct 9, 2026
@github-actions github-actions Bot removed the stale label Oct 10, 2026
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from f939ba7 to 7f46a89 Compare October 12, 2026 00:52
Comment thread app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt Outdated
Comment thread app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt Outdated
@capcom6
capcom6 force-pushed the gateway/explicit-registration branch from 6300e40 to 13f9dcf Compare October 14, 2026 08:25

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant