157 lines
4.9 KiB
Swift
157 lines
4.9 KiB
Swift
//
|
|
// Copyright 2024 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public struct MessageStickerDataSource {
|
|
public let info: StickerInfo
|
|
public let emoji: String?
|
|
public let source: AttachmentDataSource
|
|
}
|
|
|
|
public struct ValidatedMessageStickerProto {
|
|
public let sticker: MessageSticker
|
|
public let proto: SSKProtoAttachmentPointer
|
|
}
|
|
|
|
public struct ValidatedMessageStickerDataSource {
|
|
public let sticker: MessageSticker
|
|
public let attachmentDataSource: AttachmentDataSource
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public protocol MessageStickerManager {
|
|
|
|
func buildValidatedMessageSticker(
|
|
from proto: SSKProtoDataMessageSticker,
|
|
) throws -> ValidatedMessageStickerProto
|
|
|
|
func buildDataSource(
|
|
fromDraft: MessageStickerDraft,
|
|
) async throws -> MessageStickerDataSource
|
|
|
|
func validateMessageSticker(
|
|
dataSource: MessageStickerDataSource,
|
|
) throws -> ValidatedMessageStickerDataSource
|
|
|
|
func buildProtoForSending(
|
|
_ messageSticker: MessageSticker,
|
|
parentMessage: TSMessage,
|
|
tx: DBReadTransaction,
|
|
) throws -> SSKProtoDataMessageSticker
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
class MessageStickerManagerImpl: MessageStickerManager {
|
|
|
|
private let attachmentStore: AttachmentStore
|
|
private let attachmentValidator: AttachmentContentValidator
|
|
|
|
init(
|
|
attachmentStore: AttachmentStore,
|
|
attachmentValidator: AttachmentContentValidator,
|
|
) {
|
|
self.attachmentStore = attachmentStore
|
|
self.attachmentValidator = attachmentValidator
|
|
}
|
|
|
|
func buildValidatedMessageSticker(
|
|
from stickerProto: SSKProtoDataMessageSticker,
|
|
) throws -> ValidatedMessageStickerProto {
|
|
let packID: Data = stickerProto.packID
|
|
let packKey: Data = stickerProto.packKey
|
|
let stickerID: UInt32 = stickerProto.stickerID
|
|
let emoji: String? = stickerProto.emoji
|
|
let attachmentProto: SSKProtoAttachmentPointer = stickerProto.data
|
|
let stickerInfo = StickerInfo(packId: packID, packKey: packKey, stickerId: stickerID)
|
|
|
|
let messageSticker = MessageSticker(info: stickerInfo, emoji: emoji)
|
|
guard messageSticker.isValid else {
|
|
throw StickerError.invalidInput
|
|
}
|
|
|
|
if attachmentProto.contentType == nil || attachmentProto.contentType == MimeType.applicationOctetStream.rawValue {
|
|
let builder = attachmentProto.asBuilder()
|
|
builder.setContentType(MimeType.imageWebp.rawValue)
|
|
|
|
return ValidatedMessageStickerProto(
|
|
sticker: messageSticker,
|
|
proto: builder.buildInfallibly(),
|
|
)
|
|
} else {
|
|
return ValidatedMessageStickerProto(
|
|
sticker: messageSticker,
|
|
proto: attachmentProto,
|
|
)
|
|
}
|
|
}
|
|
|
|
func buildDataSource(
|
|
fromDraft draft: MessageStickerDraft,
|
|
) async throws -> MessageStickerDataSource {
|
|
let validatedDataSource = try await attachmentValidator.validateDataContents(
|
|
draft.stickerData,
|
|
mimeType: draft.stickerType.mimeType,
|
|
renderingFlag: .default,
|
|
sourceFilename: nil,
|
|
)
|
|
return MessageStickerDataSource(
|
|
info: draft.info,
|
|
emoji: draft.emoji,
|
|
source: .pendingAttachment(validatedDataSource),
|
|
)
|
|
}
|
|
|
|
func validateMessageSticker(
|
|
dataSource: MessageStickerDataSource,
|
|
) throws -> ValidatedMessageStickerDataSource {
|
|
let messageSticker = MessageSticker(info: dataSource.info, emoji: dataSource.emoji)
|
|
guard messageSticker.isValid else {
|
|
throw StickerError.invalidInput
|
|
}
|
|
|
|
return ValidatedMessageStickerDataSource(
|
|
sticker: messageSticker,
|
|
attachmentDataSource: dataSource.source,
|
|
)
|
|
}
|
|
|
|
func buildProtoForSending(
|
|
_ messageSticker: MessageSticker,
|
|
parentMessage: TSMessage,
|
|
tx: DBReadTransaction,
|
|
) throws -> SSKProtoDataMessageSticker {
|
|
|
|
guard
|
|
let parentMessageRowId = parentMessage.sqliteRowId,
|
|
let referencedAttachment = attachmentStore.fetchAnyReferencedAttachment(
|
|
for: .messageSticker(messageRowId: parentMessageRowId),
|
|
tx: tx,
|
|
)
|
|
else {
|
|
throw OWSAssertionError("Could not find sticker attachment")
|
|
}
|
|
|
|
guard let attachmentProto = referencedAttachment.asProtoForSending() else {
|
|
throw OWSAssertionError("Failed to make proto for sending from attachment!")
|
|
}
|
|
|
|
let protoBuilder = SSKProtoDataMessageSticker.builder(
|
|
packID: messageSticker.packId,
|
|
packKey: messageSticker.packKey,
|
|
stickerID: messageSticker.stickerId,
|
|
data: attachmentProto,
|
|
)
|
|
|
|
if let emoji = messageSticker.emoji?.nilIfEmpty {
|
|
protoBuilder.setEmoji(emoji)
|
|
}
|
|
|
|
return try protoBuilder.build()
|
|
}
|
|
}
|