Updated to the latest libSession and updated it's error handling

pull/976/head
Morgan Pretty 10 months ago
parent d1a4683bc3
commit b0eec5a4c2

@ -1 +1 @@
Subproject commit d0b03ecf7d17e365edb077d888e926c88ef5d593
Subproject commit ea1b1dfcf6b0a6ad6e2359df3c296935e695afc8

@ -44,6 +44,7 @@ extension ProjectState {
.contains("Log.warn(", caseSensitive: false),
.contains("Log.error(", caseSensitive: false),
.contains("Log.critical(", caseSensitive: false),
.contains("logMessage:", caseSensitive: false),
.contains("owsFailDebug(", caseSensitive: false),
.contains("#imageLiteral(resourceName:", caseSensitive: false),
.contains("UIImage(named:", caseSensitive: false),

@ -586,8 +586,6 @@
FD2B4AFF2946C93200AB4848 /* ConfigurationSyncJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD2B4AFE2946C93200AB4848 /* ConfigurationSyncJob.swift */; };
FD2B4B042949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD2B4B032949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift */; };
FD3003662A25D5B300B5A5FB /* ConfigMessageReceiveJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3003652A25D5B300B5A5FB /* ConfigMessageReceiveJob.swift */; };
FD30036A2A3ADEC100B5A5FB /* CExceptionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = FD3003692A3ADD6000B5A5FB /* CExceptionHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };
FD30036E2A3AE26000B5A5FB /* CExceptionHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = FD30036D2A3AE26000B5A5FB /* CExceptionHelper.mm */; };
FD368A6829DE8F9C000DBF1E /* _012_AddFTSIfNeeded.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD368A6729DE8F9B000DBF1E /* _012_AddFTSIfNeeded.swift */; };
FD368A6A29DE9E30000DBF1E /* UIContextualAction+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD368A6929DE9E30000DBF1E /* UIContextualAction+Utilities.swift */; };
FD37E9C328A1C6F3003AE748 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9C228A1C6F3003AE748 /* ThemeManager.swift */; };
@ -1756,8 +1754,6 @@
FD2B4AFE2946C93200AB4848 /* ConfigurationSyncJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationSyncJob.swift; sourceTree = "<group>"; };
FD2B4B032949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QueryInterfaceRequest+Utilities.swift"; sourceTree = "<group>"; };
FD3003652A25D5B300B5A5FB /* ConfigMessageReceiveJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigMessageReceiveJob.swift; sourceTree = "<group>"; };
FD3003692A3ADD6000B5A5FB /* CExceptionHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CExceptionHelper.h; sourceTree = "<group>"; };
FD30036D2A3AE26000B5A5FB /* CExceptionHelper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CExceptionHelper.mm; sourceTree = "<group>"; };
FD368A6729DE8F9B000DBF1E /* _012_AddFTSIfNeeded.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _012_AddFTSIfNeeded.swift; sourceTree = "<group>"; };
FD368A6929DE9E30000DBF1E /* UIContextualAction+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIContextualAction+Utilities.swift"; sourceTree = "<group>"; };
FD37E9C228A1C6F3003AE748 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
@ -3681,8 +3677,6 @@
FDFBB74A2A1EFF4900CA7350 /* Bencode.swift */,
FD97B23F2A3FEB050027DD57 /* ARC4RandomNumberGenerator.swift */,
FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */,
FD3003692A3ADD6000B5A5FB /* CExceptionHelper.h */,
FD30036D2A3AE26000B5A5FB /* CExceptionHelper.mm */,
FD23CE1E2A65269C0000B97C /* Crypto.swift */,
FD12A84A2AD6458800EEBA0D /* DifferenceKit+Utilities.swift */,
FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */,
@ -4639,7 +4633,6 @@
C3D9E4E3256778720040E4F3 /* UIImage+OWS.h in Headers */,
B8856E1A256F1700001CE70E /* OWSMath.h in Headers */,
C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */,
FD30036A2A3ADEC100B5A5FB /* CExceptionHelper.h in Headers */,
C3C2A67D255388CC00C340D1 /* SessionUtilitiesKit.h in Headers */,
C32C6018256E07F9003C73A2 /* NSUserDefaults+OWS.h in Headers */,
B8856D8D256F1502001CE70E /* UIView+OWS.h in Headers */,
@ -5996,7 +5989,6 @@
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Utilities.swift in Sources */,
FD97B2402A3FEB050027DD57 /* ARC4RandomNumberGenerator.swift in Sources */,
FD37EA1128AB34B3003AE748 /* TypedTableAlteration.swift in Sources */,
FD30036E2A3AE26000B5A5FB /* CExceptionHelper.mm in Sources */,
FD1936412ACA7BD8004BCF0F /* Result+Utilities.swift in Sources */,
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
FD12A84B2AD6458800EEBA0D /* DifferenceKit+Utilities.swift in Sources */,

