OSX Launcher: general cleanup, responsibility delegation, and fixes

This commit is contained in:
meeh
2018-10-13 03:54:01 +00:00
parent a9bf9e0657
commit 530470972f
5 changed files with 199 additions and 66 deletions

View File

@ -93,7 +93,8 @@ class Logger {
}
@objc static func openLink(url: String) {
SBridge.sharedInstance().openUrl(url)
NSLog("Trying to open \(url)")
NSWorkspace.shared().open(NSURL(string: url)! as URL)
}
@objc func applicationWillTerminate() {

View File

@ -0,0 +1,111 @@
//
// FolderContentMonitor.swift
// I2PLauncher
//
// Created by Mikal Villa on 28/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
/*
infix operator ~>
private let queue = DispatchQueue(label: "background")
func ~> <R> (
backgroundClosure: @escaping () -> R,
mainClosure: @escaping (_ result: R) -> ())
{
queue.async {
let result = backgroundClosure()
DispatchQueue.main.async(execute: {
mainClosure(result)
})
}
}
*/
public struct Event: CustomStringConvertible {
public let eventId: FSEventStreamEventId
public let eventPath: String
public let eventFlags: FSEventStreamEventFlags
public var description: String {
return "\(eventId) - \(eventFlags) - \(eventPath)"
}
}
public class FolderContentMonitor {
let callback: (Event) -> Void
public init(pathsToWatch: [String], sinceWhen: FSEventStreamEventId = FSEventStreamEventId(kFSEventStreamEventIdSinceNow), callback: @escaping (Event) -> Void) {
self.lastEventId = sinceWhen
self.pathsToWatch = pathsToWatch
self.callback = callback
}
deinit {
stop()
}
// MARK: - Private Properties
private let eventCallback: FSEventStreamCallback = {
(stream: ConstFSEventStreamRef,
contextInfo: UnsafeMutableRawPointer?,
numEvents: Int,
eventPaths: UnsafeMutableRawPointer,
eventFlags: UnsafePointer<FSEventStreamEventFlags>,
eventIds: UnsafePointer<FSEventStreamEventId>) in
let fileSystemWatcher: FolderContentMonitor = unsafeBitCast(contextInfo, to: FolderContentMonitor.self)
guard let paths = unsafeBitCast(eventPaths, to: NSArray.self) as? [String] else { return }
for index in 0..<numEvents {
fileSystemWatcher.processEvent(eventId: eventIds[index], eventPath: paths[index], eventFlags: eventFlags[index])
}
fileSystemWatcher.lastEventId = eventIds[numEvents - 1]
}
private let pathsToWatch: [String]
private var started = false
private var streamRef: FSEventStreamRef!
private func processEvent(eventId: FSEventStreamEventId, eventPath: String, eventFlags: FSEventStreamEventFlags) {
let event = Event(eventId: eventId, eventPath: eventPath, eventFlags: eventFlags)
callback(event)
}
public private(set) var lastEventId: FSEventStreamEventId
public func start() {
guard started == false else { return }
var context = FSEventStreamContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = Unmanaged.passUnretained(self).toOpaque()
let flags = UInt32(kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagFileEvents)
streamRef = FSEventStreamCreate(kCFAllocatorDefault, eventCallback, &context, pathsToWatch as CFArray, lastEventId, 0, flags)
FSEventStreamScheduleWithRunLoop(streamRef, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
FSEventStreamStart(streamRef)
started = true
}
public func stop() {
guard started == true else { return }
FSEventStreamStop(streamRef)
FSEventStreamInvalidate(streamRef)
FSEventStreamRelease(streamRef)
streamRef = nil
started = false
}
}

View File

@ -82,4 +82,7 @@ inline void MLog(int loglevel, NSString* format, ...)
}
#define MMLog(format_string,...) ((MLog(1, [NSString stringWithFormat:format_string,##__VA_ARGS__])))
#endif /* logger_c_h */

View File

@ -25,6 +25,7 @@ class RouterManager : NSObject {
let routerRunner = RouterRunner()
var logViewStorage: NSTextStorage?
var lastRouterPid : String? = nil
private static func handleRouterException(information:Any?) {
Logger.MLog(level:1,"event! - handle router exception")
@ -94,6 +95,27 @@ class RouterManager : NSObject {
routerManager.eventManager.listenTo(eventName: "router_already_running", action: handleRouterAlreadyStarted)
routerManager.eventManager.listenTo(eventName: "router_can_start", action: routerManager.routerRunner.StartAgent)
routerManager.eventManager.listenTo(eventName: "router_can_setup", action: routerManager.routerRunner.SetupAgent)
//routerManager.eventManager.listenTo(eventName: "launch_agent_running", action: routerManager.routerRunner.onLoadedAgent)
routerManager.eventManager.listenTo(eventName: "launch_agent_running", action: {
let agent = RouterRunner.launchAgent!
let agentStatus = agent.status()
switch agentStatus {
case .running(let pid):
DispatchQueue.main.async {
routerManager.eventManager.trigger(eventName: "router_start", information: String(pid))
routerManager.routerRunner.routerStatus.setRouterStatus(true)
routerManager.routerRunner.routerStatus.setRouterRanByUs(true)
routerManager.eventManager.trigger(eventName: "router_pid", information: String(pid))
}
break
default:
NSLog("wtf, agent status = \(agentStatus)")
break
}
})
return routerManager
}()

View File

@ -22,7 +22,7 @@ class RouterRunner: NSObject {
let domainLabel = "net.i2p.macosx.I2PRouter"
let plistName = "net.i2p.macosx.I2PRouterAgent.plist"
let plistName = "net.i2p.macosx.I2PRouter.plist"
let defaultStartupCommand:String = "/usr/libexec/java_home"
@ -35,6 +35,10 @@ class RouterRunner: NSObject {
let appSupportPath = FileManager.default.urls(for: FileManager.SearchPathDirectory.applicationSupportDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)
override init() {
super.init()
}
func SetupAgent() {
let agent = SetupAndReturnAgent()
RouterRunner.launchAgent = agent
@ -106,78 +110,70 @@ class RouterRunner: NSObject {
let shouldStartupAtLogin = userPreferences.bool(forKey: "startRouterAtLogin")
agent.runAtLoad = shouldStartupAtLogin
agent.keepAlive = true
do {
try LaunchAgentManager.shared.write(agent, called: self.plistName)
sleep(1)
try LaunchAgentManager.shared.load(agent)
sleep(1)
let agentStatus = LaunchAgentManager.shared.status(agent)
switch agentStatus {
case .running:
break
case .loaded:
break
case .unloaded:
sleep(2)
break
DispatchQueue(label: "background_starter").async {
do {
try LaunchAgentManager.shared.write(agent, called: self.plistName)
sleep(1)
try LaunchAgentManager.shared.load(agent)
sleep(1)
let agentStatus = LaunchAgentManager.shared.status(agent)
switch agentStatus {
case .running:
break
case .loaded:
DispatchQueue.main.async {
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: agent)
}
break
case .unloaded:
break
}
} catch {
DispatchQueue.main.async {
RouterManager.shared().eventManager.trigger(eventName: "router_setup_error", information: "\(error)")
}
}
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: agent)
} catch {
RouterManager.shared().eventManager.trigger(eventName: "router_setup_error", information: "\(error)")
}
return agent
}
func StartAgent(information:Any?) {
let agent = RouterRunner.launchAgent!
LaunchAgentManager.shared.start(agent)
sleep(1)
let agentStatus = agent.status()
switch agentStatus {
case .running(let pid):
RouterManager.shared().eventManager.trigger(eventName: "router_start", information: String(pid))
routerStatus.setRouterStatus(true)
routerStatus.setRouterRanByUs(true)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
// Delayed message to ensure UI has been initialized.
RouterManager.shared().eventManager.trigger(eventName: "router_pid", information: String(pid))
}
break
default: break
func StartAgent(_ information:Any? = nil) {
let agent = RouterRunner.launchAgent ?? information as! LaunchAgent
DispatchQueue(label: "background_block").async {
LaunchAgentManager.shared.start(agent, { (proc) in
NSLog("Will call onLaunchdStarted")
})
}
}
func StopAgent() {
var agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
switch agentStatus {
case .running:
LaunchAgentManager.shared.stop(RouterRunner.launchAgent!)
break
case .loaded, .unloaded:
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
routerStatus.setRouterStatus(false)
routerStatus.setRouterRanByUs(false)
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
return;
break
default: break
}
sleep(1)
agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
switch agentStatus {
case .loaded, .unloaded:
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
routerStatus.setRouterStatus(false)
routerStatus.setRouterRanByUs(false)
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
break
default: break
func StopAgent(_ callback: @escaping () -> () = {}) {
let agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
DispatchQueue(label: "background_block").async {
do {
switch agentStatus {
case .running:
// For now we need to use unload to stop it.
try LaunchAgentManager.shared.unload(RouterRunner.launchAgent!, { (proc) in
// Called when stop is actually executed
proc.waitUntilExit()
DispatchQueue.main.async {
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
callback()
}
})
try LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
break
case .unloaded:
// Seems it sometimes get unloaded on stop, we load it again.
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
return
default: break
}
} catch {
NSLog("Error \(error)")
}
}
}