safari: checkpoint as I try to get the terrible wiring right

This commit is contained in:
Omar Rizwan 2021-02-02 23:07:24 -08:00
parent f5b00deb7e
commit a465ad6a8f
8 changed files with 188 additions and 17 deletions

View file

@ -673,6 +673,10 @@ function findRoute(path) {
let port;
async function onMessage(req) {
// Safari / Safari extension app API forces you to adopt their
// {name, userInfo} structure for the request.
if (req.name === 'ToSafari') req = req.userInfo;
if (req.buf) req.buf = atob(req.buf);
console.log('req', req);
@ -712,6 +716,16 @@ function tryConnect() {
port = chrome.runtime.connectNative('com.rsnous.tabfs');
port.onMessage.addListener(onMessage);
port.onDisconnect.addListener(p => {console.log('disconnect', p)});
// Safari is very weird -- it has this native app that we have to talk to,
// so we poke that app to wake it up, get it to start the TabFS process,
// and get it to start calling us whenever TabFS wants to do an FS call.
// Is there a better way to do this?
if (chrome.runtime.getURL('/').startsWith('safari-web-extension://')) { // Safari-only
chrome.runtime.sendNativeMessage('com.rsnous.tabfs', {op: 'safari_did_connect'}, function(resp) {
console.log(resp);
});
}
}
if (!TESTING) {

View file

@ -0,0 +1,72 @@
//
// FSProcessManager.swift
// TabFS
//
// Created by Omar Rizwan on 1/31/21.
//
import Foundation
import SafariServices.SFSafariApplication
let extensionBundleIdentifier = "com.rsnous.TabFS-Extension"
class FSProcessManager {
static let shared = FSProcessManager()
// FIXME: should accept XPC connection to extension
// so it can get replies (??)
var fs: Process!
var fsInput: FileHandle!
var fsOutput: FileHandle!
func start() {
fs = Process()
fs.executableURL = URL(fileURLWithPath: "/Users/osnr/Code/tabfs/fs/tabfs")
fs.arguments = []
let inputPipe = Pipe(), outputPipe = Pipe()
fs.standardInput = inputPipe
fs.standardOutput = outputPipe
try! fs.run()
fsInput = inputPipe.fileHandleForWriting
fsOutput = outputPipe.fileHandleForReading
//
// SFSafariApplication.dispatchMessage(
// withName: "ToSafari",
// toExtensionWithIdentifier: extensionBundleIdentifier,
// userInfo: [:]
// ) { error in
// debugPrint("Message attempted. Error info: \(String.init(describing: error))")
// }
DispatchQueue.global(qos: .background).async {
while true {
let req = self.awaitRequest()
SFSafariApplication.dispatchMessage(
withName: "ToSafari",
toExtensionWithIdentifier: extensionBundleIdentifier,
userInfo: req
) { error in
debugPrint("Message attempted. Error info: \(String.init(describing: error))")
}
}
}
}
func awaitRequest() -> [String: Any] {
let length = fsOutput.readData(ofLength: 4).withUnsafeBytes {
$0.load(as: UInt32.self)
}
let data = fsOutput.readData(ofLength: Int(length))
return try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
}
func respond(_ resp: [AnyHashable: Any]) {
try! fsInput.write(JSONSerialization.data(withJSONObject: resp, options: []))
}
}

View file

@ -6,21 +6,38 @@
//
import SafariServices
import SafariServices.SFSafariApplication
import os.log
let SFExtensionMessageKey = "message"
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
os_log(.default, "Received message from browser.runtime.sendNativefffMessage: %@", context as! CVarArg)
let item = context.inputItems[0] as! NSExtensionItem
let message = item.userInfo?[SFExtensionMessageKey]
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg)
let response = NSExtensionItem()
response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
context.completeRequest(returningItems: [response], completionHandler: nil)
guard let message = item.userInfo?["message"] as? [AnyHashable: Any] else { return }
if message["op"] as! String == "safari_did_connect" {
FSProcessManager.shared.start()
let response = NSExtensionItem()
response.userInfo = [ "message": [ "aResponse to": "moop" ] ]
context.completeRequest(returningItems: [response], completionHandler: nil)
return
}
//
// os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", op as! CVarArg)
FSProcessManager.shared.respond(message)
//
// let response = NSExtensionItem()
// response.userInfo = [ "message": [ "Response to": op ] ]
//
// // How do I get too the app????
//
// context.completeRequest(returningItems: [response], completionHandler: nil)
}
}