@ -33,7 +33,7 @@ public enum ConfigurationSyncJob: JobExecutor {
.jobInfoFor(state: .running, variant: .configurationSync)
.filter({ key, info in
key != job.id && // Exclude this job
info.threadId == job.threadId // Exclude jobs for different ids
info.threadId == job.threadId // Exclude jobs for different config stores
})
.isEmpty
else {

@ -290,8 +290,11 @@ internal extension LibSession {
else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert contact to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert contact to LibSession"
)
}
// Assign all properties to match the updated contact (if there is one)
@ -308,6 +311,7 @@ internal extension LibSession {
// Store the updated contact (needs to happen before variables go out of scope)
contacts_set(conf, &contact)
try LibSessionError.throwIfNeeded(conf)
}
// Update the profile data (if there is one - users we have sent a message request to may
@ -338,6 +342,7 @@ internal extension LibSession {
// Store the updated contact (needs to happen before variables go out of scope)
contacts_set(conf, &contact)
try LibSessionError.throwIfNeeded(conf)
}
// Assign all properties to match the updated disappearing messages configuration (if there is one)
@ -352,6 +357,7 @@ internal extension LibSession {
// Store the updated contact (can't be sure if we made any changes above)
contact.priority = (info.priority ?? contact.priority)
contacts_set(conf, &contact)
try LibSessionError.throwIfNeeded(conf)
}
}
}
@ -390,7 +396,10 @@ internal extension LibSession {
var cContactId: [CChar] = contactData.id.cString(using: .utf8),
contacts_get(conf, &contact, &cContactId),
String(libSessionVal: contact.name, nullIfEmpty: true) != nil
else { return contactData.id }
else {
LibSessionError.clear(conf)
return contactData.id
}
return nil
}

