Skip to content

Commit

Permalink
Close sessions on invalidate
Browse files Browse the repository at this point in the history
  • Loading branch information
za-creature committed Nov 8, 2024
1 parent e16f516 commit a9eeb7b
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 15 deletions.
42 changes: 29 additions & 13 deletions macos/OuisyncFileProvider/Extension+Servicing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,17 @@ extension Extension {

let proxyId = generateProxyId()

connection.interruptionHandler = { [weak self] in
connection.interruptionHandler = { [weak self] in guard let self else { return }
NSLog("😑 Connection to Ouisync XPC service has been interrupted")
if let s = self {
synchronized(s) {
s.proxies.removeValue(forKey: proxyId)
return
}
synchronized(self) {
_ = self.proxies.removeValue(forKey: proxyId)
}
}

connection.invalidationHandler = { [weak self] in
connection.invalidationHandler = { [weak self] in guard let self else { return }
NSLog("😑 Connection to Ouisync XPC service has been invalidated")
if let s = self {
synchronized(s) {
s.proxies.removeValue(forKey: proxyId)
return
}
synchronized(self) {
_ = self.proxies.removeValue(forKey: proxyId)
}
}

Expand All @@ -109,12 +103,34 @@ extension Extension {
return false
}

// this is a bit awkward because to avoid a reference leak, we have to atomically add
// our invalidation closure iff the base extension has not been shut down yet, but we
// also don't want to lift the rest of this function into the synchronized block,
// thus resulting in two checks against the same value
let active = synchronized(ext) {
if ext.active {
ext.invalidators.append {
connection.invalidate() // this should notify peer; invalidationHandler cleans up proxies
await ouisyncClient.close()
}
}
return ext.active
}
guard active else {
// presumably the OS is smart enough to not keep using this service provider bound
// to an instance it has already invalidate()d but stranger things have happened
NSLog("πŸ‘‹ The File Provider extension has received a connection from the app but is in the process of shutting down")
return false
}

let proxy = AppToBackendProxy(connection, sendToApp, ouisyncClient)

connection.exportedObject = proxy
connection.exportedInterface = NSXPCInterface(with: FromAppToFileProviderProtocol.self)

proxies[proxyId] = proxy
synchronized(self) {
proxies[proxyId] = proxy
}

connection.resume()

Expand Down
19 changes: 18 additions & 1 deletion macos/OuisyncFileProvider/Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,25 @@ class Extension: NSObject, NSFileProviderReplicatedExtension {
}
}

// WARN: only mutate these while holding a lock on self
var active = true // this is set to false when shutting down
var invalidators: [() async -> Void] = [] // list of things called on invalidate(); only append if active = true!
func invalidate() {
// TODO: cleanup any resources
let active = synchronized(self) {
defer { self.active = false }
return self.active
}
guard active else { return }
Task {
NSLog("πŸ‘‹ The File Provider extension is shutting down")
async let _ = ouisyncSession.client.close()
await withTaskGroup(of: Void.self) {
for invalidator in invalidators {
$0.addTask(operation: invalidator)
}
invalidators.removeAll() // just in case they were holding strong refs
}
}
}

func item(for identifier: NSFileProviderItemIdentifier, request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) -> Progress {
Expand Down

0 comments on commit a9eeb7b

Please sign in to comment.