ios: mach messages to coordinate database acceess between app & NSE (#717)
This commit is contained in:
committed by
GitHub
parent
b435c0145f
commit
949fb17406
@@ -11,6 +11,13 @@ import SimpleXChat
|
|||||||
|
|
||||||
let logger = Logger()
|
let logger = Logger()
|
||||||
|
|
||||||
|
let machMessenger = MachMessenger(APP_MACH_PORT, callback: receivedNSEMachMessage)
|
||||||
|
|
||||||
|
func receivedNSEMachMessage(msgId: Int32, msg: String) -> String? {
|
||||||
|
logger.debug("MachMessenger: receivedNSEMachMessage \"\(msg)\" from NSE, replying")
|
||||||
|
return "reply from App to: \(msg)"
|
||||||
|
}
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct SimpleXApp: App {
|
struct SimpleXApp: App {
|
||||||
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||||
@@ -27,6 +34,7 @@ struct SimpleXApp: App {
|
|||||||
UserDefaults.standard.register(defaults: appDefaults)
|
UserDefaults.standard.register(defaults: appDefaults)
|
||||||
BGManager.shared.register()
|
BGManager.shared.register()
|
||||||
NtfManager.shared.registerCategories()
|
NtfManager.shared.registerCategories()
|
||||||
|
machMessenger.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
@@ -42,14 +50,18 @@ struct SimpleXApp: App {
|
|||||||
}
|
}
|
||||||
.onChange(of: scenePhase) { phase in
|
.onChange(of: scenePhase) { phase in
|
||||||
logger.debug("scenePhase \(String(describing: scenePhase))")
|
logger.debug("scenePhase \(String(describing: scenePhase))")
|
||||||
|
let res = machMessenger.sendMessageWithReply(NSE_MACH_PORT, msg: "App scenePhase changed to \(String(describing: scenePhase))")
|
||||||
|
logger.debug("MachMessenger \(String(describing: res), privacy: .public)")
|
||||||
setAppState(phase)
|
setAppState(phase)
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case .background:
|
case .background:
|
||||||
BGManager.shared.schedule()
|
BGManager.shared.schedule()
|
||||||
doAuthenticate = false
|
doAuthenticate = false
|
||||||
enteredBackground = ProcessInfo.processInfo.systemUptime
|
enteredBackground = ProcessInfo.processInfo.systemUptime
|
||||||
|
machMessenger.stop()
|
||||||
case .active:
|
case .active:
|
||||||
doAuthenticate = true
|
doAuthenticate = true
|
||||||
|
machMessenger.start()
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,20 @@ import SimpleXChat
|
|||||||
|
|
||||||
let logger = Logger()
|
let logger = Logger()
|
||||||
|
|
||||||
class NotificationService: UNNotificationServiceExtension {
|
let machMessenger = MachMessenger(NSE_MACH_PORT, callback: receivedAppMachMessage)
|
||||||
|
|
||||||
|
class NotificationService: UNNotificationServiceExtension {
|
||||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||||
var bestAttemptContent: UNMutableNotificationContent?
|
var bestAttemptContent: UNMutableNotificationContent?
|
||||||
|
|
||||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||||
logger.debug("NotificationService.didReceive")
|
logger.debug("NotificationService.didReceive")
|
||||||
|
machMessenger.start()
|
||||||
|
let res = machMessenger.sendMessageWithReply(APP_MACH_PORT, msg: "starting NSE didReceive")
|
||||||
|
logger.debug("MachMessenger \(String(describing: res), privacy: .public)")
|
||||||
if getAppState() != .background {
|
if getAppState() != .background {
|
||||||
contentHandler(request.content)
|
contentHandler(request.content)
|
||||||
|
machMessenger.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.debug("NotificationService: app is in the background")
|
logger.debug("NotificationService: app is in the background")
|
||||||
@@ -29,6 +34,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
if let _ = startChat() {
|
if let _ = startChat() {
|
||||||
let content = receiveMessages()
|
let content = receiveMessages()
|
||||||
contentHandler (content)
|
contentHandler (content)
|
||||||
|
machMessenger.stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +44,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
|
|
||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
}
|
}
|
||||||
|
machMessenger.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func serviceExtensionTimeWillExpire() {
|
override func serviceExtensionTimeWillExpire() {
|
||||||
@@ -48,7 +55,11 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func receivedAppMachMessage(msgId: Int32, msg: String) -> String? {
|
||||||
|
logger.debug("MachMessenger: receivedAppMachMessage \"\(msg)\" from App, replying")
|
||||||
|
return "reply from NSE to: \(msg)"
|
||||||
}
|
}
|
||||||
|
|
||||||
func startChat() -> User? {
|
func startChat() -> User? {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
5CE2BA88284532AD00EC33A6 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A6907F28376BB90076573F /* libgmp.a */; };
|
5CE2BA88284532AD00EC33A6 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A6907F28376BB90076573F /* libgmp.a */; };
|
||||||
5CE2BA89284532AD00EC33A6 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A6907E28376BB90076573F /* libgmpxx.a */; };
|
5CE2BA89284532AD00EC33A6 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A6907E28376BB90076573F /* libgmpxx.a */; };
|
||||||
5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */; };
|
5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */; };
|
||||||
5CE2BA8C284533A300EC33A6 /* GroupDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD5228186F9500503DA2 /* GroupDefaults.swift */; };
|
5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD5228186F9500503DA2 /* AppGroup.swift */; };
|
||||||
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5E5D3C282447AB00B0488A /* CallTypes.swift */; };
|
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5E5D3C282447AB00B0488A /* CallTypes.swift */; };
|
||||||
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7D2818941F00503DA2 /* API.swift */; };
|
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7D2818941F00503DA2 /* API.swift */; };
|
||||||
5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7428188D2900503DA2 /* APITypes.swift */; };
|
5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD7428188D2900503DA2 /* APITypes.swift */; };
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
5CDCAD472818589900503DA2 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
5CDCAD472818589900503DA2 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
5CDCAD492818589900503DA2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
5CDCAD492818589900503DA2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX NSE.entitlements"; sourceTree = "<group>"; };
|
5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX NSE.entitlements"; sourceTree = "<group>"; };
|
||||||
5CDCAD5228186F9500503DA2 /* GroupDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupDefaults.swift; sourceTree = "<group>"; };
|
5CDCAD5228186F9500503DA2 /* AppGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroup.swift; sourceTree = "<group>"; };
|
||||||
5CDCAD5E28187D4A00503DA2 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk/usr/lib/libiconv.tbd; sourceTree = DEVELOPER_DIR; };
|
5CDCAD5E28187D4A00503DA2 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk/usr/lib/libiconv.tbd; sourceTree = DEVELOPER_DIR; };
|
||||||
5CDCAD6028187D7900503DA2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; };
|
5CDCAD6028187D7900503DA2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.4.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; };
|
||||||
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTypes.swift; sourceTree = "<group>"; };
|
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTypes.swift; sourceTree = "<group>"; };
|
||||||
@@ -398,7 +398,6 @@
|
|||||||
5C764E87279CBC8E000C6508 /* Model */ = {
|
5C764E87279CBC8E000C6508 /* Model */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5CDCAD7128188CEB00503DA2 /* Shared */,
|
|
||||||
5C764E88279CBCB3000C6508 /* ChatModel.swift */,
|
5C764E88279CBCB3000C6508 /* ChatModel.swift */,
|
||||||
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */,
|
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */,
|
||||||
5C35CFC727B2782E00FB6C6D /* BGManager.swift */,
|
5C35CFC727B2782E00FB6C6D /* BGManager.swift */,
|
||||||
@@ -540,17 +539,10 @@
|
|||||||
path = "SimpleX NSE";
|
path = "SimpleX NSE";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
5CDCAD7128188CEB00503DA2 /* Shared */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
path = Shared;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5CE2BA692845308900EC33A6 /* SimpleXChat */ = {
|
5CE2BA692845308900EC33A6 /* SimpleXChat */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5CDCAD5228186F9500503DA2 /* GroupDefaults.swift */,
|
5CDCAD5228186F9500503DA2 /* AppGroup.swift */,
|
||||||
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */,
|
5CDCAD7228188CFF00503DA2 /* ChatTypes.swift */,
|
||||||
5CDCAD7428188D2900503DA2 /* APITypes.swift */,
|
5CDCAD7428188D2900503DA2 /* APITypes.swift */,
|
||||||
5C5E5D3C282447AB00B0488A /* CallTypes.swift */,
|
5C5E5D3C282447AB00B0488A /* CallTypes.swift */,
|
||||||
@@ -887,7 +879,7 @@
|
|||||||
5CE2BA90284533A300EC33A6 /* JSON.swift in Sources */,
|
5CE2BA90284533A300EC33A6 /* JSON.swift in Sources */,
|
||||||
5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */,
|
5CE2BA8B284533A300EC33A6 /* ChatTypes.swift in Sources */,
|
||||||
5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */,
|
5CE2BA8F284533A300EC33A6 /* APITypes.swift in Sources */,
|
||||||
5CE2BA8C284533A300EC33A6 /* GroupDefaults.swift in Sources */,
|
5CE2BA8C284533A300EC33A6 /* AppGroup.swift in Sources */,
|
||||||
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */,
|
5CE2BA8D284533A300EC33A6 /* CallTypes.swift in Sources */,
|
||||||
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */,
|
5CE2BA8E284533A300EC33A6 /* API.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
177
apps/ios/SimpleXChat/AppGroup.swift
Normal file
177
apps/ios/SimpleXChat/AppGroup.swift
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
//
|
||||||
|
// GroupDefaults.swift
|
||||||
|
// SimpleX (iOS)
|
||||||
|
//
|
||||||
|
// Created by Evgeny on 26/04/2022.
|
||||||
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
let GROUP_DEFAULT_APP_IN_BACKGROUND = "appInBackground"
|
||||||
|
|
||||||
|
let APP_GROUP_NAME = "group.chat.simplex.app"
|
||||||
|
|
||||||
|
public let NSE_MACH_PORT = "\(APP_GROUP_NAME).nse" as CFString
|
||||||
|
|
||||||
|
public let APP_MACH_PORT = "\(APP_GROUP_NAME).app" as CFString
|
||||||
|
|
||||||
|
func getGroupDefaults() -> UserDefaults? {
|
||||||
|
UserDefaults(suiteName: APP_GROUP_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setAppState(_ phase: ScenePhase) {
|
||||||
|
if let defaults = getGroupDefaults() {
|
||||||
|
defaults.set(phase == .background, forKey: GROUP_DEFAULT_APP_IN_BACKGROUND)
|
||||||
|
defaults.synchronize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getAppState() -> ScenePhase {
|
||||||
|
if let defaults = getGroupDefaults() {
|
||||||
|
if defaults.bool(forKey: GROUP_DEFAULT_APP_IN_BACKGROUND) {
|
||||||
|
return .background
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .active
|
||||||
|
}
|
||||||
|
|
||||||
|
let MACH_SEND_TIMEOUT: CFTimeInterval = 1.0
|
||||||
|
let MACH_REPLY_TIMEOUT: CFTimeInterval = 1.0
|
||||||
|
|
||||||
|
public class MachMessenger {
|
||||||
|
public init(_ localPortName: CFString, callback: @escaping Callback) {
|
||||||
|
self.localPortName = localPortName
|
||||||
|
self.callback = callback
|
||||||
|
self.localPort = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var localPortName: CFString
|
||||||
|
var callback: Callback
|
||||||
|
var localPort: CFMessagePort?
|
||||||
|
|
||||||
|
public enum SendError: Error {
|
||||||
|
case sndTimeout
|
||||||
|
case rcvTimeout
|
||||||
|
case portInvalid
|
||||||
|
case sendError(Int32)
|
||||||
|
case msgError
|
||||||
|
}
|
||||||
|
|
||||||
|
public typealias Callback = (_ msgId: Int32, _ msg: String) -> String?
|
||||||
|
|
||||||
|
class CallbackInfo {
|
||||||
|
internal init(callback: @escaping MachMessenger.Callback) {
|
||||||
|
self.callback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
var callback: Callback
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func sendError(_ code: Int32) -> SendError? {
|
||||||
|
switch code {
|
||||||
|
case kCFMessagePortSuccess: return nil
|
||||||
|
case kCFMessagePortSendTimeout: return .sndTimeout
|
||||||
|
case kCFMessagePortReceiveTimeout: return .rcvTimeout
|
||||||
|
case kCFMessagePortIsInvalid: return .portInvalid
|
||||||
|
case kCFMessagePortBecameInvalidError: return .portInvalid
|
||||||
|
default: return .sendError(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func start() {
|
||||||
|
logger.debug("MachMessenger.start")
|
||||||
|
localPort = createLocalPort(localPortName, callback: callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func stop() {
|
||||||
|
if let port = localPort {
|
||||||
|
logger.debug("MachMessenger.stop")
|
||||||
|
CFMessagePortInvalidate(port)
|
||||||
|
localPort = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func sendMessage(_ remotePortName: CFString, msgId: Int32 = 0, msg: String) -> SendError? {
|
||||||
|
logger.debug("MachMessenger.sendMessage")
|
||||||
|
if let port = createRemotePort(remotePortName) {
|
||||||
|
logger.debug("MachMessenger.sendMessage: sending...")
|
||||||
|
return sendMessage(port, msgId: msgId, msg: msg)
|
||||||
|
} else {
|
||||||
|
logger.debug("MachMessenger.sendMessage: no remote port")
|
||||||
|
return .portInvalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func sendMessageWithReply(_ remotePortName: CFString, msgId: Int32 = 0, msg: String) -> Result<String?, SendError> {
|
||||||
|
logger.debug("MachMessenger.sendMessageWithReply")
|
||||||
|
if let port = createRemotePort(remotePortName) {
|
||||||
|
logger.debug("MachMessenger.sendMessageWithReply: sending...")
|
||||||
|
return sendMessageWithReply(port, msgId: msgId, msg: msg)
|
||||||
|
} else {
|
||||||
|
logger.debug("MachMessenger.sendMessageWithReply: no remote port")
|
||||||
|
return .failure(.portInvalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func createLocalPort(_ portName: CFString, callback: @escaping Callback) -> CFMessagePort? {
|
||||||
|
logger.debug("MachMessenger.createLocalPort")
|
||||||
|
if let port = localPort { return port }
|
||||||
|
logger.debug("MachMessenger.createLocalPort: creating...")
|
||||||
|
var context = CFMessagePortContext()
|
||||||
|
context.version = 0
|
||||||
|
context.info = Unmanaged.passRetained(CallbackInfo(callback: callback)).toOpaque()
|
||||||
|
let callout: CFMessagePortCallBack = { port, msgId, msgData, info in
|
||||||
|
logger.debug("MachMessenger CFMessagePortCallBack called")
|
||||||
|
if let data = msgData,
|
||||||
|
let msg = String(data: data as Data, encoding: .utf8),
|
||||||
|
let info = info,
|
||||||
|
let resp = Unmanaged<CallbackInfo>.fromOpaque(info).takeUnretainedValue().callback(msgId, msg),
|
||||||
|
let respData = resp.data(using: .utf8) {
|
||||||
|
return Unmanaged.passRetained(respData as CFData)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return withUnsafeMutablePointer(to: &context) { cxt in
|
||||||
|
let port = CFMessagePortCreateLocal(kCFAllocatorDefault, portName, callout, cxt, nil)
|
||||||
|
CFMessagePortSetDispatchQueue(port, DispatchQueue.main);
|
||||||
|
localPort = port
|
||||||
|
logger.debug("MachMessenger.createLocalPort created: \(portName)")
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func createRemotePort(_ portName: CFString) -> CFMessagePort? {
|
||||||
|
CFMessagePortCreateRemote(kCFAllocatorDefault, portName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sendMessage(_ remotePort: CFMessagePort, msgId: Int32 = 0, msg: String) -> SendError? {
|
||||||
|
if let data = msg.data(using: .utf8) {
|
||||||
|
logger.debug("MachMessenger sendMessage")
|
||||||
|
let msgData = data as CFData
|
||||||
|
let code = CFMessagePortSendRequest(remotePort, msgId, msgData, MACH_SEND_TIMEOUT, 0, nil, nil)
|
||||||
|
logger.debug("MachMessenger sendMessage \(code)")
|
||||||
|
return MachMessenger.sendError(code)
|
||||||
|
}
|
||||||
|
return .msgError
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sendMessageWithReply(_ remotePort: CFMessagePort, msgId: Int32 = 0, msg: String) -> Result<String?, SendError> {
|
||||||
|
if let data = msg.data(using: .utf8) {
|
||||||
|
let msgData = data as CFData
|
||||||
|
var respData: Unmanaged<CFData>? = nil
|
||||||
|
let code = CFMessagePortSendRequest(remotePort, msgId, msgData, MACH_SEND_TIMEOUT, MACH_REPLY_TIMEOUT, CFRunLoopMode.defaultMode.rawValue, &respData)
|
||||||
|
if let err = MachMessenger.sendError(code) {
|
||||||
|
return .failure(err)
|
||||||
|
} else if let data = respData?.takeUnretainedValue(),
|
||||||
|
let resp = String(data: data as Data, encoding: .utf8) {
|
||||||
|
return .success(resp)
|
||||||
|
} else {
|
||||||
|
return .success(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return .failure(.msgError)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ public let maxFileSize: Int64 = 8000000
|
|||||||
|
|
||||||
func getDocumentsDirectory() -> URL {
|
func getDocumentsDirectory() -> URL {
|
||||||
// FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
// FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||||
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.chat.simplex.app")!
|
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: APP_GROUP_NAME)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getAppFilesDirectory() -> URL {
|
public func getAppFilesDirectory() -> URL {
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// GroupDefaults.swift
|
|
||||||
// SimpleX (iOS)
|
|
||||||
//
|
|
||||||
// Created by Evgeny on 26/04/2022.
|
|
||||||
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
let GROUP_DEFAULT_APP_IN_BACKGROUND = "appInBackground"
|
|
||||||
|
|
||||||
func getGroupDefaults() -> UserDefaults? {
|
|
||||||
UserDefaults(suiteName: "group.chat.simplex.app")
|
|
||||||
}
|
|
||||||
|
|
||||||
public func setAppState(_ phase: ScenePhase) {
|
|
||||||
if let defaults = getGroupDefaults() {
|
|
||||||
defaults.set(phase == .background, forKey: GROUP_DEFAULT_APP_IN_BACKGROUND)
|
|
||||||
defaults.synchronize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func getAppState() -> ScenePhase {
|
|
||||||
if let defaults = getGroupDefaults() {
|
|
||||||
if defaults.bool(forKey: GROUP_DEFAULT_APP_IN_BACKGROUND) {
|
|
||||||
return .background
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return .active
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user