You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionMessagingKit/Database/Migrations/_018_DisappearingMessagesCo...

190 lines
8.6 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import GRDB
import SessionUtilitiesKit
enum _018_DisappearingMessagesConfiguration: Migration {
static let target: TargetMigrations.Identifier = .messagingKit
static let identifier: String = "DisappearingMessagesWithTypes"
static let minExpectedRunDuration: TimeInterval = 0.1
static let createdTables: [(TableRecord & FetchableRecord).Type] = []
static func migrate(_ db: Database, using dependencies: Dependencies) throws {
try db.alter(table: "disappearingMessagesConfiguration") { t in
t.add(column: "type", .integer)
}
try db.alter(table: "contact") { t in
t.add(column: "lastKnownClientVersion", .integer)
}
/// Add index on interaction table for wasRead and variant
///
/// This is due to new disappearing messages will need some info messages to be able to be unread,
/// but we only want to count the unread message number by incoming visible messages and call messages.
try db.create(
indexOn: "interaction",
columns: ["wasRead", "variant"]
)
// If there isn't already a user account then we can just finish here (there will be no
// threads/configs to update and the configs won't be setup which would cause this to crash
guard
MigrationHelper.userExists(db),
let userEd25519SecretKey: Data = MigrationHelper.fetchIdentityValue(db, key: "ed25519SecretKey")
else { return Storage.update(progress: 1, for: self, in: target, using: dependencies) }
// Set the disappearing messages type per conversation
let userSessionId: SessionId = MigrationHelper.userSessionId(db)
let timestampMs: Int64 = Int64(dependencies.dateNow.timeIntervalSince1970 * TimeInterval(1000))
let userProfileType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterSend
let contactType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterRead
let legacyGroupType: DisappearingMessagesConfiguration.DisappearingMessageType = .disappearAfterSend
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(userProfileType.rawValue)
WHERE disappearingMessagesConfiguration.threadId = '\(userSessionId.hexString)'
""")
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(contactType.rawValue)
WHERE threadId IN (
SELECT id FROM thread WHERE variant = \(SessionThread.Variant.contact.rawValue)
)
""")
try db.execute(sql: """
UPDATE disappearingMessagesConfiguration
SET type = \(legacyGroupType.rawValue)
WHERE threadId IN (
SELECT id FROM thread WHERE variant = \(SessionThread.Variant.legacyGroup.rawValue)
)
""")
// Also need to update libSession with the new settings
let disappearingMessageInfo: [Row] = try Row.fetchAll(db, sql: """
SELECT
thread.id,
thread.variant,
disappearingMessagesConfiguration.isEnabled,
disappearingMessagesConfiguration.durationSeconds
FROM disappearingMessagesConfiguration
JOIN thread ON thread.id = disappearingMessagesConfiguration.threadId
""")
let cache: LibSession.Cache = LibSession.Cache(userSessionId: userSessionId, using: dependencies)
let userProfileConfig: LibSession.Config = try cache.loadState(
for: .userProfile,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.userProfile.rawValue)
)
let contactsConfig: LibSession.Config = try cache.loadState(
for: .contacts,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.contacts.rawValue)
)
let userGroupsConfig: LibSession.Config = try cache.loadState(
for: .userGroups,
sessionId: userSessionId,
userEd25519SecretKey: Array(userEd25519SecretKey),
groupEd25519SecretKey: nil,
cachedData: MigrationHelper.configDump(db, for: ConfigDump.Variant.userGroups.rawValue)
)
// Update the configs so the settings are synced
if let noteToSelfInfo: Row = disappearingMessageInfo.first(where: { $0["id"] == userSessionId.hexString }) {
try LibSession.updateNoteToSelf(
disappearingMessagesConfig: DisappearingMessagesConfiguration(
threadId: noteToSelfInfo["id"],
isEnabled: noteToSelfInfo["isEnabled"],
durationSeconds: noteToSelfInfo["durationSeconds"],
type: userProfileType
),
in: userProfileConfig
)
}
try LibSession.upsert(
contactData: disappearingMessageInfo
.filter {
$0["id"] != userSessionId.hexString &&
$0["variant"] == SessionThread.Variant.contact.rawValue
}
.map {
LibSession.SyncedContactInfo(
id: $0["id"],
disappearingMessagesConfig: DisappearingMessagesConfiguration(
threadId: $0["id"],
isEnabled: $0["isEnabled"],
durationSeconds: $0["durationSeconds"],
type: contactType
)
)
},
in: contactsConfig,
using: dependencies
)
try LibSession.upsert(
legacyGroups: disappearingMessageInfo
.filter { $0["variant"] == SessionThread.Variant.legacyGroup.rawValue }
.map {
LibSession.LegacyGroupInfo(
id: $0["id"],
disappearingMessageInfo: LibSession.DisappearingMessageInfo(
isEnabled: $0["isEnabled"],
durationSeconds: $0["durationSeconds"],
rawType: legacyGroupType.rawValue
)
)
},
in: userGroupsConfig
)
// Now that the state is updated we need to save the updated config dumps
if cache.configNeedsDump(userProfileConfig), let dumpData: Data = try userProfileConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('userProfile', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
if cache.configNeedsDump(contactsConfig), let dumpData: Data = try contactsConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('contacts', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
if cache.configNeedsDump(userGroupsConfig), let dumpData: Data = try userGroupsConfig.dump() {
try db.execute(
sql: """
INSERT INTO configDump (variant, publicKey, data, timestampMs)
VALUES ('userGroups', '\(userSessionId.hexString)', ?, \(timestampMs))
ON CONFLICT(variant, publicKey) DO UPDATE SET
data = ?,
timestampMs = \(timestampMs)
""",
arguments: [dumpData, dumpData]
)
}
Storage.update(progress: 1, for: self, in: target, using: dependencies)
}
}