119 lines
3.6 KiB
Swift
119 lines
3.6 KiB
Swift
//
|
|
// Copyright 2026 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import LibSignalClient
|
|
|
|
/// Represents a message that can be "addressed" stably across clients.
|
|
struct AddressableMessage {
|
|
enum Author {
|
|
case aci(Aci)
|
|
case e164(E164)
|
|
}
|
|
|
|
let author: Author
|
|
let sentTimestamp: UInt64
|
|
|
|
init(author: Author, sentTimestamp: UInt64) {
|
|
self.author = author
|
|
self.sentTimestamp = sentTimestamp
|
|
}
|
|
|
|
init?(message: TSMessage, localIdentifiers: LocalIdentifiers) {
|
|
if let incomingMessage = message as? TSIncomingMessage {
|
|
self.init(incomingMessage: incomingMessage)
|
|
} else if let outgoingMessage = message as? TSOutgoingMessage {
|
|
self.init(outgoingMessage: outgoingMessage, localIdentifiers: localIdentifiers)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
init?(incomingMessage: TSIncomingMessage) {
|
|
if let authorAci = incomingMessage.authorAddress.aci {
|
|
author = .aci(authorAci)
|
|
} else if let authorE164 = incomingMessage.authorAddress.e164 {
|
|
author = .e164(authorE164)
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
sentTimestamp = incomingMessage.timestamp
|
|
}
|
|
|
|
init(outgoingMessage: TSOutgoingMessage, localIdentifiers: LocalIdentifiers) {
|
|
author = .aci(localIdentifiers.aci)
|
|
sentTimestamp = outgoingMessage.timestamp
|
|
}
|
|
|
|
init?(proto: SSKProtoAddressableMessage) {
|
|
guard proto.hasSentTimestamp, SDS.fitsInInt64(proto.sentTimestamp) else {
|
|
return nil
|
|
}
|
|
|
|
if
|
|
let authorAci = ServiceId.parseFrom(
|
|
serviceIdBinary: proto.authorServiceIDBinary,
|
|
serviceIdString: proto.authorServiceID,
|
|
) as? Aci
|
|
{
|
|
author = .aci(authorAci)
|
|
} else if let authorE164 = E164(proto.authorE164) {
|
|
author = .e164(authorE164)
|
|
} else {
|
|
return nil
|
|
}
|
|
|
|
sentTimestamp = proto.sentTimestamp
|
|
}
|
|
|
|
var asProto: SSKProtoAddressableMessage {
|
|
let protoBuilder = SSKProtoAddressableMessage.builder()
|
|
protoBuilder.setSentTimestamp(sentTimestamp)
|
|
switch author {
|
|
case .aci(let aci): protoBuilder.setAuthorServiceIDBinary(aci.serviceIdBinary)
|
|
case .e164(let e164): protoBuilder.setAuthorE164(e164.stringValue)
|
|
}
|
|
return protoBuilder.buildInfallibly()
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
enum ConversationIdentifier {
|
|
case serviceId(ServiceId)
|
|
case e164(E164)
|
|
case groupIdentifier(GroupIdentifier)
|
|
|
|
init?(proto: SSKProtoConversationIdentifier) {
|
|
if
|
|
let serviceId = ServiceId.parseFrom(
|
|
serviceIdBinary: proto.threadServiceIDBinary,
|
|
serviceIdString: proto.threadServiceID,
|
|
)
|
|
{
|
|
self = .serviceId(serviceId)
|
|
} else if let e164 = E164(proto.threadE164) {
|
|
self = .e164(e164)
|
|
} else if
|
|
let groupIdData = proto.threadGroupID,
|
|
let groupIdentifier = try? GroupIdentifier(contents: groupIdData)
|
|
{
|
|
self = .groupIdentifier(groupIdentifier)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var asProto: SSKProtoConversationIdentifier {
|
|
let protoBuilder = SSKProtoConversationIdentifier.builder()
|
|
switch self {
|
|
case .serviceId(let serviceId): protoBuilder.setThreadServiceIDBinary(serviceId.serviceIdBinary)
|
|
case .e164(let e164): protoBuilder.setThreadE164(e164.stringValue)
|
|
case .groupIdentifier(let groupIdentifier): protoBuilder.setThreadGroupID(groupIdentifier.serialize())
|
|
}
|
|
return protoBuilder.buildInfallibly()
|
|
}
|
|
}
|