@ -144,8 +144,11 @@ internal extension LibSession {
guard convo_info_volatile_get_or_construct_1to1(conf, &oneToOne, &cThreadId) else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert contact volatile info to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert contact volatile info to LibSession"
)
}
threadInfo.changes.forEach { change in
@ -165,8 +168,11 @@ internal extension LibSession {
guard convo_info_volatile_get_or_construct_legacy_group(conf, &legacyGroup, &cThreadId) else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert legacy group volatile info to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert legacy group volatile info to LibSession"
)
}
threadInfo.changes.forEach { change in
@ -195,8 +201,11 @@ internal extension LibSession {
guard convo_info_volatile_get_or_construct_community(conf, &community, &cBaseUrl, &cRoomToken, &cPubkey) else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert community volatile info to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert community volatile info to LibSession"
)
}
threadInfo.changes.forEach { change in
@ -339,7 +348,10 @@ public extension LibSession {
guard
var cThreadId: [CChar] = threadId.cString(using: .utf8),
convo_info_volatile_get_1to1(conf, &oneToOne, &cThreadId)
else { return false }
else {
LibSessionError.clear(conf)
return false
}
return (oneToOne.last_read >= timestampMs)
@ -349,7 +361,10 @@ public extension LibSession {
guard
var cThreadId: [CChar] = threadId.cString(using: .utf8),
convo_info_volatile_get_legacy_group(conf, &legacyGroup, &cThreadId)
else { return false }
else {
LibSessionError.clear(conf)
return false
}
return (legacyGroup.last_read >= timestampMs)
@ -362,7 +377,10 @@ public extension LibSession {
var cBaseUrl: [CChar] = openGroup.server.cString(using: .utf8),
var cRoomToken: [CChar] = openGroup.roomToken.cString(using: .utf8),
convo_info_volatile_get_community(conf, &convoCommunity, &cBaseUrl, &cRoomToken)
else { return false }
else {
LibSessionError.clear(conf)
return false
}
return (convoCommunity.last_read >= timestampMs)

@ -419,7 +419,10 @@ public extension LibSession {
var contact: contacts_contact = contacts_contact()
guard contacts_get(conf, &contact, &cThreadId) else { return false }
guard contacts_get(conf, &contact, &cThreadId) else {
LibSessionError.clear(conf)
return false
}
/// If the user opens a conversation with an existing contact but doesn't send them a message
/// then the one-to-one conversation should remain hidden so we want to delete the `SessionThread`
@ -440,10 +443,14 @@ public extension LibSession {
var community: ugroups_community_info = ugroups_community_info()
/// Not handling the `hidden` behaviour for communities so just indicate the existence
return user_groups_get_community(conf, &community, &cBaseUrl, &cRoom)
let result: Bool = user_groups_get_community(conf, &community, &cBaseUrl, &cRoom)
LibSessionError.clear(conf)
return result
case .legacyGroup:
let groupInfo: UnsafeMutablePointer<ugroups_legacy_group_info>? = user_groups_get_legacy_group(conf, &cThreadId)
LibSessionError.clear(conf)
/// Not handling the `hidden` behaviour for legacy groups so just indicate the existence
if groupInfo != nil {

@ -409,8 +409,11 @@ internal extension LibSession {
guard let userGroup: UnsafeMutablePointer<ugroups_legacy_group_info> = user_groups_get_or_construct_legacy_group(conf, &cGroupId) else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert legacy group conversation to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert legacy group conversation to LibSession"
)
}
// Assign all properties to match the updated group (if there is one)
@ -419,6 +422,7 @@ internal extension LibSession {
// Store the updated group (needs to happen before variables go out of scope)
user_groups_set_legacy_group(conf, userGroup)
try LibSessionError.throwIfNeeded(conf) { ugroups_legacy_group_free(userGroup) }
}
if let lastKeyPair: ClosedGroupKeyPair = legacyGroup.lastKeyPair {
@ -428,6 +432,7 @@ internal extension LibSession {
// Store the updated group (needs to happen before variables go out of scope)
user_groups_set_legacy_group(conf, userGroup)
try LibSessionError.throwIfNeeded(conf) { ugroups_legacy_group_free(userGroup) }
}
// Assign all properties to match the updated disappearing messages config (if there is one)
@ -437,6 +442,7 @@ internal extension LibSession {
)
user_groups_set_legacy_group(conf, userGroup)
try LibSessionError.throwIfNeeded(conf) { ugroups_legacy_group_free(userGroup) }
}
// Add/Remove the group members and admins
@ -500,6 +506,7 @@ internal extension LibSession {
// Note: Need to free the legacy group pointer
user_groups_set_free_legacy_group(conf, userGroup)
try LibSessionError.throwIfNeeded(conf)
}
}
@ -526,8 +533,11 @@ internal extension LibSession {
guard user_groups_get_or_construct_community(conf, &userCommunity, &cBaseUrl, &cRoom, &cPubkey) else {
/// It looks like there are some situations where this object might not get created correctly (and
/// will throw due to the implicit unwrapping) as a result we put it in a guard and throw instead
SNLog("Unable to upsert community conversation to LibSession: \(LibSession.lastError(conf))")
throw LibSessionError.getOrConstructFailedUnexpectedly
throw LibSessionError(
conf,
fallbackError: .getOrConstructFailedUnexpectedly,
logMessage: "Unable to upsert community conversation to LibSession"
)
}
userCommunity.priority = (community.priority ?? userCommunity.priority)
@ -624,6 +634,7 @@ public extension LibSession {
// coming in from the legacy group swarm)
guard userGroup == nil else {
ugroups_legacy_group_free(userGroup)
try LibSessionError.throwIfNeeded(conf)
return
}

@ -180,12 +180,14 @@ internal extension LibSession {
// Update the name
var updatedName: [CChar] = try profile.name.cString(using: .utf8) ?? { throw LibSessionError.invalidCConversion }()
user_profile_set_name(conf, &updatedName)
try LibSessionError.throwIfNeeded(conf)
// Either assign the updated profile pic, or sent a blank profile pic (to remove the current one)
var profilePic: user_profile_pic = user_profile_pic()
profilePic.url = profile.profilePictureUrl.toLibSession()
profilePic.key = profile.profileEncryptionKey.toLibSession()
user_profile_set_pic(conf, profilePic)
try LibSessionError.throwIfNeeded(conf)
}
static func updateNoteToSelf(

@ -82,9 +82,6 @@ public extension LibSession {
static var libSessionVersion: String { String(cString: LIBSESSION_UTIL_VERSION_STR) }
internal static func lastError(_ conf: UnsafeMutablePointer<config_object>?) -> String {
return (conf?.pointee.last_error.map { String(cString: $0) } ?? "Unknown") // stringlint:disable
}
// MARK: - Loading
@ -209,9 +206,10 @@ public extension LibSession {
var dumpResult: UnsafeMutablePointer<UInt8>? = nil
var dumpResultLen: Int = 0
try CExceptionHelper.performSafely {
config_dump(conf, &dumpResult, &dumpResultLen)
}
config_dump(conf, &dumpResult, &dumpResultLen)
// If we got an error then throw it
try LibSessionError.throwIfNeeded(conf)
guard let dumpResult: UnsafeMutablePointer<UInt8> = dumpResult else { return nil }
@ -247,14 +245,17 @@ public extension LibSession {
ConfigDump.Variant.userVariants.forEach { existingDumpVariants.insert($0) }
}
// Ensure we always check the required user config types for changes even if there is no dump
// data yet (to deal with first launch cases)
/// Ensure we always check the required user config types for changes even if there is no dump data yet (to deal with first launch cases)
///
/// **Note:** We `mutate` when retrieving the pending changes here because we want to ensure no other threads can modify the
/// config while we are reading (which could result in crashes)
return try existingDumpVariants
.reduce(into: PendingChanges()) { result, variant in
try LibSession
.config(for: variant, publicKey: publicKey)
.wrappedValue
.map { conf in
.mutate { conf in
guard conf != nil else { return }
// Check if the config needs to be pushed
guard config_needs_push(conf) else {
// If not then try retrieve any obsolete hashes to be removed
@ -275,31 +276,22 @@ public extension LibSession {
return
}
var cPushData: UnsafeMutablePointer<config_push_data>!
let configCountInfo: String = {
var result: String = "Invalid" // stringlint:disable
try? CExceptionHelper.performSafely {
guard let cPushData: UnsafeMutablePointer<config_push_data> = config_push(conf) else {
let configCountInfo: String = {
switch variant {
case .userProfile: result = "1 profile"
case .contacts: result = "\(contacts_size(conf)) contacts"
case .userGroups: result = "\(user_groups_size(conf)) group conversations"
case .convoInfoVolatile: result = "\(convo_info_volatile_size(conf)) volatile conversations"
case .invalid: break
case .userProfile: return "1 profile" // stringlint:disable
case .contacts: return "\(contacts_size(conf)) contacts" // stringlint:disable
case .userGroups: return "\(user_groups_size(conf)) group conversations" // stringlint:disable
case .convoInfoVolatile: return "\(convo_info_volatile_size(conf)) volatile conversations" // stringlint:disable
case .invalid: return "Invalid" // stringlint:disable
}
}
}()
return result
}()
do {
try CExceptionHelper.performSafely {
cPushData = config_push(conf)
}
}
catch {
SNLog("[LibSession] Failed to generate push data for \(variant) config data, size: \(configCountInfo), error: \(error)")
throw error
throw LibSessionError(
conf,
fallbackError: .unableToGeneratePushData,
logMessage: "[LibSession] Failed to generate push data for \(variant) config data, size: \(configCountInfo), error"
)
}
let pushData: Data = Data(
@ -431,16 +423,16 @@ public extension LibSession {
else { return SNLog("[LibSession] Failed to correctly allocate merge data") }
var mergeSize: [size_t] = value.map { size_t($0.data.count) }
var mergedHashesPtr: UnsafeMutablePointer<config_string_list>?
try CExceptionHelper.performSafely {
mergedHashesPtr = config_merge(
conf,
&mergeHashes,
&mergeData,
&mergeSize,
value.count
)
}
let mergedHashesPtr: UnsafeMutablePointer<config_string_list>? = config_merge(
conf,
&mergeHashes,
&mergeData,
&mergeSize,
value.count
)
// If we got an error then throw it
try LibSessionError.throwIfNeeded(conf)
// Get the list of hashes from the config (to determine which were successful)
let mergedHashes: [String] = mergedHashesPtr

@ -154,9 +154,10 @@ fileprivate extension LibSessionUtilSpec {
expect(config_needs_dump(conf)).to(beTrue())
expect {
try CExceptionHelper.performSafely { config_push(conf).deallocate() }
config_push(conf)?.deallocate()
try LibSessionError.throwIfNeeded(conf)
}
.to(throwError(NSError(domain: "cpp_exception", code: -2, userInfo: ["NSLocalizedDescription": "Config data is too large"])))
.to(throwError(LibSessionError.libSessionError("Config data is too large.")))
}
}
@ -196,7 +197,10 @@ fileprivate extension LibSessionUtilSpec {
)
contacts_set(conf, &contact)
do { try CExceptionHelper.performSafely { config_push(conf).deallocate() } }
do {
config_push(conf)?.deallocate()
try LibSessionError.throwIfNeeded(conf)
}
catch { break }
// We successfully inserted a contact and didn't hit the limit so increment the counter
@ -220,7 +224,10 @@ fileprivate extension LibSessionUtilSpec {
)
contacts_set(conf, &contact)
do { try CExceptionHelper.performSafely { config_push(conf).deallocate() } }
do {
config_push(conf)?.deallocate()
try LibSessionError.throwIfNeeded(conf)
}
catch { break }
// We successfully inserted a contact and didn't hit the limit so increment the counter
@ -244,7 +251,10 @@ fileprivate extension LibSessionUtilSpec {
)
contacts_set(conf, &contact)
do { try CExceptionHelper.performSafely { config_push(conf).deallocate() } }
do {
config_push(conf)?.deallocate()
try LibSessionError.throwIfNeeded(conf)
}
catch { break }
// We successfully inserted a contact and didn't hit the limit so increment the counter
@ -252,7 +262,7 @@ fileprivate extension LibSessionUtilSpec {
}
// Check that the record count matches the maximum when we last checked
expect(numRecords).to(equal(270))
expect(numRecords).to(equal(274))
}
// MARK: ---- has not changed the max filled records
@ -268,7 +278,10 @@ fileprivate extension LibSessionUtilSpec {
)
contacts_set(conf, &contact)
do { try CExceptionHelper.performSafely { config_push(conf).deallocate() } }
do {
config_push(conf)?.deallocate()
try LibSessionError.throwIfNeeded(conf)
}
catch { break }
// We successfully inserted a contact and didn't hit the limit so increment the counter
@ -277,7 +290,7 @@ fileprivate extension LibSessionUtilSpec {
// Check that the record count matches the maximum when we last checked (seems to swap between
// these two on different test runs for some reason)
expect(numRecords).to(satisfyAnyOf(equal(219), equal(220)))
expect(numRecords).to(equal(223))
}
}

@ -143,12 +143,13 @@ class LibSessionTypeConversionUtilitiesSpec: QuickSpec {
// MARK: ---- truncates when too long
it("truncates when too long") {
let result: (CChar, CChar, CChar, CChar, CChar) = "TestTest".toLibSession()
let result: (CChar, CChar, CChar, CChar, CChar, CChar) = "TestTest".toLibSession()
expect(result.0).to(equal(84))
expect(result.1).to(equal(101))
expect(result.2).to(equal(115))
expect(result.3).to(equal(116))
expect(result.4).to(equal(84))
expect(result.5).to(equal(0)) // Last character will always be a null termination
}
// MARK: ---- when optional

@ -5,13 +5,14 @@
import Foundation
import SessionUtil
public enum LibSessionError: LocalizedError {
public enum LibSessionError: Error, CustomStringConvertible {
case unableToCreateConfigObject
case nilConfigObject
case userDoesNotExist
case getOrConstructFailedUnexpectedly
case processingLoopLimitReached
case invalidCConversion
case unableToGeneratePushData
case libSessionError(String)
case unknown
@ -26,17 +27,52 @@ public enum LibSessionError: LocalizedError {
}
}
public var errorDescription: String? {
public init?(_ conf: UnsafeMutablePointer<config_object>?) {
guard let lastErrorPtr: UnsafePointer<CChar> = conf?.pointee.last_error else { return nil }
let errorString = String(cString: lastErrorPtr)
conf?.pointee.last_error = nil // Clear the last error so subsequent calls don't get confused
self = LibSessionError.libSessionError(errorString)
}
public init(
_ conf: UnsafeMutablePointer<config_object>?,
fallbackError: LibSessionError,
logMessage: String? = nil
) {
self = (LibSessionError(conf) ?? fallbackError)
if let logMessage: String = logMessage {
Log.error("\(logMessage): \(self)")
}
}
public static func throwIfNeeded(
_ conf: UnsafeMutablePointer<config_object>?,
beforeThrow: (() -> ())? = nil
) throws {
guard let error: LibSessionError = LibSessionError(conf) else { return }
beforeThrow?()
throw error
}
public static func clear(_ conf: UnsafeMutablePointer<config_object>?) {
conf?.pointee.last_error = nil
}
public var description: String {
switch self {
case .unableToCreateConfigObject: return "Unable to create config object."
case .nilConfigObject: return "Null config object."
case .userDoesNotExist: return "User does not exist."
case .getOrConstructFailedUnexpectedly: return "'getOrConstruct' failed unexpectedly."
case .processingLoopLimitReached: return "Processing loop limit reached."
case .invalidCConversion: return "Invalid conversation to C type."
case .unableToCreateConfigObject: return "Unable to create config object (LibSessionError.unableToCreateConfigObject)."
case .nilConfigObject: return "Null config object (LibSessionError.nilConfigObject)."
case .userDoesNotExist: return "User does not exist (LibSessionError.userDoesNotExist)."
case .getOrConstructFailedUnexpectedly: return "'getOrConstruct' failed unexpectedly (LibSessionError.getOrConstructFailedUnexpectedly)."
case .processingLoopLimitReached: return "Processing loop limit reached (LibSessionError.processingLoopLimitReached)."
case .invalidCConversion: return "Invalid conversation to C type (LibSessionError.invalidCConversion)."
case .unableToGeneratePushData: return "Unable to generate push data (LibSessionError.unableToGeneratePushData)."
case .libSessionError(let error): return "\(error)\(error.hasSuffix(".") ? "" : ".")"
case .unknown: return "An unknown error occurred."
case .unknown: return "An unknown error occurred (LibSessionError.unknown)."
}
}
}

@ -59,10 +59,14 @@ public extension String {
func toLibSession<T>() -> T {
let targetSize: Int = MemoryLayout<T>.stride
// Limit the string to be the destination size - 1 (for the null terminated character), this will
// mean instead of crashing by trying to set a value that is too large, we truncate the value)
let sizeLimitedString: String = String(self.substring(to: min(count, targetSize - 1)))
var dataMatchingDestinationSize: [CChar] = [CChar](repeating: 0, count: targetSize)
dataMatchingDestinationSize.replaceSubrange(
0..<Swift.min(targetSize, self.utf8CString.count),
with: self.utf8CString
0..<Swift.min(targetSize, sizeLimitedString.utf8CString.count),
with: sizeLimitedString.utf8CString
)
return dataMatchingDestinationSize.withUnsafeBytes { ptr in

@ -13,5 +13,3 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[];
#import <SessionUtilitiesKit/UIImage+OWS.h>
#import <SessionUtilitiesKit/UIView+OWS.h>
#import <SessionUtilitiesKit/OWSBackgroundTask.h>
#import <SessionUtilitiesKit/CExceptionHelper.h>

@ -1,16 +0,0 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
#ifndef __CExceptionHelper_h__
#define __CExceptionHelper_h__
#import <Foundation/Foundation.h>
#define noEscape __attribute__((noescape))
@interface CExceptionHelper: NSObject
+ (BOOL)performSafely:(noEscape void(^)(void))tryBlock error:(__autoreleasing NSError **)error;
@end
#endif

@ -1,36 +0,0 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
//
// This logic is not foolproof and may result in memory-leaks, when possible we should look to remove this
// and use the native C++ <-> Swift interoperability coming with Swift 5.9
//
// This solution was sourced from the following link, for more information please refer to this thread:
// https://forums.swift.org/t/pitch-a-swift-representation-for-thrown-and-caught-exceptions/54583
#import "CExceptionHelper.h"
#include <exception>
@implementation CExceptionHelper
+ (BOOL)performSafely:(noEscape void(^)(void))tryBlock error:(__autoreleasing NSError **)error {
try {
tryBlock();
return YES;
}
catch(NSException* e) {
*error = [[NSError alloc] initWithDomain:e.name code:-1 userInfo:e.userInfo];
return NO;
}
catch (std::exception& e) {
NSString* what = [NSString stringWithUTF8String: e.what()];
NSDictionary* userInfo = @{NSLocalizedDescriptionKey : what};
*error = [[NSError alloc] initWithDomain:@"cpp_exception" code:-2 userInfo:userInfo];
return NO;
}
catch(...) {
NSDictionary* userInfo = @{NSLocalizedDescriptionKey:@"Other C++ exception"};
*error = [[NSError alloc] initWithDomain:@"cpp_exception" code:-3 userInfo:userInfo];
return NO;
}
}
@end
Loading…
Cancel
Save