feat(relay): ephemeral delivery, call wake-ups and TURN credentials

Protocol and relay groundwork for typing indicators and 1:1 calls.

- ContentHint.EPHEMERAL: delivered only to an online recipient, never
  queued or pushed; the sender gets Receipt.STATUS_DROPPED otherwise.
- ContentHint.CALL: a call offer is queued like a normal message, but an
  offline recipient is woken immediately — a PushKit VoIP push on iOS
  (priority 10, 45 s expiry) or a short-lived FCM data message on
  Android. The relay learns that a device is being called, not by whom.
- RegisterPush.voip_token stores the iOS VoIP token next to the regular
  APNs token (migration 0004).
- TurnRequest/TurnCredentials: logged-in devices receive time-limited
  coturn credentials (use-auth-secret REST scheme, HMAC-SHA1), so the
  TURN server is never an open relay. Configured with SEPOT_TURN_URLS and
  SEPOT_TURN_SECRET or SEPOT_TURN_SECRET_FILE; without them calls fall
  back to direct connections and STUN.
This commit is contained in:
Julius Joska
2026-10-03 22:43:53 +02:00
parent 4e3d7de32c
commit 69687d0acf
14 changed files with 698 additions and 27 deletions
+18 -2
View File
@@ -22,14 +22,27 @@ class ContentHint extends $pb.ProtobufEnum {
static const ContentHint CONTENT_HINT_SUPPLEMENTARY =
ContentHint._(2, _omitEnumNames ? '' : 'CONTENT_HINT_SUPPLEMENTARY');
/// Jen živé doručení (např. „píše…“): offline příjemci se neukládá do
/// fronty ani nebudí pushem — zastaralá by po vyzvednutí jen mátla.
static const ContentHint CONTENT_HINT_EPHEMERAL =
ContentHint._(3, _omitEnumNames ? '' : 'CONTENT_HINT_EPHEMERAL');
/// Nabídka hovoru: ukládá se jako běžná zpráva, ale offline příjemce se
/// budí VoIP pushem (iOS) nebo FCM s krátkou platností — zvonit má hned.
/// Relay se tím dozví, že zařízení někdo volá; kdo, dál neví.
static const ContentHint CONTENT_HINT_CALL =
ContentHint._(4, _omitEnumNames ? '' : 'CONTENT_HINT_CALL');
static const $core.List<ContentHint> values = <ContentHint>[
CONTENT_HINT_DEFAULT,
CONTENT_HINT_RESYNC,
CONTENT_HINT_SUPPLEMENTARY,
CONTENT_HINT_EPHEMERAL,
CONTENT_HINT_CALL,
];
static final $core.List<ContentHint?> _byValue =
$pb.ProtobufEnum.$_initByValueList(values, 2);
$pb.ProtobufEnum.$_initByValueList(values, 4);
static ContentHint? valueOf($core.int value) =>
value < 0 || value >= _byValue.length ? null : _byValue[value];
@@ -43,15 +56,18 @@ class Receipt_Status extends $pb.ProtobufEnum {
Receipt_Status._(1, _omitEnumNames ? '' : 'STATUS_DELIVERED_ONLINE');
static const Receipt_Status STATUS_STORED_OFFLINE =
Receipt_Status._(2, _omitEnumNames ? '' : 'STATUS_STORED_OFFLINE');
static const Receipt_Status STATUS_DROPPED =
Receipt_Status._(3, _omitEnumNames ? '' : 'STATUS_DROPPED');
static const $core.List<Receipt_Status> values = <Receipt_Status>[
STATUS_QUEUED,
STATUS_DELIVERED_ONLINE,
STATUS_STORED_OFFLINE,
STATUS_DROPPED,
];
static final $core.List<Receipt_Status?> _byValue =
$pb.ProtobufEnum.$_initByValueList(values, 2);
$pb.ProtobufEnum.$_initByValueList(values, 3);
static Receipt_Status? valueOf($core.int value) =>
value < 0 || value >= _byValue.length ? null : _byValue[value];