[feat] add iOS announcement inbox

This commit is contained in:
dijunkun
2026-09-29 23:43:32 +08:00
parent 2d1241c0a0
commit 31acb6b2f0
9 changed files with 814 additions and 17 deletions
@@ -99,6 +99,10 @@ typedef struct {
- (void)rtcBridge:(CrossDeskRTCBridge *)bridge
didReceivePresence:(NSDictionary<NSString *, NSNumber *> *)presence
snapshot:(BOOL)snapshot;
- (void)rtcBridge:(CrossDeskRTCBridge *)bridge
didReceiveAnnouncementMessage:(NSData *)message;
- (void)rtcBridge:(CrossDeskRTCBridge *)bridge
didFailAnnouncementRequest:(NSString *)requestID;
- (void)rtcBridge:(CrossDeskRTCBridge *)bridge
didReceiveCursorVisible:(BOOL)visible
shape:(NSInteger)shape
@@ -150,6 +154,8 @@ typedef struct {
subscribe:(BOOL)subscribe
NS_SWIFT_NAME(requestPresence(remoteIDs:subscribe:));
- (void)invalidatePresence;
- (void)sendAnnouncementRequest:(NSData *)request requestID:(NSString *)requestID
NS_SWIFT_NAME(sendAnnouncementRequest(_:requestID:));
- (void)connectToRemoteID:(NSString *)remoteID password:(NSString *)password;
- (void)disconnect;
@@ -615,13 +615,6 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
if (load_status == errSecSuccess) {
self->_state->identity_with_password = cached.UTF8String;
self->_state->identity_base = BaseIdentity(self->_state->identity_with_password);
NSString *identifier = [NSString stringWithUTF8String:self->_state->identity_base.c_str()];
DispatchMain(^{
id<CrossDeskRTCBridgeDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(rtcBridge:didProvisionIdentity:)]) {
[delegate rtcBridge:self didProvisionIdentity:identifier];
}
});
} else if (load_status != errSecItemNotFound) {
[self reportIdentityStorageStatus:load_status];
// Locked/unavailable Keychain is not the same as a missing identity.
@@ -631,6 +624,18 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
return;
}
[self createIdentityPeer];
if (load_status == errSecSuccess) {
NSString *identifier = [NSString stringWithUTF8String:self->_state->identity_base.c_str()];
const uint64_t identity_generation = self->_identityGeneration.load();
DispatchMain(^{
if (networking_generation != self->_networkingGeneration.load() ||
identity_generation != self->_identityGeneration.load()) return;
id<CrossDeskRTCBridgeDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(rtcBridge:didProvisionIdentity:)]) {
[delegate rtcBridge:self didProvisionIdentity:identifier];
}
});
}
});
}
@@ -658,6 +663,32 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
_presenceGeneration.fetch_add(1);
}
- (void)sendAnnouncementRequest:(NSData *)request requestID:(NSString *)requestID {
NSData *payload = [request copy];
NSString *identifier = [requestID copy];
const uint64_t generation = _identityGeneration.load();
const uint64_t signal_generation = _signalGeneration.load();
const uint64_t networking_generation = _networkingGeneration.load();
dispatch_async(_rtcQueue, ^{
if (generation != self->_identityGeneration.load() ||
signal_generation != self->_signalGeneration.load() ||
networking_generation != self->_networkingGeneration.load()) return;
if (self->_state->identity_peer && self->_state->identity_ready &&
!self->_state->identity_base.empty() &&
SendSignalMessage(self->_state->identity_peer,
static_cast<const char *>(payload.bytes), payload.length) == 0) return;
DispatchMain(^{
if (generation != self->_identityGeneration.load() ||
signal_generation != self->_signalGeneration.load() ||
networking_generation != self->_networkingGeneration.load()) return;
id<CrossDeskRTCBridgeDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(rtcBridge:didFailAnnouncementRequest:)]) {
[delegate rtcBridge:self didFailAnnouncementRequest:identifier];
}
});
});
}
- (void)sendVideoSettingsWithQuality:(NSInteger)quality
frameRate:(NSInteger)frameRate
preference:(NSInteger)preference
@@ -1216,10 +1247,11 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
size:(size_t)size
role:(PeerRole)role
generation:(uint64_t)generation {
constexpr size_t kMaxPresenceMessageSize = 256 * 1024;
// Twenty 8 KiB bodies may expand substantially when JSON-escaped.
constexpr size_t kMaxSignalMessageSize = 1024 * 1024;
if (role != PeerRole::Identity || generation != _identityGeneration.load() ||
!message || size == 0 ||
size > kMaxPresenceMessageSize) {
size > kMaxSignalMessageSize) {
return;
}
@@ -1235,6 +1267,19 @@ Params MakeParams(const RTCState &state, const std::string &user_id,
NSString *type = object[@"type"];
if (![type isKindOfClass:NSString.class]) return;
if ([type isEqualToString:@"announcements"] ||
[type isEqualToString:@"announcements_changed"]) {
DispatchMain(^{
if (generation != self->_identityGeneration.load() ||
signal_generation != self->_signalGeneration.load()) return;
id<CrossDeskRTCBridgeDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(rtcBridge:didReceiveAnnouncementMessage:)]) {
[delegate rtcBridge:self didReceiveAnnouncementMessage:payload];
}
});
return;
}
NSMutableDictionary<NSString *, NSNumber *> *presence =
[NSMutableDictionary dictionary];
if ([type isEqualToString:@"presence"]) {