mirror of
https://github.com/osnr/TabFS.git
synced 2024-05-03 14:23:11 +02:00
safari: fix some races when you reload Web inspector, make ws connection retry
This commit is contained in:
parent
2f639e2a02
commit
0f2ab4b4de
|
@ -720,15 +720,26 @@ function tryConnect() {
|
|||
if (chrome.runtime.getURL('/').startsWith('safari-web-extension://')) { // Safari-only
|
||||
chrome.runtime.sendNativeMessage('com.rsnous.tabfs', {op: 'safari_did_connect'}, resp => {
|
||||
console.log(resp);
|
||||
const socket = new WebSocket('ws://localhost:9991');
|
||||
|
||||
socket.addEventListener('message', event => {
|
||||
onMessage(JSON.parse(event.data));
|
||||
});
|
||||
let socket;
|
||||
function connectSocket(checkAfterTime) {
|
||||
socket = new WebSocket('ws://localhost:9991');
|
||||
socket.addEventListener('message', event => {
|
||||
onMessage(JSON.parse(event.data));
|
||||
});
|
||||
|
||||
port = { postMessage(message) {
|
||||
socket.send(JSON.stringify(message));
|
||||
} };
|
||||
port = { postMessage(message) {
|
||||
socket.send(JSON.stringify(message));
|
||||
} };
|
||||
|
||||
setTimeout(() => {
|
||||
if (socket.readyState !== 1) {
|
||||
console.log('ws connection failed, retrying in', checkAfterTime);
|
||||
connectSocket(checkAfterTime * 2);
|
||||
}
|
||||
}, checkAfterTime);
|
||||
}
|
||||
connectSocket(200);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,12 @@ it's mounted.
|
|||
### tips
|
||||
|
||||
- To open Web inspector: Safari -> Develop menu -> Web Extension
|
||||
Background Pages -> TabFS
|
||||
Background Pages -> TabFS.
|
||||
|
||||
- You need to rebuild if you change background.js. This is pretty
|
||||
annoying.
|
||||
Refreshing this inspector should reload the tabfs filesystem, also.
|
||||
|
||||
- You need to rebuild in Xcode any time you change background.js
|
||||
(because the extension files are copied into the extension, rather
|
||||
than running directly from folder as in Firefox and Chrome). This is
|
||||
pretty annoying.
|
||||
|
||||
|
|
|
@ -17,16 +17,20 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
|||
|
||||
guard message["op"] as! String == "safari_did_connect" else { return }
|
||||
|
||||
// The XPC service is a subprocess that lives outside the macOS App Sandbox.
|
||||
// The XPC service is a process that can live 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.
|
||||
|
||||
// We only use one native message to bootstrap the XPC service, then do all communications
|
||||
// to that service (which in turn talks to tabfs.c) over WebSocket instead.
|
||||
// We only use one native message, to bootstrap the XPC service (TabFSService).
|
||||
// Then the XPC service starts TabFSServer. TabFSServer is separate because
|
||||
// XPC services get killed by the OS after a minute or two; TabFSServer
|
||||
// is just a normal process that can live on. It talks straight
|
||||
// to background.js (which in turn talks to tabfs.c) over a WebSocket.
|
||||
|
||||
// (Safari makes doing native messaging quite painful, so we try to avoid it.
|
||||
// It forces the browser to pop to front if you message Safari in the obvious way,
|
||||
// for instance: https://developer.apple.com/forums/thread/122232
|
||||
// And with the WebSocket, the XPC service can talk straight to background.js, whereas
|
||||
// And with the WebSocket, the server can talk straight to background.js, whereas
|
||||
// native messaging would require us here to sit in the middle.)
|
||||
|
||||
let connection = NSXPCConnection(serviceName: "com.rsnous.TabFSService")
|
||||
|
@ -44,8 +48,9 @@ class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
|
|||
// FIXME: report port back?
|
||||
let response = NSExtensionItem()
|
||||
response.userInfo = [ "message": "alive" ]
|
||||
// This response (over native messaging) prompts background.js to
|
||||
// connect to the WebSocket server that the XPC service should now be running.
|
||||
// This response (over native messaging) will prompt background.js to
|
||||
// connect to the WebSocket server of TabFSServer, which should
|
||||
// now be running.
|
||||
context.completeRequest(returningItems: [response]) { (what) in
|
||||
print(what)
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -75,8 +75,9 @@ class TabFSServer {
|
|||
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)
|
||||
if let err = err {
|
||||
os_log(.default, "resp error: %{public}@", err.debugDescription as CVarArg)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -104,10 +105,10 @@ class TabFSServer {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: notify
|
||||
|
||||
print("OK")
|
||||
}
|
||||
}
|
||||
|
||||
let server = TabFSServer()
|
||||
|
||||
dispatchMain()
|
||||
|
|
|
@ -12,13 +12,36 @@ import os.log
|
|||
class TabFSService: NSObject, TabFSServiceProtocol {
|
||||
func start(withReply reply: @escaping () -> Void) {
|
||||
// This XPC call is enough to just force the XPC service to be started.
|
||||
os_log("HELLO")
|
||||
|
||||
// kill old copies of TabFSServer
|
||||
let killall = Process()
|
||||
killall.launchPath = "/usr/bin/killall"
|
||||
killall.arguments = ["TabFSServer"]
|
||||
killall.launch()
|
||||
killall.waitUntilExit()
|
||||
|
||||
// spin until old TabFSServer (if any) is gone
|
||||
while true {
|
||||
let pgrep = Process()
|
||||
pgrep.launchPath = "/usr/bin/pgrep"
|
||||
pgrep.arguments = ["TabFSServer"]
|
||||
pgrep.launch()
|
||||
pgrep.waitUntilExit()
|
||||
if pgrep.terminationStatus != 0 { break }
|
||||
|
||||
Thread.sleep(forTimeInterval: 0.01)
|
||||
}
|
||||
|
||||
let server = Process()
|
||||
os_log("HOW ARE YOU?")
|
||||
let serverOutput = Pipe()
|
||||
server.executableURL = Bundle.main.url(forResource: "TabFSServer", withExtension: "")!
|
||||
os_log("I AM GOOD")
|
||||
server.standardOutput = serverOutput
|
||||
server.launch()
|
||||
os_log("GREAT")
|
||||
|
||||
// FIXME: should we wait for some signal that the server is ready?
|
||||
// right now, background.js will just periodically retry until it can connect.
|
||||
|
||||
// tell background.js to try to connect.
|
||||
reply()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue