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) {
|
||||
SBridge.sharedInstance().openUrl(url)
|
||||
NSLog("Trying to open \(url)")
|
||||
NSWorkspace.shared().open(NSURL(string: url)! as URL)
|
||||
}
|
||||
|
||||
@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 */
|
||||
|
@ -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
|
||||
}()
|
||||
|
||||
|
@ -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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user