Sketch out installed sticker classes.
This commit is contained in:
parent
970f65e980
commit
e69b7d481b
@ -1,5 +1,7 @@
|
||||
{
|
||||
"#comment": "NOTE: This file is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run `sds_codegen.sh`.",
|
||||
"InstalledSticker": 28,
|
||||
"InstalledStickerPack": 27,
|
||||
"OWSAddToContactsOfferMessage": 23,
|
||||
"OWSAddToProfileWhitelistOfferMessage": 7,
|
||||
"OWSContactOffersInteraction": 21,
|
||||
|
||||
@ -168,7 +168,7 @@ private struct OWSThumbnailRequest {
|
||||
throw OWSThumbnailError.failure(description: "Could not convert thumbnail to JPEG.")
|
||||
}
|
||||
do {
|
||||
try thumbnailData.write(to: URL(fileURLWithPath: thumbnailPath), options: .atomicWrite)
|
||||
try thumbnailData.write(to: URL(fileURLWithPath: thumbnailPath), options: .atomic)
|
||||
} catch let error as NSError {
|
||||
throw OWSThumbnailError.externalError(description: "File write failed: \(thumbnailPath), \(error)", underlyingError: error)
|
||||
}
|
||||
|
||||
@ -0,0 +1,249 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import GRDBCipher
|
||||
import SignalCoreKit
|
||||
|
||||
// NOTE: This file is generated by /Scripts/sds_codegen/sds_generate.py.
|
||||
// Do not manually edit it, instead run `sds_codegen.sh`.
|
||||
|
||||
// MARK: - SDSSerializable
|
||||
|
||||
extension InstalledSticker: SDSSerializable {
|
||||
public var serializer: SDSSerializer {
|
||||
// Any subclass can be cast to it's superclass,
|
||||
// so the order of this switch statement matters.
|
||||
// We need to do a "depth first" search by type.
|
||||
switch self {
|
||||
default:
|
||||
return InstalledStickerSerializer(model: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Table Metadata
|
||||
|
||||
extension InstalledStickerSerializer {
|
||||
|
||||
// This defines all of the columns used in the table
|
||||
// where this model (and any subclasses) are persisted.
|
||||
static let recordTypeColumn = SDSColumnMetadata(columnName: "recordType", columnType: .int, columnIndex: 0)
|
||||
static let uniqueIdColumn = SDSColumnMetadata(columnName: "uniqueId", columnType: .unicodeString, columnIndex: 1)
|
||||
// Base class properties
|
||||
static let packIdColumn = SDSColumnMetadata(columnName: "packId", columnType: .blob, columnIndex: 2)
|
||||
static let packKeyColumn = SDSColumnMetadata(columnName: "packKey", columnType: .blob, columnIndex: 3)
|
||||
static let stickerIdColumn = SDSColumnMetadata(columnName: "stickerId", columnType: .int, columnIndex: 4)
|
||||
|
||||
// TODO: We should decide on a naming convention for
|
||||
// tables that store models.
|
||||
public static let table = SDSTableMetadata(tableName: "model_InstalledSticker", columns: [
|
||||
recordTypeColumn,
|
||||
uniqueIdColumn,
|
||||
packIdColumn,
|
||||
packKeyColumn,
|
||||
stickerIdColumn
|
||||
])
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Deserialization
|
||||
|
||||
extension InstalledStickerSerializer {
|
||||
// This method defines how to deserialize a model, given a
|
||||
// database row. The recordType column is used to determine
|
||||
// the corresponding model class.
|
||||
class func sdsDeserialize(statement: SelectStatement) throws -> InstalledSticker {
|
||||
|
||||
if OWSIsDebugBuild() {
|
||||
guard statement.columnNames == table.selectColumnNames else {
|
||||
owsFailDebug("Unexpected columns: \(statement.columnNames) != \(table.selectColumnNames)")
|
||||
throw SDSError.invalidResult
|
||||
}
|
||||
}
|
||||
|
||||
// SDSDeserializer is used to convert column values into Swift values.
|
||||
let deserializer = SDSDeserializer(sqliteStatement: statement.sqliteStatement)
|
||||
let recordTypeValue = try deserializer.int(at: 0)
|
||||
guard let recordType = SDSRecordType(rawValue: UInt(recordTypeValue)) else {
|
||||
owsFailDebug("Invalid recordType: \(recordTypeValue)")
|
||||
throw SDSError.invalidResult
|
||||
}
|
||||
switch recordType {
|
||||
case .installedSticker:
|
||||
|
||||
let uniqueId = try deserializer.string(at: uniqueIdColumn.columnIndex)
|
||||
let packId = try deserializer.blob(at: packIdColumn.columnIndex)
|
||||
let packKey = try deserializer.blob(at: packKeyColumn.columnIndex)
|
||||
let stickerId = UInt32(try deserializer.int64(at: stickerIdColumn.columnIndex))
|
||||
|
||||
return InstalledSticker(uniqueId: uniqueId,
|
||||
packId: packId,
|
||||
packKey: packKey,
|
||||
stickerId: stickerId)
|
||||
|
||||
default:
|
||||
owsFail("Invalid record type \(recordType)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Save/Remove/Update
|
||||
|
||||
@objc
|
||||
extension InstalledSticker {
|
||||
@objc
|
||||
public func anySave(transaction: SDSAnyWriteTransaction) {
|
||||
switch transaction.writeTransaction {
|
||||
case .yapWrite(let ydbTransaction):
|
||||
save(with: ydbTransaction)
|
||||
case .grdbWrite(let grdbTransaction):
|
||||
SDSSerialization.save(entity: self, transaction: grdbTransaction)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func anyRemove(transaction: SDSAnyWriteTransaction) {
|
||||
switch transaction.writeTransaction {
|
||||
case .yapWrite(let ydbTransaction):
|
||||
remove(with: ydbTransaction)
|
||||
case .grdbWrite(let grdbTransaction):
|
||||
SDSSerialization.delete(entity: self, transaction: grdbTransaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - InstalledStickerCursor
|
||||
|
||||
@objc
|
||||
public class InstalledStickerCursor: NSObject {
|
||||
private let cursor: SDSCursor<InstalledSticker>
|
||||
|
||||
init(cursor: SDSCursor<InstalledSticker>) {
|
||||
self.cursor = cursor
|
||||
}
|
||||
|
||||
// TODO: Revisit error handling in this class.
|
||||
public func next() throws -> InstalledSticker? {
|
||||
return try cursor.next()
|
||||
}
|
||||
|
||||
public func all() throws -> [InstalledSticker] {
|
||||
return try cursor.all()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Obj-C Fetch
|
||||
|
||||
// TODO: We may eventually want to define some combination of:
|
||||
//
|
||||
// * fetchCursor, fetchOne, fetchAll, etc. (ala GRDB)
|
||||
// * Optional "where clause" parameters for filtering.
|
||||
// * Async flavors with completions.
|
||||
//
|
||||
// TODO: I've defined flavors that take a read transaction.
|
||||
// Or we might take a "connection" if we end up having that class.
|
||||
@objc
|
||||
extension InstalledSticker {
|
||||
public class func grdbFetchCursor(transaction: GRDBReadTransaction) -> InstalledStickerCursor {
|
||||
return InstalledStickerCursor(cursor: SDSSerialization.fetchCursor(tableMetadata: InstalledStickerSerializer.table,
|
||||
transaction: transaction,
|
||||
deserialize: InstalledStickerSerializer.sdsDeserialize))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Swift Fetch
|
||||
|
||||
extension InstalledSticker {
|
||||
public class func grdbFetchCursor(sql: String,
|
||||
arguments: [DatabaseValueConvertible]?,
|
||||
transaction: GRDBReadTransaction) -> InstalledStickerCursor {
|
||||
var statementArguments: StatementArguments?
|
||||
if let arguments = arguments {
|
||||
guard let statementArgs = StatementArguments(arguments) else {
|
||||
owsFail("Could not convert arguments.")
|
||||
}
|
||||
statementArguments = statementArgs
|
||||
}
|
||||
return InstalledStickerCursor(cursor: SDSSerialization.fetchCursor(sql: sql,
|
||||
arguments: statementArguments,
|
||||
transaction: transaction,
|
||||
deserialize: InstalledStickerSerializer.sdsDeserialize))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SDSSerializer
|
||||
|
||||
// The SDSSerializer protocol specifies how to insert and update the
|
||||
// row that corresponds to this model.
|
||||
class InstalledStickerSerializer: SDSSerializer {
|
||||
|
||||
private let model: InstalledSticker
|
||||
public required init(model: InstalledSticker) {
|
||||
self.model = model
|
||||
}
|
||||
|
||||
public func serializableColumnTableMetadata() -> SDSTableMetadata {
|
||||
return InstalledStickerSerializer.table
|
||||
}
|
||||
|
||||
public func insertColumnNames() -> [String] {
|
||||
// When we insert a new row, we include the following columns:
|
||||
//
|
||||
// * "record type"
|
||||
// * "unique id"
|
||||
// * ...all columns that we set when updating.
|
||||
return [
|
||||
InstalledStickerSerializer.recordTypeColumn.columnName,
|
||||
uniqueIdColumnName()
|
||||
] + updateColumnNames()
|
||||
|
||||
}
|
||||
|
||||
public func insertColumnValues() -> [DatabaseValueConvertible] {
|
||||
let result: [DatabaseValueConvertible] = [
|
||||
SDSRecordType.installedSticker.rawValue
|
||||
] + [uniqueIdColumnValue()] + updateColumnValues()
|
||||
if OWSIsDebugBuild() {
|
||||
if result.count != insertColumnNames().count {
|
||||
owsFailDebug("Update mismatch: \(result.count) != \(insertColumnNames().count)")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func updateColumnNames() -> [String] {
|
||||
return [
|
||||
InstalledStickerSerializer.packIdColumn,
|
||||
InstalledStickerSerializer.packKeyColumn,
|
||||
InstalledStickerSerializer.stickerIdColumn
|
||||
].map { $0.columnName }
|
||||
}
|
||||
|
||||
public func updateColumnValues() -> [DatabaseValueConvertible] {
|
||||
let result: [DatabaseValueConvertible] = [
|
||||
self.model.packId,
|
||||
self.model.packKey,
|
||||
self.model.stickerId
|
||||
|
||||
]
|
||||
if OWSIsDebugBuild() {
|
||||
if result.count != updateColumnNames().count {
|
||||
owsFailDebug("Update mismatch: \(result.count) != \(updateColumnNames().count)")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func uniqueIdColumnName() -> String {
|
||||
return InstalledStickerSerializer.uniqueIdColumn.columnName
|
||||
}
|
||||
|
||||
// TODO: uniqueId is currently an optional on our models.
|
||||
// We should probably make the return type here String?
|
||||
public func uniqueIdColumnValue() -> DatabaseValueConvertible {
|
||||
// FIXME remove force unwrap
|
||||
return model.uniqueId!
|
||||
}
|
||||
}
|
||||
40
SignalServiceKit/src/Messages/Stickers/InstalledSticker.h
Normal file
40
SignalServiceKit/src/Messages/Stickers/InstalledSticker.h
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SDSAnyReadTransaction;
|
||||
|
||||
@interface InstalledSticker : TSYapDatabaseObject
|
||||
|
||||
@property (nonatomic, readonly) NSData *packId;
|
||||
@property (nonatomic, readonly) NSData *packKey;
|
||||
@property (nonatomic, readonly) UInt32 stickerId;
|
||||
|
||||
- (instancetype)initWithPackId:(NSData *)packId packKey:(NSData *)packKey stickerId:(UInt32)stickerId;
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
// This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithUniqueId:(NSString *)uniqueId
|
||||
packId:(NSData *)packId
|
||||
packKey:(NSData *)packKey
|
||||
stickerId:(unsigned int)stickerId
|
||||
NS_SWIFT_NAME(init(uniqueId:packId:packKey:stickerId:));
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (NSString *)uniqueIdForPackId:(NSData *)packId stickerId:(UInt32)stickerId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
66
SignalServiceKit/src/Messages/Stickers/InstalledSticker.m
Normal file
66
SignalServiceKit/src/Messages/Stickers/InstalledSticker.m
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InstalledSticker.h"
|
||||
#import <SignalCoreKit/NSData+OWS.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation InstalledSticker
|
||||
|
||||
- (instancetype)initWithPackId:(NSData *)packId packKey:(NSData *)packKey stickerId:(UInt32)stickerId
|
||||
{
|
||||
OWSAssertDebug(packId.length > 0);
|
||||
OWSAssertDebug(packKey.length > 0);
|
||||
|
||||
self = [super initWithUniqueId:[InstalledSticker uniqueIdForPackId:packId stickerId:stickerId]];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_packId = packId;
|
||||
_packKey = packKey;
|
||||
_stickerId = stickerId;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
// This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithUniqueId:(NSString *)uniqueId
|
||||
packId:(NSData *)packId
|
||||
packKey:(NSData *)packKey
|
||||
stickerId:(unsigned int)stickerId
|
||||
{
|
||||
self = [super initWithUniqueId:uniqueId];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_packId = packId;
|
||||
_packKey = packKey;
|
||||
_stickerId = stickerId;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (NSString *)uniqueIdForPackId:(NSData *)packId stickerId:(UInt32)stickerId
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@.%lu", packId.hexadecimalString, (unsigned long)stickerId];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -0,0 +1,243 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import GRDBCipher
|
||||
import SignalCoreKit
|
||||
|
||||
// NOTE: This file is generated by /Scripts/sds_codegen/sds_generate.py.
|
||||
// Do not manually edit it, instead run `sds_codegen.sh`.
|
||||
|
||||
// MARK: - SDSSerializable
|
||||
|
||||
extension InstalledStickerPack: SDSSerializable {
|
||||
public var serializer: SDSSerializer {
|
||||
// Any subclass can be cast to it's superclass,
|
||||
// so the order of this switch statement matters.
|
||||
// We need to do a "depth first" search by type.
|
||||
switch self {
|
||||
default:
|
||||
return InstalledStickerPackSerializer(model: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Table Metadata
|
||||
|
||||
extension InstalledStickerPackSerializer {
|
||||
|
||||
// This defines all of the columns used in the table
|
||||
// where this model (and any subclasses) are persisted.
|
||||
static let recordTypeColumn = SDSColumnMetadata(columnName: "recordType", columnType: .int, columnIndex: 0)
|
||||
static let uniqueIdColumn = SDSColumnMetadata(columnName: "uniqueId", columnType: .unicodeString, columnIndex: 1)
|
||||
// Base class properties
|
||||
static let packIdColumn = SDSColumnMetadata(columnName: "packId", columnType: .blob, columnIndex: 2)
|
||||
static let packKeyColumn = SDSColumnMetadata(columnName: "packKey", columnType: .blob, columnIndex: 3)
|
||||
|
||||
// TODO: We should decide on a naming convention for
|
||||
// tables that store models.
|
||||
public static let table = SDSTableMetadata(tableName: "model_InstalledStickerPack", columns: [
|
||||
recordTypeColumn,
|
||||
uniqueIdColumn,
|
||||
packIdColumn,
|
||||
packKeyColumn
|
||||
])
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Deserialization
|
||||
|
||||
extension InstalledStickerPackSerializer {
|
||||
// This method defines how to deserialize a model, given a
|
||||
// database row. The recordType column is used to determine
|
||||
// the corresponding model class.
|
||||
class func sdsDeserialize(statement: SelectStatement) throws -> InstalledStickerPack {
|
||||
|
||||
if OWSIsDebugBuild() {
|
||||
guard statement.columnNames == table.selectColumnNames else {
|
||||
owsFailDebug("Unexpected columns: \(statement.columnNames) != \(table.selectColumnNames)")
|
||||
throw SDSError.invalidResult
|
||||
}
|
||||
}
|
||||
|
||||
// SDSDeserializer is used to convert column values into Swift values.
|
||||
let deserializer = SDSDeserializer(sqliteStatement: statement.sqliteStatement)
|
||||
let recordTypeValue = try deserializer.int(at: 0)
|
||||
guard let recordType = SDSRecordType(rawValue: UInt(recordTypeValue)) else {
|
||||
owsFailDebug("Invalid recordType: \(recordTypeValue)")
|
||||
throw SDSError.invalidResult
|
||||
}
|
||||
switch recordType {
|
||||
case .installedStickerPack:
|
||||
|
||||
let uniqueId = try deserializer.string(at: uniqueIdColumn.columnIndex)
|
||||
let packId = try deserializer.blob(at: packIdColumn.columnIndex)
|
||||
let packKey = try deserializer.blob(at: packKeyColumn.columnIndex)
|
||||
|
||||
return InstalledStickerPack(uniqueId: uniqueId,
|
||||
packId: packId,
|
||||
packKey: packKey)
|
||||
|
||||
default:
|
||||
owsFail("Invalid record type \(recordType)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Save/Remove/Update
|
||||
|
||||
@objc
|
||||
extension InstalledStickerPack {
|
||||
@objc
|
||||
public func anySave(transaction: SDSAnyWriteTransaction) {
|
||||
switch transaction.writeTransaction {
|
||||
case .yapWrite(let ydbTransaction):
|
||||
save(with: ydbTransaction)
|
||||
case .grdbWrite(let grdbTransaction):
|
||||
SDSSerialization.save(entity: self, transaction: grdbTransaction)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func anyRemove(transaction: SDSAnyWriteTransaction) {
|
||||
switch transaction.writeTransaction {
|
||||
case .yapWrite(let ydbTransaction):
|
||||
remove(with: ydbTransaction)
|
||||
case .grdbWrite(let grdbTransaction):
|
||||
SDSSerialization.delete(entity: self, transaction: grdbTransaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - InstalledStickerPackCursor
|
||||
|
||||
@objc
|
||||
public class InstalledStickerPackCursor: NSObject {
|
||||
private let cursor: SDSCursor<InstalledStickerPack>
|
||||
|
||||
init(cursor: SDSCursor<InstalledStickerPack>) {
|
||||
self.cursor = cursor
|
||||
}
|
||||
|
||||
// TODO: Revisit error handling in this class.
|
||||
public func next() throws -> InstalledStickerPack? {
|
||||
return try cursor.next()
|
||||
}
|
||||
|
||||
public func all() throws -> [InstalledStickerPack] {
|
||||
return try cursor.all()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Obj-C Fetch
|
||||
|
||||
// TODO: We may eventually want to define some combination of:
|
||||
//
|
||||
// * fetchCursor, fetchOne, fetchAll, etc. (ala GRDB)
|
||||
// * Optional "where clause" parameters for filtering.
|
||||
// * Async flavors with completions.
|
||||
//
|
||||
// TODO: I've defined flavors that take a read transaction.
|
||||
// Or we might take a "connection" if we end up having that class.
|
||||
@objc
|
||||
extension InstalledStickerPack {
|
||||
public class func grdbFetchCursor(transaction: GRDBReadTransaction) -> InstalledStickerPackCursor {
|
||||
return InstalledStickerPackCursor(cursor: SDSSerialization.fetchCursor(tableMetadata: InstalledStickerPackSerializer.table,
|
||||
transaction: transaction,
|
||||
deserialize: InstalledStickerPackSerializer.sdsDeserialize))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Swift Fetch
|
||||
|
||||
extension InstalledStickerPack {
|
||||
public class func grdbFetchCursor(sql: String,
|
||||
arguments: [DatabaseValueConvertible]?,
|
||||
transaction: GRDBReadTransaction) -> InstalledStickerPackCursor {
|
||||
var statementArguments: StatementArguments?
|
||||
if let arguments = arguments {
|
||||
guard let statementArgs = StatementArguments(arguments) else {
|
||||
owsFail("Could not convert arguments.")
|
||||
}
|
||||
statementArguments = statementArgs
|
||||
}
|
||||
return InstalledStickerPackCursor(cursor: SDSSerialization.fetchCursor(sql: sql,
|
||||
arguments: statementArguments,
|
||||
transaction: transaction,
|
||||
deserialize: InstalledStickerPackSerializer.sdsDeserialize))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SDSSerializer
|
||||
|
||||
// The SDSSerializer protocol specifies how to insert and update the
|
||||
// row that corresponds to this model.
|
||||
class InstalledStickerPackSerializer: SDSSerializer {
|
||||
|
||||
private let model: InstalledStickerPack
|
||||
public required init(model: InstalledStickerPack) {
|
||||
self.model = model
|
||||
}
|
||||
|
||||
public func serializableColumnTableMetadata() -> SDSTableMetadata {
|
||||
return InstalledStickerPackSerializer.table
|
||||
}
|
||||
|
||||
public func insertColumnNames() -> [String] {
|
||||
// When we insert a new row, we include the following columns:
|
||||
//
|
||||
// * "record type"
|
||||
// * "unique id"
|
||||
// * ...all columns that we set when updating.
|
||||
return [
|
||||
InstalledStickerPackSerializer.recordTypeColumn.columnName,
|
||||
uniqueIdColumnName()
|
||||
] + updateColumnNames()
|
||||
|
||||
}
|
||||
|
||||
public func insertColumnValues() -> [DatabaseValueConvertible] {
|
||||
let result: [DatabaseValueConvertible] = [
|
||||
SDSRecordType.installedStickerPack.rawValue
|
||||
] + [uniqueIdColumnValue()] + updateColumnValues()
|
||||
if OWSIsDebugBuild() {
|
||||
if result.count != insertColumnNames().count {
|
||||
owsFailDebug("Update mismatch: \(result.count) != \(insertColumnNames().count)")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func updateColumnNames() -> [String] {
|
||||
return [
|
||||
InstalledStickerPackSerializer.packIdColumn,
|
||||
InstalledStickerPackSerializer.packKeyColumn
|
||||
].map { $0.columnName }
|
||||
}
|
||||
|
||||
public func updateColumnValues() -> [DatabaseValueConvertible] {
|
||||
let result: [DatabaseValueConvertible] = [
|
||||
self.model.packId,
|
||||
self.model.packKey
|
||||
|
||||
]
|
||||
if OWSIsDebugBuild() {
|
||||
if result.count != updateColumnNames().count {
|
||||
owsFailDebug("Update mismatch: \(result.count) != \(updateColumnNames().count)")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func uniqueIdColumnName() -> String {
|
||||
return InstalledStickerPackSerializer.uniqueIdColumn.columnName
|
||||
}
|
||||
|
||||
// TODO: uniqueId is currently an optional on our models.
|
||||
// We should probably make the return type here String?
|
||||
public func uniqueIdColumnValue() -> DatabaseValueConvertible {
|
||||
// FIXME remove force unwrap
|
||||
return model.uniqueId!
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface InstalledStickerPack : TSYapDatabaseObject
|
||||
|
||||
@property (nonatomic, readonly) NSData *packId;
|
||||
@property (nonatomic, readonly) NSData *packKey;
|
||||
|
||||
- (instancetype)initWithPackId:(NSData *)packId packKey:(NSData *)packKey;
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
// This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithUniqueId:(NSString *)uniqueId
|
||||
packId:(NSData *)packId
|
||||
packKey:(NSData *)packKey
|
||||
NS_SWIFT_NAME(init(uniqueId:packId:packKey:));
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (NSString *)uniqueIdForPackId:(NSData *)packId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InstalledStickerPack.h"
|
||||
#import <SignalCoreKit/NSData+OWS.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation InstalledStickerPack
|
||||
|
||||
- (instancetype)initWithPackId:(NSData *)packId packKey:(NSData *)packKey
|
||||
{
|
||||
OWSAssertDebug(packId.length > 0);
|
||||
OWSAssertDebug(packKey.length > 0);
|
||||
|
||||
self = [super initWithUniqueId:[InstalledStickerPack uniqueIdForPackId:packId]];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_packId = packId;
|
||||
_packKey = packKey;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
// This snippet is generated by /Scripts/sds_codegen/sds_generate.py. Do not manually edit it, instead run
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithUniqueId:(NSString *)uniqueId
|
||||
packId:(NSData *)packId
|
||||
packKey:(NSData *)packKey
|
||||
{
|
||||
self = [super initWithUniqueId:uniqueId];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_packId = packId;
|
||||
_packKey = packKey;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (NSString *)uniqueIdForPackId:(NSData *)packId
|
||||
{
|
||||
return packId.hexadecimalString;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
113
SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift
Normal file
113
SignalServiceKit/src/Messages/Stickers/InstalledStickers.swift
Normal file
@ -0,0 +1,113 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
|
||||
@objc
|
||||
public class InstalledStickers: NSObject {
|
||||
|
||||
private static var databaseStorage: SDSDatabaseStorage {
|
||||
return SDSDatabaseStorage.shared
|
||||
}
|
||||
|
||||
public static let collection = "InstalledStickers"
|
||||
|
||||
private let store = SDSKeyValueStore(collection: InstalledStickers.collection)
|
||||
|
||||
private override init() {}
|
||||
|
||||
// MARK: - Paths
|
||||
|
||||
@objc
|
||||
public class func cacheDirUrl() -> URL {
|
||||
var url = URL(fileURLWithPath: OWSFileSystem.appSharedDataDirectoryPath())
|
||||
url.appendPathComponent("InstalledStickers")
|
||||
OWSFileSystem.ensureDirectoryExists(url.path)
|
||||
return url
|
||||
}
|
||||
|
||||
private class func stickerUrl(packId: Data,
|
||||
stickerId: UInt32) -> URL {
|
||||
assert(packId.count > 0)
|
||||
|
||||
let uniqueId = InstalledSticker.uniqueId(forPackId: packId, stickerId: stickerId)
|
||||
|
||||
var url = cacheDirUrl()
|
||||
// All stickers are .webp.
|
||||
url.appendPathComponent("\(uniqueId).webp")
|
||||
return url
|
||||
}
|
||||
|
||||
// MARK: - Internal Methods
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public class func fetchInstalledSticker(packId: Data,
|
||||
stickerId: UInt32,
|
||||
transaction: SDSAnyReadTransaction) -> InstalledSticker? {
|
||||
assert(packId.count > 0)
|
||||
|
||||
let uniqueId = InstalledSticker.uniqueId(forPackId: packId, stickerId: stickerId)
|
||||
|
||||
switch transaction.readTransaction {
|
||||
case .yapRead(let ydbTransaction):
|
||||
return InstalledSticker.fetch(uniqueId: uniqueId, transaction: ydbTransaction)
|
||||
case .grdbRead(let grdbTransaction):
|
||||
let tableMetadata = InstalledStickerSerializer.table
|
||||
let columnNames: [String] = tableMetadata.selectColumnNames
|
||||
let columnsSQL: String = columnNames.map { $0.quotedDatabaseIdentifier }.joined(separator: ", ")
|
||||
let tableName: String = tableMetadata.tableName
|
||||
let uniqueIdColumnName: String = InstalledStickerSerializer.uniqueIdColumn.columnName
|
||||
let sql: String = "SELECT \(columnsSQL) FROM \(tableName.quotedDatabaseIdentifier) WHERE \(uniqueIdColumnName.quotedDatabaseIdentifier) == ?"
|
||||
|
||||
let cursor = InstalledSticker.grdbFetchCursor(sql: sql,
|
||||
arguments: [uniqueId],
|
||||
transaction: grdbTransaction)
|
||||
do {
|
||||
return try cursor.next()
|
||||
} catch {
|
||||
owsFailDebug("error: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func installSticker(packId: Data,
|
||||
packKey: Data,
|
||||
stickerId: UInt32,
|
||||
stickerData: Data) {
|
||||
assert(packId.count > 0)
|
||||
assert(packKey.count > 0)
|
||||
assert(stickerData.count > 0)
|
||||
|
||||
var result: InstalledSticker?
|
||||
databaseStorage.readSwallowingErrors { (transaction) in
|
||||
if let installedSticker = fetchInstalledSticker(packId: packId, stickerId: stickerId, transaction: transaction) {
|
||||
result = installedSticker
|
||||
}
|
||||
}
|
||||
if result != nil {
|
||||
// Sticker already installed, skip.
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.global().async {
|
||||
let url = stickerUrl(packId: packId, stickerId: stickerId)
|
||||
do {
|
||||
try stickerData.write(to: url, options: .atomic)
|
||||
} catch let error as NSError {
|
||||
owsFailDebug("File write failed: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
databaseStorage.writeSwallowingErrors { (transaction) in
|
||||
let installedSticker = InstalledSticker(packId: packId, packKey: packKey, stickerId: stickerId)
|
||||
installedSticker.anySave(transaction: transaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,18 +5,20 @@
|
||||
// Any Obj-c used by SSK Swift must be imported.
|
||||
#import <Reachability/Reachability.h>
|
||||
#import <SignalServiceKit/ContactsManagerProtocol.h>
|
||||
#import <SignalServiceKit/InstalledSticker.h>
|
||||
#import <SignalServiceKit/InstalledStickerPack.h>
|
||||
#import <SignalServiceKit/NotificationsProtocol.h>
|
||||
#import <SignalServiceKit/OWSBatchMessageProcessor.h>
|
||||
#import <SignalServiceKit/OWSFileSystem.h>
|
||||
#import <SignalServiceKit/OWSMessageReceiver.h>
|
||||
#import <SignalServiceKit/OWSOperation.h>
|
||||
#import <SignalServiceKit/OWSReadReceiptManager.h>
|
||||
#import <SignalServiceKit/OWSSyncManagerProtocol.h>
|
||||
#import <SignalServiceKit/SSKJobRecord.h>
|
||||
#import <SignalServiceKit/TSAttachment.h>
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <SignalServiceKit/TSGroupModel.h>
|
||||
#import <SignalServiceKit/TSGroupThread.h>
|
||||
#import <SignalServiceKit/TSOutgoingMessage.h>
|
||||
#import <SignalServiceKit/TSThread.h>
|
||||
#import <SignalServiceKit/TSYapDatabaseObject.h>
|
||||
#import <SignalServiceKit/TSAttachment.h>
|
||||
#import <SignalServiceKit/OWSBatchMessageProcessor.h>
|
||||
#import <SignalServiceKit/OWSReadReceiptManager.h>
|
||||
#import <SignalServiceKit/OWSMessageReceiver.h>
|
||||
|
||||
@ -18,10 +18,6 @@ public class SDSKeyValueStore: NSObject {
|
||||
return SDSDatabaseStorage.shared
|
||||
}
|
||||
|
||||
private var primaryStorage: OWSPrimaryStorage {
|
||||
return OWSPrimaryStorage.shared()
|
||||
}
|
||||
|
||||
// By default, all reads/writes use this collection.
|
||||
public let collection: String
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@ import SignalCoreKit
|
||||
|
||||
@objc
|
||||
public enum SDSRecordType: UInt {
|
||||
case installedSticker = 28
|
||||
case installedStickerPack = 27
|
||||
case addToContactsOfferMessage = 23
|
||||
case addToProfileWhitelistOfferMessage = 7
|
||||
case contactOffersInteraction = 21
|
||||
|
||||
Loading…
Reference in New Issue
Block a user