Added in a migration to create the user profile config and trigger a sync

# Conflicts:
#	Session.xcodeproj/project.pbxproj
pull/856/head
Morgan Pretty 2 years ago
parent d03d2ce8ab
commit f721178b49

@ -785,6 +785,7 @@
FD8ECF852934508B00C0D1BB /* BatchResponseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF842934508B00C0D1BB /* BatchResponseSpec.swift */; };
FD8ECF8629346DA100C0D1BB /* HeaderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C906127E411AF00CD579F /* HeaderSpec.swift */; };
FD8ECF8729346DB500C0D1BB /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C906327E4122F00CD579F /* RequestSpec.swift */; };
FD8ECF892935AB7200C0D1BB /* SessionUtilError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */; };
FD90040F2818AB6D00ABAAF6 /* GetSnodePoolJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */; };
FD9004122818ABDC00ABAAF6 /* Job.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73F280402C4004C14C5 /* Job.swift */; };
FD9004142818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */; };
@ -1905,6 +1906,7 @@
FD8ECF7E2934298100C0D1BB /* SharedConfigDump.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedConfigDump.swift; sourceTree = "<group>"; };
FD8ECF812934387A00C0D1BB /* ConfigUserProfileSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigUserProfileSpec.swift; sourceTree = "<group>"; };
FD8ECF842934508B00C0D1BB /* BatchResponseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchResponseSpec.swift; sourceTree = "<group>"; };
FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionUtilError.swift; sourceTree = "<group>"; };
FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSnodePoolJob.swift; sourceTree = "<group>"; };
FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
FDA8EAFD280E8B78002B68E5 /* FailedMessageSendsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedMessageSendsJob.swift; sourceTree = "<group>"; };
@ -4027,6 +4029,7 @@
children = (
FD8ECF7829340F7100C0D1BB /* libsession-util.xcframework */,
FD8ECF7A29340FFD00C0D1BB /* SessionUtil.swift */,
FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */,
);
path = LibSessionUtil;
sourceTree = "<group>";
@ -5564,6 +5567,8 @@
FD245C59285065FC00B966DD /* ControlMessage.swift in Sources */,
B8DE1FB626C22FCB0079C9CE /* CallMessage.swift in Sources */,
FD245C50285065C700B966DD /* VisibleMessage+Quote.swift in Sources */,
FD8ECF892935AB7200C0D1BB /* SessionUtilError.swift in Sources */,
FD8ECF42292B340D00C0D1BB /* SOGSBatchRequest.swift in Sources */,
FD5C7307284F103B0029977D /* MessageReceiver+MessageRequests.swift in Sources */,
C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */,
FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */,

@ -27,7 +27,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// MARK: - Lifecycle
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
SessionUtil.loadState() // TODO: Remove this (move to 'Configuration'? Or call directly as part of 'AppSetup'?)
// These should be the first things we do (the startup process can fail without them)
SetCurrentAppContext(MainAppContext())
verifyDBKeysAvailableBeforeBackgroundLaunch()

