forked from I2P_Developers/i2p.i2p
OSX Launcher: major updates to the glue between 'backend' and GUI. Implemented the use of the new LaunchAgent classes
This commit is contained in:
@@ -19,34 +19,42 @@ class RouterManager : NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
static let packedVersion : String = "0.9.36"
|
||||
static let packedVersion : String = "0.9.37"
|
||||
|
||||
let eventManager = EventManager()
|
||||
let routerRunner = RouterRunner()
|
||||
|
||||
var logViewStorage: NSTextStorage?
|
||||
|
||||
private static func handleRouterException(information:Any?) {
|
||||
NSLog("event! - handle router exception")
|
||||
NSLog(information as! String)
|
||||
Logger.MLog(level:1,"event! - handle router exception")
|
||||
Logger.MLog(level:1,information as! String)
|
||||
}
|
||||
private static func handleRouterStart(information:Any?) {
|
||||
NSLog("event! - handle router start")
|
||||
Logger.MLog(level:1,"event! - handle router start")
|
||||
RouterProcessStatus.routerStartedAt = Date()
|
||||
RouterProcessStatus.isRouterChildProcess = true
|
||||
RouterProcessStatus.isRouterRunning = true
|
||||
}
|
||||
private static func handleRouterAlreadyStarted(information:Any?) {
|
||||
Logger.MLog(level:1,"event! - handle router already started");
|
||||
}
|
||||
private static func handleRouterStop(information:Any?) {
|
||||
NSLog("event! - handle router stop")
|
||||
Logger.MLog(level:1,"event! - handle router stop")
|
||||
// TODO: Double check, check if pid stored exists
|
||||
RouterProcessStatus.routerStartedAt = nil
|
||||
RouterProcessStatus.isRouterChildProcess = false
|
||||
RouterProcessStatus.isRouterRunning = false
|
||||
}
|
||||
private static func handleRouterPid(information:Any?) {
|
||||
Swift.print("event! - handle router pid: ", information ?? "")
|
||||
Logger.MLog(level:1,"".appendingFormat("event! - handle router pid: ", information as! String!))
|
||||
if (information != nil) {
|
||||
let intPid = Int(information as! String)
|
||||
}
|
||||
}
|
||||
private static func handleRouterVersion(information:Any?) {
|
||||
do {
|
||||
Swift.print("event! - handle router version: ", information ?? "")
|
||||
Logger.MLog(level:1, "".appendingFormat("event! - handle router version: ", information as! String!))
|
||||
guard let currentVersion : String = information as? String else {
|
||||
throw ErrorsInRouterMgmr.InvalidVersion
|
||||
}
|
||||
@@ -54,11 +62,11 @@ class RouterManager : NSObject {
|
||||
throw ErrorsInRouterMgmr.InvalidVersion
|
||||
}
|
||||
if (packedVersion.compare(currentVersion, options: .numeric) == .orderedDescending) {
|
||||
Swift.print("event! - router version: Packed version is newer, gonna re-deploy")
|
||||
Logger.MLog(level:1,"event! - router version: Packed version is newer, gonna re-deploy")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_must_upgrade", information: "got new version")
|
||||
} else {
|
||||
Swift.print("event! - router version: No update needed")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: "all ok")
|
||||
Logger.MLog(level:1,"event! - router version: No update needed")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_can_setup", information: "all ok")
|
||||
}
|
||||
} catch ErrorsInRouterMgmr.InvalidVersion {
|
||||
// This is most likely due to an earlier extract got killed halfway or something
|
||||
@@ -72,8 +80,7 @@ class RouterManager : NSObject {
|
||||
}
|
||||
|
||||
private static var sharedRouterManager: RouterManager = {
|
||||
let inst = DetectJava()
|
||||
let routerManager = RouterManager(detectJavaInstance: inst)
|
||||
let routerManager = RouterManager(detectJavaInstance: DetectJava.shared())
|
||||
|
||||
// Configuration
|
||||
// ...
|
||||
@@ -84,6 +91,9 @@ class RouterManager : NSObject {
|
||||
routerManager.eventManager.listenTo(eventName: "router_pid", action: handleRouterPid)
|
||||
routerManager.eventManager.listenTo(eventName: "router_version", action: handleRouterVersion)
|
||||
routerManager.eventManager.listenTo(eventName: "router_exception", action: handleRouterException)
|
||||
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)
|
||||
return routerManager
|
||||
}()
|
||||
|
||||
@@ -108,6 +118,13 @@ class RouterManager : NSObject {
|
||||
|
||||
// MARK: - Accessors
|
||||
|
||||
static func logInfo(format: String, messages: String...) {
|
||||
//SBridge.sharedInstance().logMessageWithFormat(0, format, messages)func k(_ x: Int32, _ params: String...) {
|
||||
/*withVaList(messages) {
|
||||
genericLogger(x, $0)
|
||||
}*/
|
||||
}
|
||||
|
||||
class func shared() -> RouterManager {
|
||||
return sharedRouterManager
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import Foundation
|
||||
|
||||
extension RouterProcessStatus {
|
||||
|
||||
static func createNewRouterProcess(i2pPath: String, javaBinPath: String) {
|
||||
static func createNewRouterProcess(i2pPath: String) {
|
||||
let timeWhenStarted = Date()
|
||||
RouterProcessStatus.routerStartedAt = timeWhenStarted
|
||||
SBridge.sharedInstance().startupI2PRouter(i2pPath, javaBinPath: javaBinPath)
|
||||
SBridge.sharedInstance().startupI2PRouter(i2pPath)
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
static func shutdownRouterChildProcess() {
|
||||
|
||||
@@ -30,7 +30,11 @@ import AppKit
|
||||
}
|
||||
|
||||
@objc func getJavaHome() -> String {
|
||||
return RouterProcessStatus.knownJavaBinPath!
|
||||
return DetectJava.shared().javaHome
|
||||
}
|
||||
|
||||
@objc func getJavaViaLibexec() -> Array<String> {
|
||||
return DetectJava.shared().getJavaViaLibexecBin()
|
||||
}
|
||||
|
||||
@objc func triggerEvent(en: String, details: String? = nil) {
|
||||
@@ -47,10 +51,8 @@ extension RouterProcessStatus {
|
||||
static var isRouterChildProcess : Bool = (RouterManager.shared().getRouterTask() != nil)
|
||||
static var routerVersion : String? = Optional.none
|
||||
static var routerStartedAt : Date? = Optional.none
|
||||
static var knownJavaBinPath : String? = Optional.none
|
||||
static var i2pDirectoryPath : String = NSHomeDirectory() + "/Library/I2P"
|
||||
|
||||
static var knownRouterSubTaskRef : I2PSubprocess? = Optional.none
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,62 +8,212 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class RouterRunner: NSObject, I2PSubprocess {
|
||||
class RouterRunner: NSObject {
|
||||
|
||||
var subprocessPath: String?
|
||||
|
||||
var daemonPath: String?
|
||||
var arguments: String?
|
||||
var timeWhenStarted: Date?
|
||||
|
||||
static var launchAgent: LaunchAgent?
|
||||
let routerStatus: RouterProcessStatus = RouterProcessStatus()
|
||||
|
||||
var currentRunningProcess: Subprocess?
|
||||
var currentProcessResults: ExecutionResult?
|
||||
|
||||
func findJava() {
|
||||
self.subprocessPath = RouterProcessStatus.knownJavaBinPath
|
||||
}
|
||||
let domainLabel = "net.i2p.macosx.I2PRouter"
|
||||
|
||||
let defaultStartupFlags:[String] = [
|
||||
"-Xmx512M",
|
||||
"-Xms128m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dwrapper.logfile=/tmp/router.log",
|
||||
"-Dwrapper.logfile.loglevel=DEBUG",
|
||||
"-Dwrapper.java.pidfile=/tmp/routerjvm.pid",
|
||||
"-Dwrapper.console.loglevel=DEBUG"
|
||||
let plistName = "net.i2p.macosx.I2PRouterAgent.plist"
|
||||
|
||||
let defaultStartupCommand:String = "/usr/libexec/java_home"
|
||||
|
||||
let defaultJavaHomeArgs:[String] = [
|
||||
"-v",
|
||||
"1.7+",
|
||||
"--exec",
|
||||
"java",
|
||||
]
|
||||
|
||||
private func subInit(cmdPath: String?, cmdArgs: String?) {
|
||||
// Use this as common init
|
||||
self.subprocessPath = cmdPath
|
||||
self.arguments = cmdArgs
|
||||
if (self.arguments?.isEmpty)! {
|
||||
self.arguments = Optional.some(defaultStartupFlags.joined(separator: " "))
|
||||
};
|
||||
let newArgs:[String] = ["-c ",
|
||||
self.subprocessPath!,
|
||||
" ",
|
||||
self.arguments!,
|
||||
]
|
||||
self.currentRunningProcess = Optional.some(Subprocess.init(executablePath: "/bin/sh", arguments: newArgs))
|
||||
let appSupportPath = FileManager.default.urls(for: FileManager.SearchPathDirectory.applicationSupportDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)
|
||||
|
||||
func SetupAgent() {
|
||||
let agent = SetupAndReturnAgent()
|
||||
RouterRunner.launchAgent = agent
|
||||
}
|
||||
|
||||
init(cmdPath: String?, _ cmdArgs: String? = Optional.none) {
|
||||
super.init()
|
||||
self.subInit(cmdPath: cmdPath, cmdArgs: cmdArgs)
|
||||
typealias Async = (_ success: () -> Void, _ failure: (NSError) -> Void) -> Void
|
||||
|
||||
func retry(numberOfTimes: Int, _ sleepForS: UInt32, task: () -> Async, success: () -> Void, failure: (NSError) -> Void) {
|
||||
task()(success, { error in
|
||||
if numberOfTimes > 1 {
|
||||
sleep(sleepForS)
|
||||
retry(numberOfTimes: numberOfTimes - 1, sleepForS, task: task, success: success, failure: failure)
|
||||
} else {
|
||||
failure(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
init(coder: NSCoder) {
|
||||
super.init()
|
||||
self.subInit(cmdPath: Optional.none, cmdArgs: Optional.none)
|
||||
}
|
||||
|
||||
func execute() {
|
||||
if (self.currentRunningProcess != Optional.none!) {
|
||||
print("Already executing! Process ", self.toString())
|
||||
}
|
||||
self.timeWhenStarted = Date()
|
||||
RouterProcessStatus.routerStartedAt = self.timeWhenStarted
|
||||
func SetupAndReturnAgent() -> LaunchAgent {
|
||||
|
||||
self.currentProcessResults = self.currentRunningProcess?.execute(captureOutput: true)
|
||||
let defaultStartupFlags:[String] = [
|
||||
"-Xmx512M",
|
||||
"-Xms128m",
|
||||
"-Djava.awt.headless=true",
|
||||
"".appendingFormat("-Di2p.base.dir=%@", NSHomeDirectory()+"/Library/I2P"),
|
||||
"".appendingFormat("-Dwrapper.logfile=%@/Library/I2P/router.log", NSHomeDirectory()),
|
||||
"-Dwrapper.logfile.loglevel=DEBUG",
|
||||
"".appendingFormat("-Dwrapper.java.pidfile=%@/i2p/router.pid", appSupportPath.description),
|
||||
"-Dwrapper.console.loglevel=DEBUG",
|
||||
"net.i2p.router.Router"
|
||||
]
|
||||
|
||||
self.daemonPath = self.defaultStartupCommand
|
||||
self.arguments = defaultStartupFlags.joined(separator: " ")
|
||||
|
||||
let basePath = NSHomeDirectory()+"/Library/I2P"
|
||||
|
||||
let jars = try! FileManager.default.contentsOfDirectory(atPath: basePath+"/lib")
|
||||
var classpath:String = "."
|
||||
for jar in jars {
|
||||
classpath += ":"+basePath+"/lib/"+jar
|
||||
}
|
||||
|
||||
var cliArgs:[String] = [
|
||||
self.daemonPath!,
|
||||
]
|
||||
cliArgs.append(contentsOf: self.defaultJavaHomeArgs)
|
||||
cliArgs.append(contentsOf: [
|
||||
"-cp",
|
||||
classpath,
|
||||
])
|
||||
cliArgs.append(contentsOf: defaultStartupFlags)
|
||||
let agent = LaunchAgent(label: self.domainLabel,program: cliArgs)
|
||||
agent.launchOnlyOnce = false
|
||||
agent.keepAlive = false
|
||||
agent.workingDirectory = basePath
|
||||
agent.userName = NSUserName()
|
||||
agent.standardErrorPath = NSHomeDirectory()+"/Library/Logs/I2P/router.stderr.log"
|
||||
agent.standardOutPath = NSHomeDirectory()+"/Library/Logs/I2P/router.stdout.log"
|
||||
agent.environmentVariables = [
|
||||
"PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
|
||||
"I2PBASE": basePath,
|
||||
]
|
||||
agent.disabled = false
|
||||
agent.processType = ProcessType.adaptive
|
||||
RouterRunner.launchAgent = agent
|
||||
|
||||
let userPreferences = UserDefaults.standard
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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 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 SetupLaunchd() {
|
||||
do {
|
||||
try LaunchAgentManager.shared.write(RouterRunner.launchAgent!, called: self.plistName)
|
||||
try LaunchAgentManager.shared.load(RouterRunner.launchAgent!)
|
||||
} catch {
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_exception", information: error)
|
||||
}
|
||||
}
|
||||
|
||||
func TeardownLaunchd() {
|
||||
/*let status = LaunchAgentManager.shared.status(RouterRunner.launchAgent!)
|
||||
switch status {
|
||||
case .running:*/
|
||||
do {
|
||||
// Unload no matter previous state!
|
||||
try LaunchAgentManager.shared.unload(RouterRunner.launchAgent!)
|
||||
|
||||
let plistPath = NSHomeDirectory()+"/Library/LaunchAgents/"+self.plistName
|
||||
|
||||
sleep(1)
|
||||
if FileManager.default.fileExists(atPath: plistPath) {
|
||||
try FileManager.default.removeItem(atPath: plistPath)
|
||||
}
|
||||
} catch LaunchAgentManagerError.urlNotSet(label: self.domainLabel) {
|
||||
Logger.MLog(level:3, "URL not set in launch agent")
|
||||
} catch {
|
||||
Logger.MLog(level:3, "".appendingFormat("Error in launch agent: %s", error as CVarArg))
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_exception", information: error)
|
||||
}
|
||||
/* break
|
||||
default: break
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user