Files
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

62 lines
3.0 KiB
Swift

import Foundation
import Postbox
/// Which message a delivered notification stands for, keyed by the `UNNotificationRequest`
/// identifier the system assigned to it.
///
/// The notification service extension records this for every message notification it
/// handles. Siri's announce flow (AirPods, CarPlay) later asks the intents extension for the
/// messages behind a notification through `INSearchForMessagesIntent.notificationIdentifiers`,
/// and this is the only link between that identifier and a `MessageId`: the identifier is
/// generated by the system per delivery and never appears in the push payload.
///
/// The links live in one item-cache row as a bounded, newest-last list. Request identifiers
/// are per-delivery UUIDs that never repeat, so a row per link would grow for the life of the
/// account (the item cache has no eviction), while Siri only ever asks about a notification
/// that is still recent.
private struct NotificationRequestMessageIdLink: Codable {
var requestIdentifier: String
var peerId: Int64
var namespace: Int32
var id: Int32
}
private struct NotificationRequestMessageIdLinks: Codable {
var links: [NotificationRequestMessageIdLink]
}
/// How many recent notification → message links are kept per account.
public let _internal_notificationRequestMessageIdsLimit: Int = 256
private let notificationRequestMessageIdsEntryId = ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.notificationRequestMessageIds, key: ValueBoxKey("links"))
private func loadLinks(transaction: Transaction) -> [NotificationRequestMessageIdLink] {
return transaction.retrieveItemCacheEntry(id: notificationRequestMessageIdsEntryId)?.get(NotificationRequestMessageIdLinks.self)?.links ?? []
}
public func _internal_setNotificationRequestMessageId(transaction: Transaction, requestIdentifier: String, messageId: MessageId) {
if requestIdentifier.isEmpty {
return
}
var links = loadLinks(transaction: transaction)
links.removeAll(where: { $0.requestIdentifier == requestIdentifier })
links.append(NotificationRequestMessageIdLink(requestIdentifier: requestIdentifier, peerId: messageId.peerId.toInt64(), namespace: messageId.namespace, id: messageId.id))
if links.count > _internal_notificationRequestMessageIdsLimit {
links.removeFirst(links.count - _internal_notificationRequestMessageIdsLimit)
}
guard let entry = CodableEntry(NotificationRequestMessageIdLinks(links: links)) else {
return
}
transaction.putItemCacheEntry(id: notificationRequestMessageIdsEntryId, entry: entry)
}
public func _internal_getNotificationRequestMessageId(transaction: Transaction, requestIdentifier: String) -> MessageId? {
if requestIdentifier.isEmpty {
return nil
}
guard let link = loadLinks(transaction: transaction).last(where: { $0.requestIdentifier == requestIdentifier }) else {
return nil
}
return MessageId(peerId: PeerId(link.peerId), namespace: link.namespace, id: link.id)
}