service/PushReceiver.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QByteArray> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QString> | ||
| 6 | |||
| 7 | #include "data/DavPushModels.h" | ||
| 8 | |||
| 9 | // Sprint 96 S96.2.1: provider-independent contract of a push receive | ||
| 10 | // channel (one per DAV account). The provider adapter owns transport, | ||
| 11 | // framing, heartbeats and reconnects; the DAV-Push coordinator owns keys, | ||
| 12 | // decryption and DAV registrations. Provider events (open/keepalive) prove | ||
| 13 | // the stream only — a DAV change is a delivered message that decrypts and | ||
| 14 | // maps to a selected collection. | ||
| 15 | class PushReceiver : public QObject { | ||
| 16 | Q_OBJECT | ||
| 17 | public: | ||
| 18 | struct Config { | ||
| 19 | QString server; // https origin of the push service | ||
| 20 | QString channel; // random channel id (secret) | ||
| 21 | QByteArray token; // optional subscriber bearer token (secret) | ||
| 22 | QString resumeAfterId; // provider cursor: replay messages after this id | ||
| 23 | QString vapidKey; // DAV server's VAPID key, base64url (UnifiedPush distributors; optional) | ||
| 24 | }; | ||
| 25 | // Typed reason of the last failure (no secrets). | ||
| 26 | enum class Failure { None, Network, Timeout, Tls, Authentication, RateLimited, Protocol, Overflow }; | ||
| 27 | 34 | Q_ENUM(Failure) | |
| 28 | |||
| 29 | using QObject::QObject; | ||
| 30 | 63 | ~PushReceiver() override = default; | |
| 31 | |||
| 32 | virtual void start(const Config &config) = 0; | ||
| 33 | virtual void stop() = 0; | ||
| 34 | // The publisher URL a DAV server delivers to (secret capability). | ||
| 35 | virtual QString endpoint() const = 0; | ||
| 36 | |||
| 37 | 567 | DavPushReceiverState state() const { return m_state; } | |
| 38 | 16 | Failure failure() const { return m_failure; } | |
| 39 | 444 | QString failureDetail() const { return m_failureDetail; } | |
| 40 | 440 | qint64 connectedSince() const { return m_connectedSince; } // epoch ms, 0 = not connected | |
| 41 | 439 | qint64 lastActivity() const { return m_lastActivity; } // epoch ms of the last provider event | |
| 42 | 449 | qint64 nextAttemptAt() const { return m_nextAttemptAt; } // epoch ms of the next reconnect | |
| 43 | 1 | QString lastMessageId() const { return m_lastMessageId; } | |
| 44 | |||
| 45 | signals: | ||
| 46 | void stateChanged(); | ||
| 47 | // One delivered push body (still encrypted). `messageId` is the | ||
| 48 | // provider's id; duplicates of recently seen ids are not emitted. | ||
| 49 | void messageReceived(const QByteArray &payload, const QString &messageId); | ||
| 50 | // The stream (re)opened after a gap: messages may have been lost, the | ||
| 51 | // owner requests a catch-up sync. | ||
| 52 | void streamResumed(bool afterGap); | ||
| 53 | // Wire accounting (bytes of the provider stream). | ||
| 54 | void bytesReceived(qint64 bytes); | ||
| 55 | |||
| 56 | protected: | ||
| 57 | 186 | void setState(DavPushReceiverState state, Failure failure = Failure::None, const QString &detail = {}) { | |
| 58 |
6/8✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 7 taken 171 times.
✓ Branch 3 → 4 taken 15 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 15 times.
✗ Branch 5 → 7 not taken.
✓ Branch 8 → 9 taken 15 times.
✓ Branch 8 → 10 taken 171 times.
|
186 | if (m_state == state && m_failure == failure && m_failureDetail == detail) return; |
| 59 | 171 | m_state = state; | |
| 60 | 171 | m_failure = failure; | |
| 61 | 171 | m_failureDetail = detail; | |
| 62 | 171 | emit stateChanged(); | |
| 63 | } | ||
| 64 | |||
| 65 | DavPushReceiverState m_state = DavPushReceiverState::Stopped; | ||
| 66 | Failure m_failure = Failure::None; | ||
| 67 | QString m_failureDetail; | ||
| 68 | qint64 m_connectedSince = 0; | ||
| 69 | qint64 m_lastActivity = 0; | ||
| 70 | qint64 m_nextAttemptAt = 0; | ||
| 71 | QString m_lastMessageId; | ||
| 72 | }; | ||
| 73 |