|
|
|
@ -48,12 +48,28 @@ public final class LokiPublicChatPoller : NSObject {
|
|
|
|
|
|
|
|
|
|
// MARK: Polling
|
|
|
|
|
private func pollForNewMessages() {
|
|
|
|
|
// Prepare
|
|
|
|
|
let publicChat = self.publicChat
|
|
|
|
|
let userHexEncodedPublicKey = self.userHexEncodedPublicKey
|
|
|
|
|
// Processing logic for incoming messages
|
|
|
|
|
func processIncomingMessage(_ message: LokiPublicChatMessage) {
|
|
|
|
|
let _ = LokiPublicChatAPI.getMessages(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global()) { messages in
|
|
|
|
|
let uniqueHexEncodedPublicKeys = Set(messages.map { $0.hexEncodedPublicKey })
|
|
|
|
|
func proceed() {
|
|
|
|
|
let storage = OWSPrimaryStorage.shared()
|
|
|
|
|
var newDisplayNameUpdatees: Set<String> = []
|
|
|
|
|
storage.dbReadConnection.read { transaction in
|
|
|
|
|
newDisplayNameUpdatees = Set(uniqueHexEncodedPublicKeys.filter { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) != $0 }.compactMap { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) })
|
|
|
|
|
}
|
|
|
|
|
if !newDisplayNameUpdatees.isEmpty {
|
|
|
|
|
let displayNameUpdatees = LokiPublicChatAPI.displayNameUpdatees[publicChat.id] ?? []
|
|
|
|
|
LokiPublicChatAPI.displayNameUpdatees[publicChat.id] = displayNameUpdatees.union(newDisplayNameUpdatees)
|
|
|
|
|
}
|
|
|
|
|
messages.forEach { message in
|
|
|
|
|
var wasSentByCurrentUser = false
|
|
|
|
|
OWSPrimaryStorage.shared().dbReadConnection.read { transaction in
|
|
|
|
|
wasSentByCurrentUser = LokiDatabaseUtilities.isUserLinkedDevice(message.hexEncodedPublicKey, transaction: transaction)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var masterHexEncodedPublicKey: String? = nil
|
|
|
|
|
storage.dbReadConnection.read { transaction in
|
|
|
|
|
masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: message.hexEncodedPublicKey, in: transaction)
|
|
|
|
@ -122,82 +138,26 @@ public final class LokiPublicChatPoller : NSObject {
|
|
|
|
|
dataMessage.setPublicChatInfo(try! publicChatInfo.build())
|
|
|
|
|
}
|
|
|
|
|
let content = SSKProtoContent.builder()
|
|
|
|
|
if !wasSentByCurrentUser {
|
|
|
|
|
content.setDataMessage(try! dataMessage.build())
|
|
|
|
|
} else {
|
|
|
|
|
let syncMessageSentBuilder = SSKProtoSyncMessageSent.builder()
|
|
|
|
|
syncMessageSentBuilder.setMessage(try! dataMessage.build())
|
|
|
|
|
syncMessageSentBuilder.setDestination(userHexEncodedPublicKey)
|
|
|
|
|
syncMessageSentBuilder.setTimestamp(message.timestamp)
|
|
|
|
|
let syncMessageSent = try! syncMessageSentBuilder.build()
|
|
|
|
|
let syncMessageBuilder = SSKProtoSyncMessage.builder()
|
|
|
|
|
syncMessageBuilder.setSent(syncMessageSent)
|
|
|
|
|
content.setSyncMessage(try! syncMessageBuilder.build())
|
|
|
|
|
}
|
|
|
|
|
let envelope = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp)
|
|
|
|
|
envelope.setSource(senderHexEncodedPublicKey)
|
|
|
|
|
envelope.setSourceDevice(OWSDevicePrimaryDeviceId)
|
|
|
|
|
envelope.setContent(try! content.build().serializedData())
|
|
|
|
|
storage.dbReadWriteConnection.readWrite { transaction in
|
|
|
|
|
transaction.setObject(senderDisplayName, forKey: senderHexEncodedPublicKey, inCollection: publicChat.id)
|
|
|
|
|
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Processing logic for outgoing messages
|
|
|
|
|
func processOutgoingMessage(_ message: LokiPublicChatMessage) {
|
|
|
|
|
guard let messageServerID = message.serverID else { return }
|
|
|
|
|
let storage = OWSPrimaryStorage.shared()
|
|
|
|
|
var isDuplicate = false
|
|
|
|
|
storage.dbReadConnection.read { transaction in
|
|
|
|
|
let id = storage.getIDForMessage(withServerID: UInt(messageServerID), in: transaction)
|
|
|
|
|
isDuplicate = id != nil
|
|
|
|
|
}
|
|
|
|
|
guard !isDuplicate else { return }
|
|
|
|
|
let groupID = publicChat.idAsData
|
|
|
|
|
let thread = TSGroupThread.getOrCreateThread(withGroupId: groupID)
|
|
|
|
|
let signalQuote: TSQuotedMessage?
|
|
|
|
|
if let quote = message.quote {
|
|
|
|
|
signalQuote = TSQuotedMessage(timestamp: quote.quotedMessageTimestamp, authorId: quote.quoteeHexEncodedPublicKey, body: quote.quotedMessageBody, quotedAttachmentsForSending: [])
|
|
|
|
|
} else {
|
|
|
|
|
signalQuote = nil
|
|
|
|
|
}
|
|
|
|
|
var attachmentIDs: [String] = []
|
|
|
|
|
// TODO: Restore attachments
|
|
|
|
|
let signalLinkPreview: OWSLinkPreview?
|
|
|
|
|
if let linkPreview = message.attachments.first(where: { $0.kind == .linkPreview }) {
|
|
|
|
|
let attachment = TSAttachmentPointer(serverId: linkPreview.serverID, encryptionKey: nil, byteCount: UInt32(linkPreview.size), contentType: linkPreview.contentType, sourceFilename: linkPreview.fileName, caption: linkPreview.caption, albumMessageId: nil)
|
|
|
|
|
attachment.save()
|
|
|
|
|
signalLinkPreview = OWSLinkPreview(urlString: linkPreview.linkPreviewURL!, title: linkPreview.linkPreviewTitle!, imageAttachmentId: attachment.uniqueId!, isDirectAttachment: false)
|
|
|
|
|
} else {
|
|
|
|
|
signalLinkPreview = nil
|
|
|
|
|
}
|
|
|
|
|
let body = (message.body == message.timestamp.description) ? "" : message.body // Workaround for the fact that the back-end doesn't accept messages without a body
|
|
|
|
|
let signalMessage = TSOutgoingMessage(outgoingMessageWithTimestamp: message.timestamp, in: thread, messageBody: body, attachmentIds: NSMutableArray(array: attachmentIDs), expiresInSeconds: 0,
|
|
|
|
|
expireStartedAt: 0, isVoiceMessage: false, groupMetaMessage: .deliver, quotedMessage: signalQuote, contactShare: nil, linkPreview: signalLinkPreview)
|
|
|
|
|
signalMessage.actualSenderHexEncodedPublicKey = message.hexEncodedPublicKey
|
|
|
|
|
storage.dbReadWriteConnection.readWrite { transaction in
|
|
|
|
|
signalMessage.update(withSentRecipient: publicChat.server, wasSentByUD: false, transaction: transaction)
|
|
|
|
|
signalMessage.saveGroupChatServerID(messageServerID, in: transaction)
|
|
|
|
|
guard let messageID = signalMessage.uniqueId else { return print("[Loki] Failed to save public chat message.") }
|
|
|
|
|
storage.setIDForMessageWithServerID(UInt(messageServerID), to: messageID, in: transaction)
|
|
|
|
|
}
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
if let linkPreviewURL = OWSLinkPreview.previewUrl(forMessageBodyText: message.body, selectedRange: nil) {
|
|
|
|
|
signalMessage.generateLinkPreviewIfNeeded(fromURL: linkPreviewURL)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Poll
|
|
|
|
|
let _ = LokiPublicChatAPI.getMessages(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global()) { messages in
|
|
|
|
|
let uniqueHexEncodedPublicKeys = Set(messages.map { $0.hexEncodedPublicKey })
|
|
|
|
|
func proceed() {
|
|
|
|
|
let storage = OWSPrimaryStorage.shared()
|
|
|
|
|
var newDisplayNameUpdatees: Set<String> = []
|
|
|
|
|
storage.dbReadConnection.read { transaction in
|
|
|
|
|
newDisplayNameUpdatees = Set(uniqueHexEncodedPublicKeys.filter { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) != $0 }.compactMap { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) })
|
|
|
|
|
}
|
|
|
|
|
if !newDisplayNameUpdatees.isEmpty {
|
|
|
|
|
let displayNameUpdatees = LokiPublicChatAPI.displayNameUpdatees[publicChat.id] ?? []
|
|
|
|
|
LokiPublicChatAPI.displayNameUpdatees[publicChat.id] = displayNameUpdatees.union(newDisplayNameUpdatees)
|
|
|
|
|
}
|
|
|
|
|
messages.forEach { message in
|
|
|
|
|
var wasSentByCurrentUser = false
|
|
|
|
|
OWSPrimaryStorage.shared().dbReadConnection.read { transaction in
|
|
|
|
|
wasSentByCurrentUser = LokiDatabaseUtilities.isUserLinkedDevice(message.hexEncodedPublicKey, transaction: transaction)
|
|
|
|
|
}
|
|
|
|
|
if !wasSentByCurrentUser {
|
|
|
|
|
processIncomingMessage(message)
|
|
|
|
|
} else {
|
|
|
|
|
processOutgoingMessage(message)
|
|
|
|
|
let messageServerID = message.serverID
|
|
|
|
|
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: messageServerID ?? 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|