Repository navigation
feat(device-client): sync per zone, zone keys, notices stream and status - #127
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second of three
orbyn-device-clientPRs: sync. Design:docs/device-client.md("Sync").open_engine(snapshot)opensorbyn_client::Enginefor this device (a snapshot of another account or device is refused). The host stages and reads records with the engine as plainFields; sealing, opening and zone keys are inside it. The host seals the snapshot under the vault key.sync_all(&mut engine): one pass. Device list, zone keys other devices sent (accepted, then quarantined records retried), the zone list compared with local tokens, then every changed or pending zone pulled and pushed. A new zone is created on the server with a new key sealed to the account's other trusted devices.sync_zoneandsend_keysare public (the approver callssend_keysper zone after an approval).token_expired(also when an upload gets it); push merges a 409record_changedand goes again. A zone with no key yet iswaiting_for_key, not an error. A network failure isTransport, changes nothing and leaves everything staged.status(): atokio::sync::watchofSyncStatus { state, last_synced, last_error }withIdle,Syncing,Offline,SignedOut,ReauthenticationRequired,SessionExpired,AccountGone,Failed.notices(config): the/v1/syncWebSocket (ws for a loopback http, wss with rustls, ring and the web roots; still no aws-lc or OpenSSL). Signs in first with the session token;Connected,ZoneChanged,Resync,Disconnected,Rejected; answers pings; a silent connection is dropped after two minutes; reconnects with a doubling, jittered delay (1 s to 60 s); stops onunauthorized.ZoneDeleted,NoZoneKey,Engine(message);DeviceClient::api()accessor;DeviceApi::base_url()(default none).7a5f71d): a pass stops after 8 conflicts (Server { 409, record_changed }) and after 3 restarts on a 410 (Server { 410, token_expired }), keeping the work staged; the notices stream allowswsonly to a loopback IP literal (any other plain-text base gets no stream), caps frames and messages at 16 KiB, has a connect timeout, and writes the sign-in message with the token into a wiped buffer. TheTooLargecomment now says what happens (the batch is cleared, the records stay dirty, the next pass hits it again).remove_deviceand the deviceapplabel (engine#73). The integration test does the approval over HTTP with the engine's own pairing calls until then. Protection-chain signing is not done by the client.Closes #
Testing
crates/orbyn-server/tests/device_client.rs(real server, Postgres, real loopback socket): two devices with the zone key, a sealed record the server holds only as ciphertext, a pending device refused, waiting for a key then sending once it arrives, a merge of both devices' edits, a real conflict (a rival upload lands just before ours) merged and sent again, history purged and the zone started again, the snapshot round trip and refusal, offline work kept and sent later, a second zone's key handed out in the same pass, and the notices stream hearing another device and being rejected after the session is revoked.tests/notices.rs: a hand-made WebSocket server checks the sign-in message, the pong, the reconnect and the stop. Unit tests for the percent-encoding, the state per error and the backoff.wsto any host, no frame limits, no connect timeout): all killed.tests/limits.rsscripts a transport that always answers 409 or 410 and checks the pass stops after the limit with an error and the work staged;tests/notices.rschecks a connection that reaches ready starts the delay over, the connect timeout and the oversized frame. One equivalent removed: the explicitverify_devicescall, since the engine verifies when it takes keys in or hands them out.cargo test --workspace -- --include-ignoredwith Postgres.Co-authors
none
AI usage
Checklist
docs/architecture.mdwith any rule change; generated wire types with any contract change