forked from I2P_Developers/i2p.i2p
OSX Launcher: general cleanup, responsibility delegation, and fixes
This commit is contained in:
@ -93,7 +93,8 @@ class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc static func openLink(url: String) {
|
@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() {
|
@objc func applicationWillTerminate() {
|
||||||
|
111
launchers/macosx/I2PLauncher/Utils/FolderContentMonitor.swift
Normal file
111
launchers/macosx/I2PLauncher/Utils/FolderContentMonitor.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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 */
|
#endif /* logger_c_h */
|
||||||
|
@ -25,6 +25,7 @@ class RouterManager : NSObject {
|
|||||||
let routerRunner = RouterRunner()
|
let routerRunner = RouterRunner()
|
||||||
|
|
||||||
var logViewStorage: NSTextStorage?
|
var logViewStorage: NSTextStorage?
|
||||||
|
var lastRouterPid : String? = nil
|
||||||
|
|
||||||
private static func handleRouterException(information:Any?) {
|
private static func handleRouterException(information:Any?) {
|
||||||
Logger.MLog(level:1,"event! - handle router exception")
|
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_already_running", action: handleRouterAlreadyStarted)
|
||||||
routerManager.eventManager.listenTo(eventName: "router_can_start", action: routerManager.routerRunner.StartAgent)
|
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: "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
|
return routerManager
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class RouterRunner: NSObject {
|
|||||||
|
|
||||||
let domainLabel = "net.i2p.macosx.I2PRouter"
|
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"
|
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)
|
let appSupportPath = FileManager.default.urls(for: FileManager.SearchPathDirectory.applicationSupportDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
func SetupAgent() {
|
func SetupAgent() {
|
||||||
let agent = SetupAndReturnAgent()
|
let agent = SetupAndReturnAgent()
|
||||||
RouterRunner.launchAgent = agent
|
RouterRunner.launchAgent = agent
|
||||||
@ -106,78 +110,70 @@ class RouterRunner: NSObject {
|
|||||||
let shouldStartupAtLogin = userPreferences.bool(forKey: "startRouterAtLogin")
|
let shouldStartupAtLogin = userPreferences.bool(forKey: "startRouterAtLogin")
|
||||||
agent.runAtLoad = shouldStartupAtLogin
|
agent.runAtLoad = shouldStartupAtLogin
|
||||||
agent.keepAlive = true
|
agent.keepAlive = true
|
||||||
|
DispatchQueue(label: "background_starter").async {
|
||||||
do {
|
do {
|
||||||
|
try LaunchAgentManager.shared.write(agent, called: self.plistName)
|
||||||
try LaunchAgentManager.shared.write(agent, called: self.plistName)
|
sleep(1)
|
||||||
sleep(1)
|
try LaunchAgentManager.shared.load(agent)
|
||||||
try LaunchAgentManager.shared.load(agent)
|
sleep(1)
|
||||||
sleep(1)
|
|
||||||
|
let agentStatus = LaunchAgentManager.shared.status(agent)
|
||||||
let agentStatus = LaunchAgentManager.shared.status(agent)
|
switch agentStatus {
|
||||||
switch agentStatus {
|
case .running:
|
||||||
case .running:
|
break
|
||||||
break
|
case .loaded:
|
||||||
case .loaded:
|
DispatchQueue.main.async {
|
||||||
break
|
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: agent)
|
||||||
case .unloaded:
|
}
|
||||||
sleep(2)
|
break
|
||||||
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
|
return agent
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartAgent(information:Any?) {
|
|
||||||
let agent = RouterRunner.launchAgent!
|
func StartAgent(_ information:Any? = nil) {
|
||||||
LaunchAgentManager.shared.start(agent)
|
let agent = RouterRunner.launchAgent ?? information as! LaunchAgent
|
||||||
sleep(1)
|
DispatchQueue(label: "background_block").async {
|
||||||
let agentStatus = agent.status()
|
LaunchAgentManager.shared.start(agent, { (proc) in
|
||||||
switch agentStatus {
|
NSLog("Will call onLaunchdStarted")
|
||||||
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 StopAgent() {
|
func StopAgent(_ callback: @escaping () -> () = {}) {
|
||||||
var agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
|
let agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
|
||||||
switch agentStatus {
|
DispatchQueue(label: "background_block").async {
|
||||||
case .running:
|
do {
|
||||||
LaunchAgentManager.shared.stop(RouterRunner.launchAgent!)
|
switch agentStatus {
|
||||||
break
|
case .running:
|
||||||
case .loaded, .unloaded:
|
// For now we need to use unload to stop it.
|
||||||
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
|
try LaunchAgentManager.shared.unload(RouterRunner.launchAgent!, { (proc) in
|
||||||
routerStatus.setRouterStatus(false)
|
// Called when stop is actually executed
|
||||||
routerStatus.setRouterRanByUs(false)
|
proc.waitUntilExit()
|
||||||
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
|
DispatchQueue.main.async {
|
||||||
return;
|
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
|
||||||
break
|
callback()
|
||||||
default: break
|
}
|
||||||
}
|
})
|
||||||
sleep(1)
|
try LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
|
||||||
agentStatus = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
|
break
|
||||||
switch agentStatus {
|
case .unloaded:
|
||||||
case .loaded, .unloaded:
|
// Seems it sometimes get unloaded on stop, we load it again.
|
||||||
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
|
try! LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
|
||||||
routerStatus.setRouterStatus(false)
|
return
|
||||||
routerStatus.setRouterRanByUs(false)
|
default: break
|
||||||
RouterManager.shared().eventManager.trigger(eventName: "router_stop", information: "ok")
|
}
|
||||||
break
|
} catch {
|
||||||
default: break
|
NSLog("Error \(error)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user