From 2f639e2a0276efb3dbb8a470e61ee8ffc2503f5b Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 8 Feb 2021 12:12:43 -0800 Subject: [PATCH] safari: TabFSServer subprocess that can live long. fixes bug where fs would die after a minute or two --- extension/safari/README.md | 9 ++ .../SafariWebExtensionHandler.swift | 2 +- .../TabFS/TabFS.xcodeproj/project.pbxproj | 128 +++++++++++++++--- .../UserInterfaceState.xcuserstate | Bin 61421 -> 61961 bytes .../xcschemes/xcschememanagement.plist | 9 +- extension/safari/TabFS/TabFSServer/main.swift | 113 ++++++++++++++++ .../TabFS/TabFSService/TabFSService.swift | 104 +------------- 7 files changed, 245 insertions(+), 120 deletions(-) create mode 100644 extension/safari/TabFS/TabFSServer/main.swift diff --git a/extension/safari/README.md b/extension/safari/README.md index 730cf82..9ceafdc 100644 --- a/extension/safari/README.md +++ b/extension/safari/README.md @@ -20,3 +20,12 @@ sites. It should be running now! (?) Check the `fs/mnt` folder of the TabFS repo on your computer to see if it's mounted. + +### tips + +- To open Web inspector: Safari -> Develop menu -> Web Extension + Background Pages -> TabFS + +- You need to rebuild if you change background.js. This is pretty + annoying. + diff --git a/extension/safari/TabFS/TabFS Extension/SafariWebExtensionHandler.swift b/extension/safari/TabFS/TabFS Extension/SafariWebExtensionHandler.swift index fbe9538..75790fa 100644 --- a/extension/safari/TabFS/TabFS Extension/SafariWebExtensionHandler.swift +++ b/extension/safari/TabFS/TabFS Extension/SafariWebExtensionHandler.swift @@ -16,7 +16,7 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { guard let message = item.userInfo?["message"] as? [AnyHashable: Any] else { return } guard message["op"] as! String == "safari_did_connect" else { return } - + // The XPC service is a subprocess that lives outside the macOS App Sandbox. // (Safari extension native code, including this file, has to live in the sandbox.) // It can do forbidden things like spawn tabfs filesystem and set up WebSocket server. diff --git a/extension/safari/TabFS/TabFS.xcodeproj/project.pbxproj b/extension/safari/TabFS/TabFS.xcodeproj/project.pbxproj index d274516..5495f1d 100644 --- a/extension/safari/TabFS/TabFS.xcodeproj/project.pbxproj +++ b/extension/safari/TabFS/TabFS.xcodeproj/project.pbxproj @@ -9,10 +9,11 @@ /* Begin PBXBuildFile section */ F028D2B625D0B7370095C2D5 /* TabFSService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B525D0B7370095C2D5 /* TabFSService.swift */; }; F028D2B825D0B7370095C2D5 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B725D0B7370095C2D5 /* main.swift */; }; - F028D2BC25D0B7370095C2D5 /* TabFSService.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = F028D2B125D0B7370095C2D5 /* TabFSService.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; F028D2D725D0B8500095C2D5 /* TabFSServiceProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */; }; F028D2DE25D0B8590095C2D5 /* TabFSServiceProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D2B325D0B7370095C2D5 /* TabFSServiceProtocols.swift */; }; F028D2ED25D106F10095C2D5 /* TabFSService.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = F028D2B125D0B7370095C2D5 /* TabFSService.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + F028D30125D17B080095C2D5 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F028D30025D17B080095C2D5 /* main.swift */; }; + F028D34525D17D6A0095C2D5 /* TabFSServer in CopyFiles */ = {isa = PBXBuildFile; fileRef = F028D2FE25D17B080095C2D5 /* TabFSServer */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; F04429F625C7507200D998A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04429F525C7507200D998A5 /* AppDelegate.swift */; }; F04429F925C7507200D998A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F04429F725C7507200D998A5 /* Main.storyboard */; }; F04429FB25C7507200D998A5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04429FA25C7507200D998A5 /* ViewController.swift */; }; @@ -27,12 +28,12 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - F028D2BA25D0B7370095C2D5 /* PBXContainerItemProxy */ = { + F028D33725D17D100095C2D5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F04429E925C7507200D998A5 /* Project object */; proxyType = 1; - remoteGlobalIDString = F028D2B025D0B7370095C2D5; - remoteInfo = TabFSService; + remoteGlobalIDString = F028D2FD25D17B080095C2D5; + remoteInfo = TabFSServer; }; F0442A0525C7507400D998A5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -44,17 +45,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - F028D2BD25D0B7370095C2D5 /* Embed XPC Services */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices"; - dstSubfolderSpec = 16; - files = ( - F028D2BC25D0B7370095C2D5 /* TabFSService.xpc in Embed XPC Services */, - ); - name = "Embed XPC Services"; - runOnlyForDeploymentPostprocessing = 0; - }; F028D2E525D106BB0095C2D5 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -65,6 +55,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F028D2FC25D17B080095C2D5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + F028D30E25D17BD20095C2D5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + F028D34525D17D6A0095C2D5 /* TabFSServer in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F0442A1425C7507400D998A5 /* Embed App Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -84,6 +93,8 @@ F028D2B525D0B7370095C2D5 /* TabFSService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabFSService.swift; sourceTree = ""; }; F028D2B725D0B7370095C2D5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; F028D2B925D0B7370095C2D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F028D2FE25D17B080095C2D5 /* TabFSServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TabFSServer; sourceTree = BUILT_PRODUCTS_DIR; }; + F028D30025D17B080095C2D5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; F04429F125C7507200D998A5 /* TabFS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabFS.app; sourceTree = BUILT_PRODUCTS_DIR; }; F04429F425C7507200D998A5 /* TabFS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TabFS.entitlements; sourceTree = ""; }; F04429F525C7507200D998A5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -110,6 +121,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F028D2FB25D17B080095C2D5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F04429EE25C7507200D998A5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -139,12 +157,21 @@ path = TabFSService; sourceTree = ""; }; + F028D2FF25D17B080095C2D5 /* TabFSServer */ = { + isa = PBXGroup; + children = ( + F028D30025D17B080095C2D5 /* main.swift */, + ); + path = TabFSServer; + sourceTree = ""; + }; F04429E825C7507200D998A5 = { isa = PBXGroup; children = ( F04429F325C7507200D998A5 /* TabFS */, F0442A0A25C7507400D998A5 /* TabFS Extension */, F028D2B225D0B7370095C2D5 /* TabFSService */, + F028D2FF25D17B080095C2D5 /* TabFSServer */, F0442A0725C7507400D998A5 /* Frameworks */, F04429F225C7507200D998A5 /* Products */, ); @@ -156,6 +183,7 @@ F04429F125C7507200D998A5 /* TabFS.app */, F0442A0325C7507400D998A5 /* TabFS Extension.appex */, F028D2B125D0B7370095C2D5 /* TabFSService.xpc */, + F028D2FE25D17B080095C2D5 /* TabFSServer */, ); name = Products; sourceTree = ""; @@ -214,16 +242,35 @@ F028D2AD25D0B7370095C2D5 /* Sources */, F028D2AE25D0B7370095C2D5 /* Frameworks */, F028D2AF25D0B7370095C2D5 /* Resources */, + F028D30E25D17BD20095C2D5 /* CopyFiles */, ); buildRules = ( ); dependencies = ( + F028D33825D17D100095C2D5 /* PBXTargetDependency */, ); name = TabFSService; productName = TabFSService; productReference = F028D2B125D0B7370095C2D5 /* TabFSService.xpc */; productType = "com.apple.product-type.xpc-service"; }; + F028D2FD25D17B080095C2D5 /* TabFSServer */ = { + isa = PBXNativeTarget; + buildConfigurationList = F028D30425D17B090095C2D5 /* Build configuration list for PBXNativeTarget "TabFSServer" */; + buildPhases = ( + F028D2FA25D17B080095C2D5 /* Sources */, + F028D2FB25D17B080095C2D5 /* Frameworks */, + F028D2FC25D17B080095C2D5 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TabFSServer; + productName = TabFSServer; + productReference = F028D2FE25D17B080095C2D5 /* TabFSServer */; + productType = "com.apple.product-type.tool"; + }; F04429F025C7507200D998A5 /* TabFS */ = { isa = PBXNativeTarget; buildConfigurationList = F0442A1525C7507400D998A5 /* Build configuration list for PBXNativeTarget "TabFS" */; @@ -232,13 +279,11 @@ F04429EE25C7507200D998A5 /* Frameworks */, F04429EF25C7507200D998A5 /* Resources */, F0442A1425C7507400D998A5 /* Embed App Extensions */, - F028D2BD25D0B7370095C2D5 /* Embed XPC Services */, ); buildRules = ( ); dependencies = ( F0442A0625C7507400D998A5 /* PBXTargetDependency */, - F028D2BB25D0B7370095C2D5 /* PBXTargetDependency */, ); name = TabFS; productName = TabFS; @@ -275,6 +320,9 @@ F028D2B025D0B7370095C2D5 = { CreatedOnToolsVersion = 12.1; }; + F028D2FD25D17B080095C2D5 = { + CreatedOnToolsVersion = 12.1; + }; F04429F025C7507200D998A5 = { CreatedOnToolsVersion = 12.1; }; @@ -299,6 +347,7 @@ F04429F025C7507200D998A5 /* TabFS */, F0442A0225C7507400D998A5 /* TabFS Extension */, F028D2B025D0B7370095C2D5 /* TabFSService */, + F028D2FD25D17B080095C2D5 /* TabFSServer */, ); }; /* End PBXProject section */ @@ -344,6 +393,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F028D2FA25D17B080095C2D5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F028D30125D17B080095C2D5 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F04429ED25C7507200D998A5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -365,10 +422,10 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - F028D2BB25D0B7370095C2D5 /* PBXTargetDependency */ = { + F028D33825D17D100095C2D5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = F028D2B025D0B7370095C2D5 /* TabFSService */; - targetProxy = F028D2BA25D0B7370095C2D5 /* PBXContainerItemProxy */; + target = F028D2FD25D17B080095C2D5 /* TabFSServer */; + targetProxy = F028D33725D17D100095C2D5 /* PBXContainerItemProxy */; }; F0442A0625C7507400D998A5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -421,6 +478,28 @@ }; name = Release; }; + F028D30225D17B080095C2D5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 75YA78K5AM; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + F028D30325D17B080095C2D5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 75YA78K5AM; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; F0442A0F25C7507400D998A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -628,6 +707,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + F028D30425D17B090095C2D5 /* Build configuration list for PBXNativeTarget "TabFSServer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F028D30225D17B080095C2D5 /* Debug */, + F028D30325D17B080095C2D5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; F04429EC25C7507200D998A5 /* Build configuration list for PBXProject "TabFS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/extension/safari/TabFS/TabFS.xcodeproj/project.xcworkspace/xcuserdata/osnr.xcuserdatad/UserInterfaceState.xcuserstate b/extension/safari/TabFS/TabFS.xcodeproj/project.xcworkspace/xcuserdata/osnr.xcuserdatad/UserInterfaceState.xcuserstate index 7b7b1d3434926613cd0b1d6d1e644e594946fde1..db4d28a4586d55fe2fec66a1786a1afbb034a065 100644 GIT binary patch delta 30304 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 F{{UW8E&%`l delta 29764 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 diff --git a/extension/safari/TabFS/TabFS.xcodeproj/xcuserdata/osnr.xcuserdatad/xcschemes/xcschememanagement.plist b/extension/safari/TabFS/TabFS.xcodeproj/xcuserdata/osnr.xcuserdatad/xcschemes/xcschememanagement.plist index 9296675..e89e3dc 100644 --- a/extension/safari/TabFS/TabFS.xcodeproj/xcuserdata/osnr.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/extension/safari/TabFS/TabFS.xcodeproj/xcuserdata/osnr.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,13 +7,18 @@ TabFS.xcscheme_^#shared#^_ orderHint - 0 + 2 - TabFSService.xcscheme_^#shared#^_ + TabFSServer.xcscheme_^#shared#^_ orderHint 1 + TabFSService.xcscheme_^#shared#^_ + + orderHint + 0 + diff --git a/extension/safari/TabFS/TabFSServer/main.swift b/extension/safari/TabFS/TabFSServer/main.swift new file mode 100644 index 0000000..245bfb1 --- /dev/null +++ b/extension/safari/TabFS/TabFSServer/main.swift @@ -0,0 +1,113 @@ +// +// main.swift +// TabFSServer +// +// Created by Omar Rizwan on 2/8/21. +// + +import Foundation +import Network +import os.log + +class TabFSServer { + + var fs: Process! + var fsInput: FileHandle! + var fsOutput: FileHandle! + func startFs() { + let fileURL = URL(fileURLWithPath: #filePath) + let repoURL = fileURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() + + fs = Process() + fs.executableURL = repoURL.appendingPathComponent("fs").appendingPathComponent("tabfs") + fs.currentDirectoryURL = fs.executableURL?.deletingLastPathComponent() + + fs.arguments = [] + + let inputPipe = Pipe(), outputPipe = Pipe() + fs.standardInput = inputPipe + fs.standardOutput = outputPipe + + fsInput = inputPipe.fileHandleForWriting + fsOutput = outputPipe.fileHandleForReading + + try! fs.run() + } + + var ws: NWListener! + func startWs() { + // TODO: randomly generate port and report back to caller? + let port = NWEndpoint.Port(rawValue: 9991)! + + let parameters = NWParameters(tls: nil) + parameters.allowLocalEndpointReuse = true + parameters.includePeerToPeer = true + // for security ? so people outside your computer can't hijack TabFS at least + parameters.requiredInterfaceType = .loopback + + let opts = NWProtocolWebSocket.Options() + opts.autoReplyPing = true + parameters.defaultProtocolStack.applicationProtocols.insert(opts, at: 0) + + ws = try! NWListener(using: parameters, on: port) + ws.start(queue: .main) + } + + init() { + startFs() + startWs() + + var handleRequest: ((_ req: Data) -> Void)? + ws.newConnectionHandler = { conn in + conn.start(queue: .main) + + handleRequest = { req in + let metaData = NWProtocolWebSocket.Metadata(opcode: .text) + let context = NWConnection.ContentContext(identifier: "context", metadata: [metaData]) + conn.send(content: req, contentContext: context, completion: .contentProcessed({ err in + if err != nil { + os_log(.default, "req %{public}@ error: %{public}@", String(data: req, encoding: .utf8)!, err!.debugDescription as CVarArg) + // FIXME: ERROR + } + })) + } + + func read() { + conn.receiveMessage { (resp, context, isComplete, err) in + guard let resp = resp else { + // FIXME err + os_log(.default, "resp error: %{public}@", err!.debugDescription as CVarArg) + return + } + + // Send the response back to tabfs.c. + self.fsInput.write(withUnsafeBytes(of: UInt32(resp.count)) { Data($0) }) + self.fsInput.write(resp) + read() + } + } + read() + } + + DispatchQueue.global(qos: .default).async { + while true { + // Blocking read from the tabfs process. + let length = self.fsOutput.readData(ofLength: 4).withUnsafeBytes { $0.load(as: UInt32.self) } + let req = self.fsOutput.readData(ofLength: Int(length)) + + if let handleRequest = handleRequest { + // Send the request over the WebSocket connection to background.js in browser. + handleRequest(req) + } else { + // FIXME: ERROR + } + } + } + + // FIXME: notify + + } +} + +let server = TabFSServer() +dispatchMain() diff --git a/extension/safari/TabFS/TabFSService/TabFSService.swift b/extension/safari/TabFS/TabFSService/TabFSService.swift index 86c39f8..4a86dd6 100644 --- a/extension/safari/TabFS/TabFSService/TabFSService.swift +++ b/extension/safari/TabFS/TabFSService/TabFSService.swift @@ -10,105 +10,15 @@ import Network import os.log class TabFSService: NSObject, TabFSServiceProtocol { - var fs: Process! - var fsInput: FileHandle! - var fsOutput: FileHandle! - func startFs() { - let fileURL = URL(fileURLWithPath: #filePath) - let repoURL = fileURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent() - - fs = Process() - fs.executableURL = repoURL.appendingPathComponent("fs").appendingPathComponent("tabfs") - fs.currentDirectoryURL = fs.executableURL?.deletingLastPathComponent() - - fs.arguments = [] - - let inputPipe = Pipe(), outputPipe = Pipe() - fs.standardInput = inputPipe - fs.standardOutput = outputPipe - - fsInput = inputPipe.fileHandleForWriting - fsOutput = outputPipe.fileHandleForReading - - try! fs.run() - } - - var ws: NWListener! - func startWs() { - // TODO: randomly generate port and report back to caller? - let port = NWEndpoint.Port(rawValue: 9991)! - - let parameters = NWParameters(tls: nil) - parameters.allowLocalEndpointReuse = true - parameters.includePeerToPeer = true - // for security ? so people outside your computer can't hijack TabFS at least - parameters.requiredInterfaceType = .loopback - - let opts = NWProtocolWebSocket.Options() - opts.autoReplyPing = true - parameters.defaultProtocolStack.applicationProtocols.insert(opts, at: 0) - - ws = try! NWListener(using: parameters, on: port) - ws.start(queue: .main) - } - - override init() { - super.init() - - startFs() - startWs() - - var handleRequest: ((_ req: Data) -> Void)? - ws.newConnectionHandler = { conn in - conn.start(queue: .main) - - handleRequest = { req in - let metaData = NWProtocolWebSocket.Metadata(opcode: .text) - let context = NWConnection.ContentContext(identifier: "context", metadata: [metaData]) - conn.send(content: req, contentContext: context, completion: .contentProcessed({ err in - if err != nil { - os_log(.default, "req %{public}@ error: %{public}@", String(data: req, encoding: .utf8)!, err!.debugDescription as CVarArg) - // FIXME: ERROR - } - })) - } - - func read() { - conn.receiveMessage { (resp, context, isComplete, err) in - guard let resp = resp else { - // FIXME err - os_log(.default, "resp error: %{public}@", err!.debugDescription as CVarArg) - return - } - - // Send the response back to tabfs.c. - self.fsInput.write(withUnsafeBytes(of: UInt32(resp.count)) { Data($0) }) - self.fsInput.write(resp) - read() - } - } - read() - } - - DispatchQueue.global(qos: .default).async { - while true { - // Blocking read from the tabfs process. - let length = self.fsOutput.readData(ofLength: 4).withUnsafeBytes { $0.load(as: UInt32.self) } - let req = self.fsOutput.readData(ofLength: Int(length)) - - if let handleRequest = handleRequest { - // Send the request over the WebSocket connection to background.js in browser. - handleRequest(req) - } else { - // FIXME: ERROR - } - } - } - // FIXME: disable auto termination - } - func start(withReply reply: @escaping () -> Void) { // This XPC call is enough to just force the XPC service to be started. + os_log("HELLO") + let server = Process() + os_log("HOW ARE YOU?") + server.executableURL = Bundle.main.url(forResource: "TabFSServer", withExtension: "")! + os_log("I AM GOOD") + server.launch() + os_log("GREAT") reply() } }