View file

@ -18,6 +18,7 @@
F0442A1E25C7507500D998A5 /* safari in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1A25C7507500D998A5 /* safari */; };
F0442A1F25C7507500D998A5 /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1B25C7507500D998A5 /* manifest.json */; };
F0442A2025C7507500D998A5 /* vendor in Resources */ = {isa = PBXBuildFile; fileRef = F0442A1C25C7507500D998A5 /* vendor */; };
F068D65625C7C66700DB3AB5 /* FSProcessManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F068D65225C77F7600DB3AB5 /* FSProcessManager.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -61,6 +62,7 @@
F0442A1A25C7507500D998A5 /* safari */ = {isa = PBXFileReference; lastKnownFileType = folder; name = safari; path = ../..; sourceTree = "<group>"; };
F0442A1B25C7507500D998A5 /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = manifest.json; path = ../../../manifest.json; sourceTree = "<group>"; };
F0442A1C25C7507500D998A5 /* vendor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vendor; path = ../../../vendor; sourceTree = "<group>"; };
F068D65225C77F7600DB3AB5 /* FSProcessManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FSProcessManager.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -125,6 +127,7 @@
F0442A0A25C7507400D998A5 /* TabFS Extension */ = {
isa = PBXGroup;
children = (
F068D65225C77F7600DB3AB5 /* FSProcessManager.swift */,
F0442A1825C7507500D998A5 /* Resources */,
F0442A0B25C7507400D998A5 /* SafariWebExtensionHandler.swift */,
F0442A0D25C7507400D998A5 /* Info.plist */,
@ -257,6 +260,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F068D65625C7C66700DB3AB5 /* FSProcessManager.swift in Sources */,
F0442A0C25C7507400D998A5 /* SafariWebExtensionHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -8,9 +8,57 @@
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "62A8B265-14D3-4F90-9C2B-6F38280A1C0A"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/SafariWebExtensionHandler.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "18"
endingLineNumber = "18"
landmarkName = "beginRequest(with:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "171B952C-1DD2-4555-B565-AF63FA641791"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/FSProcessManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "25"
endingLineNumber = "25"
landmarkName = "start()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "C3177652-3D89-4E01-8BF5-03C666008BDB"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/SafariWebExtensionHandler.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "19"
endingLineNumber = "19"
landmarkName = "beginRequest(with:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "111CBF7A-E3E9-4303-9961-9812F8781A39"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "TabFS Extension/SafariWebExtensionHandler.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"

View file

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="16085" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16085"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17156"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -66,7 +67,7 @@
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="TabFS" customModuleProvider="target"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
@ -97,18 +98,28 @@
<!--View Controller-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="TabFS" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="m2S-Jp-Qdl">
<rect key="frame" x="0.0" y="0.0" width="480" height="344"/>
<rect key="frame" x="0.0" y="0.0" width="480" height="407"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="centerX" spacing="42" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZLV-xE-AGT">
<rect key="frame" x="0.0" y="34" width="480" height="265"/>
<rect key="frame" x="0.0" y="34" width="480" height="328"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="FWV-e2-WQh" userLabel="IconView">
<rect key="frame" x="176" y="137" width="128" height="128"/>
<rect key="frame" x="176" y="200" width="128" height="128"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" image="AppIcon" id="Hhb-TZ-Dhg"/>
</imageView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LPN-IP-tY1">
<rect key="frame" x="144" y="130" width="192" height="32"/>
<buttonCell key="cell" type="push" title="Start TabFS and Connect" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="OYN-4O-IVc">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="startTabFSAndConnect:" target="XfG-lQ-9wD" id="ECW-0t-4uE"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EB0-ac-UZR">
<rect key="frame" x="38" y="63" width="404" height="32"/>
<constraints>
@ -138,11 +149,13 @@ DQ
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>

View file

@ -48,4 +48,7 @@ class ViewController: NSViewController {
}
}
@IBAction func startTabFSAndConnect(_ sender: Any) {
// FSProcessManager.start()
}
}