@ -13,7 +13,7 @@ internal struct ConfigDump: Codable, Equatable, Hashable, Identifiable, Fetchabl
case data
}
enum Variant: String, Codable, DatabaseValueConvertible {
enum Variant: String, Codable, DatabaseValueConvertible, CaseIterable {
case userProfile
}

@ -5,74 +5,140 @@ import GRDB
import SessionUtil
import SessionUtilitiesKit
/*internal*/public enum SessionUtil { // TODO: Rename this to be cleaner?
/*internal*/public enum SessionUtil {
typealias ConfResult = (needsPush: Bool, needsDump: Bool)
// MARK: - Configs
private static var userProfileConfig: Atomic<UnsafeMutablePointer<config_object>?> = Atomic(nil)
// MARK: - Variables
public static var needsSync: Bool {
return ConfigDump.Variant.allCases.contains { variant in
switch variant {
case .userProfile:
return (userProfileConfig.wrappedValue.map { config_needs_push($0) } ?? false)
}
}
}
// MARK: - Loading
/*internal*/public static func loadState() {
SessionUtil.userProfileConfig.mutate { $0 = loadState(for: .userProfile) }
}
private static func loadState(for variant: ConfigDump.Variant) -> UnsafeMutablePointer<config_object>? {
// Load any
let storedDump: Data? = Storage.shared
.read { db in try ConfigDump.fetchOne(db, id: .userProfile) }?
.read { db in try ConfigDump.fetchOne(db, id: variant) }?
.data
var dump: UnsafePointer<CChar>? = nil // TODO: Load from DB/Disk
let dumpLen: size_t = 0
var conf: UnsafeMutablePointer<config_object>? = nil
// var confSetup: UnsafeMutablePointer<UnsafeMutablePointer<config_object>?>? = nil
var error: UnsafeMutablePointer<CChar>? = nil
// TODO: Will need to manually release any unsafe pointers
let result = user_profile_init(&conf, dump, dumpLen, error)
guard result == 0 else { return } // TODO: Throw error
// var conf: UnsafeMutablePointer<config_object>? = confSetup?.pointee
user_profile_set_name(conf, "TestName") // TODO: Confirm success
let profileUrl: [CChar] = "http://example.org/omg-pic-123.bmp".bytes.map { CChar(bitPattern: $0) }
let profileKey: [CChar] = "secretNOTSECRET".bytes.map { CChar(bitPattern: $0) }
let profilePic: user_profile_pic = profileUrl.withUnsafeBufferPointer { profileUrlPtr in
profileKey.withUnsafeBufferPointer { profileKeyPtr in
user_profile_pic(
url: profileUrlPtr.baseAddress,
key: profileKeyPtr.baseAddress,
keylen: profileKey.count
return try? loadState(for: variant, cachedData: storedDump)
}
internal static func loadState(
for variant: ConfigDump.Variant,
cachedData: Data? = nil
) throws -> UnsafeMutablePointer<config_object>? {
// Setup initial variables (including getting the memory address for any cached data)
var conf: UnsafeMutablePointer<config_object>? = nil
let error: UnsafeMutablePointer<CChar>? = nil
let cachedDump: (data: UnsafePointer<CChar>, length: Int)? = cachedData?.withUnsafeBytes { unsafeBytes in
return unsafeBytes.baseAddress.map {
(
$0.assumingMemoryBound(to: CChar.self),
unsafeBytes.count
)
}
}
user_profile_set_pic(conf, profilePic) // TODO: Confirm success
if config_needs_push(conf) {
print("Needs Push!!!")
// No need to deallocate the `cachedDump.data` as it'll automatically be cleaned up by
// the `cachedData` lifecycle, but need to deallocate the `error` if it gets set
defer {
error?.deallocate()
}
if config_needs_dump(conf) {
print("Needs Dump!!!")
}
// Try to create the object
let result: Int32 = {
switch variant {
case .userProfile:
return user_profile_init(&conf, cachedDump?.data, (cachedDump?.length ?? 0), error)
}
}()
var toPush: UnsafeMutablePointer<CChar>? = nil
var pushLen: Int = 0
let seqNo = config_push(conf, &toPush, &pushLen)
guard result == 0 else {
let errorString: String = (error.map { String(cString: $0) } ?? "unknown error")
SNLog("[SessionUtil Error] Unable to create \(variant.rawValue) config object: \(errorString)")
throw SessionUtilError.unableToCreateConfigObject
}
//var remoteAddr: [CChar] = remote.bytes.map { CChar(bitPattern: $0) }
//config_dump(conf, &dump1, &dump1len);
return conf
}
internal static func saveState(
_ db: Database,
conf: UnsafeMutablePointer<config_object>?,
for variant: ConfigDump.Variant
) throws {
guard conf != nil else { throw SessionUtilError.nilConfigObject }
free(toPush) // TODO: Confirm
// If it doesn't need a dump then do nothing
guard config_needs_dump(conf) else { return }
var dumpResult: UnsafeMutablePointer<CChar>? = nil
var dumpResultLen: Int = 0
config_dump(conf, &dumpResult, &dumpResultLen)
print("RAWR")
let str = String(cString: dumpResult!)
let stryBytes = str.bytes
let hexStr = stryBytes.toHexString()
let data = Data(bytes: dumpResult!, count: dumpResultLen)
// dumpResult.
// Storage.shared.write { db in
// try ConfigDump(variant: .userProfile, data: <#T##Data#>)
// .save(db)
// }
//
print("RAWR2")
guard let dumpResult: UnsafeMutablePointer<CChar> = dumpResult else { return }
let dumpData: Data = Data(bytes: dumpResult, count: dumpResultLen)
dumpResult.deallocate()
try ConfigDump(
variant: variant,
data: dumpData
)
.save(db)
}
// MARK: - UserProfile
internal static func update(
conf: UnsafeMutablePointer<config_object>?,
with profile: Profile
) throws -> ConfResult {
guard conf != nil else { throw SessionUtilError.nilConfigObject }
// Update the name
user_profile_set_name(conf, profile.name)
let profilePic: user_profile_pic? = profile.profilePictureUrl?
.bytes
.map { CChar(bitPattern: $0) }
.withUnsafeBufferPointer { profileUrlPtr in
let profileKey: [CChar]? = profile.profileEncryptionKey?
.keyData
.bytes
.map { CChar(bitPattern: $0) }
return profileKey?.withUnsafeBufferPointer { profileKeyPtr in
user_profile_pic(
url: profileUrlPtr.baseAddress,
key: profileKeyPtr.baseAddress,
keylen: (profileKey?.count ?? 0)
)
}
}
if let profilePic: user_profile_pic = profilePic {
user_profile_set_pic(conf, profilePic)
}
//String(cString: dumpResult!)
return (
needsPush: config_needs_push(conf),
needsDump: config_needs_dump(conf)
)
}
}

@ -0,0 +1,8 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
public enum SessionUtilError: Error {
case unableToCreateConfigObject
case nilConfigObject
}

@ -8,6 +8,17 @@ extension Collection {
}
}
public extension Collection {
/// This creates an UnsafeMutableBufferPointer to access data in memory directly. This result pointer provides no automated
/// memory management so after use you are responsible for handling the life cycle and need to call `deallocate()`.
func unsafeCopy() -> UnsafeMutableBufferPointer<Element> {
let copy = UnsafeMutableBufferPointer<Element>.allocate(capacity: self.underestimatedCount)
_ = copy.initialize(from: self)
return copy
}
}
public extension Collection where Element == [CChar] {
/// This creates an array of UnsafePointer types to access data of the C strings in memory. This array provides no automated
/// memory management of it's children so after use you are responsible for handling the life cycle of the child elements and

@ -74,8 +74,13 @@ public enum AppSetup {
],
onProgressUpdate: migrationProgressChanged,
onComplete: { result, needsConfigSync in
// After the migrations have run but before the migration completion we load the
// SessionUtil state and update the 'needsConfigSync' flag based on whether the
// configs also need to be sync'ed
SessionUtil.loadState()
DispatchQueue.main.async {
migrationsCompletion(result, needsConfigSync)
migrationsCompletion(result, (needsConfigSync || SessionUtil.needsSync))
// The 'if' is only there to prevent the "variable never read" warning from showing
if backgroundTask != nil { backgroundTask = nil }

Loading…
Cancel
Save