forked from I2P_Developers/i2p.i2p
Mac OS X Launcher:
* Enabled Apple's "Hardened Runtime", however unsecure memory had to be allowed to spawn java etc. * Updated docs about Event Manager code * Make the launcher handle cases where extract is incomplete or invalid * Bugfixes as always
This commit is contained in:
@@ -59,10 +59,18 @@ import Cocoa
|
||||
let sub:Subprocess = Subprocess.init(executablePath: "/bin/sh", arguments: cmdArgs)
|
||||
let results:ExecutionResult = sub.execute(captureOutput: true)!
|
||||
if (results.didCaptureOutput) {
|
||||
let i2pVersion = results.outputLines.first?.replace(target: "I2P Core version: ", withString: "")
|
||||
NSLog("I2P version detected: %@",i2pVersion ?? "Unknown")
|
||||
RouterProcessStatus.routerVersion = i2pVersion
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_version", information: i2pVersion)
|
||||
if (results.status == 0) {
|
||||
let i2pVersion = results.outputLines.first?.replace(target: "I2P Core version: ", withString: "")
|
||||
NSLog("I2P version detected: %@",i2pVersion ?? "Unknown")
|
||||
RouterProcessStatus.routerVersion = i2pVersion
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_version", information: i2pVersion)
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: i2pVersion)
|
||||
} else {
|
||||
NSLog("Non zero exit code from subprocess while trying to detect version number!")
|
||||
for line in results.errorsLines {
|
||||
NSLog(line)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("Warning: Version Detection did NOT captured output")
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import Foundation
|
||||
DetectJava.hasJRE = true
|
||||
self.javaHome = self.javaHome.replace(target: "\n", withString: "").replace(target: "Internet Plug-Ins", withString: "Internet\\ Plug-Ins")
|
||||
print("DetectJava.javaHome did change to "+self.javaHome)
|
||||
RouterManager.shared().eventManager.trigger(eventName: "java_found", information: self.javaHome)
|
||||
}
|
||||
};
|
||||
private var testedEnv : Bool = false
|
||||
|
@@ -8,6 +8,13 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
enum ErrorsInRouterMgmr: Swift.Error {
|
||||
case NoJavaFound
|
||||
case InvalidVersion
|
||||
case NotFound
|
||||
}
|
||||
|
||||
class RouterManager : NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
@@ -18,6 +25,10 @@ class RouterManager : NSObject {
|
||||
|
||||
var logViewStorage: NSTextStorage?
|
||||
|
||||
private static func handleRouterException(information:Any?) {
|
||||
NSLog("event! - handle router exception")
|
||||
NSLog(information as! String)
|
||||
}
|
||||
private static func handleRouterStart(information:Any?) {
|
||||
NSLog("event! - handle router start")
|
||||
RouterProcessStatus.routerStartedAt = Date()
|
||||
@@ -31,17 +42,32 @@ class RouterManager : NSObject {
|
||||
RouterProcessStatus.isRouterRunning = false
|
||||
}
|
||||
private static func handleRouterPid(information:Any?) {
|
||||
Swift.print("event! - handle router pid: %s", information ?? "")
|
||||
Swift.print("event! - handle router pid: ", information ?? "")
|
||||
}
|
||||
private static func handleRouterVersion(information:Any?) {
|
||||
Swift.print("event! - handle router version: %s", information ?? "")
|
||||
let currentVersion : String = information as! String
|
||||
if (packedVersion.compare(currentVersion, options: .numeric) == .orderedDescending) {
|
||||
Swift.print("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")
|
||||
do {
|
||||
Swift.print("event! - handle router version: ", information ?? "")
|
||||
guard let currentVersion : String = information as? String else {
|
||||
throw ErrorsInRouterMgmr.InvalidVersion
|
||||
}
|
||||
if (currentVersion == "Unknown") {
|
||||
throw ErrorsInRouterMgmr.InvalidVersion
|
||||
}
|
||||
if (packedVersion.compare(currentVersion, options: .numeric) == .orderedDescending) {
|
||||
Swift.print("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")
|
||||
}
|
||||
} catch ErrorsInRouterMgmr.InvalidVersion {
|
||||
// This is most likely due to an earlier extract got killed halfway or something
|
||||
// Trigger an update
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_must_upgrade", information: "invalid version found")
|
||||
} catch {
|
||||
// WTF
|
||||
NSLog("Fatal error in RouterManager");
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +83,7 @@ class RouterManager : NSObject {
|
||||
routerManager.eventManager.listenTo(eventName: "router_stop", action: handleRouterStop)
|
||||
routerManager.eventManager.listenTo(eventName: "router_pid", action: handleRouterPid)
|
||||
routerManager.eventManager.listenTo(eventName: "router_version", action: handleRouterVersion)
|
||||
routerManager.eventManager.listenTo(eventName: "router_exception", action: handleRouterException)
|
||||
return routerManager
|
||||
}()
|
||||
|
||||
|
@@ -1,5 +1,24 @@
|
||||
# The Mac OS X Launcher
|
||||
|
||||
## The Event Manager
|
||||
|
||||
This is some Swift code which makes the application use events to signal the different compoents of the application. This seems to be the cleanest way since we're doing java subprocesses and so on. This can also be named a publish-subscribe system as well. If you're familiar with Javascript it would be a handy skill.
|
||||
|
||||
### Event Overview
|
||||
|
||||
| Event name | Details sent as arguments | Description |
|
||||
| ------------- | ------------- | ------------- |
|
||||
| router_start | nothing | This event get triggered when the router starts |
|
||||
| router_exception | exception message | This will be triggered in case something within the functions that start the java (router) subprocess throws an exception |
|
||||
| java_found | the location | This will be triggered once the DetectJava swift class has found java |
|
||||
| router_must_upgrade | nothing | This will be triggered if no I2P is found, or if it's failing to get the version from the jar file |
|
||||
| extract_completed | nothing | This is triggered when the deployment process is done extracting I2P to it's directory |
|
||||
| router_can_start | nothing | This event will be triggered when I2P is found and a version number has been found, router won't start before this event |
|
||||
| router_stop | error if any | Triggered when the router subprocess exits |
|
||||
| router_pid | the pid number as string | Triggered when we know the pid of the router subprocess |
|
||||
| router_version | the version string | Triggered when we have successfully extracted current I2P version |
|
||||
| extract_errored | the error message | Triggered if the process didn't exit correctly |
|
||||
|
||||
## Misc
|
||||
|
||||
**Note** this project is WIP, cause Meeh has yet to merge in Obj-C/Swift code for GUI stuff in OSX.
|
||||
|
@@ -85,9 +85,7 @@
|
||||
NSLog(@"Expection occurred %@", [e reason]);
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
self.isRouterRunning = NO;
|
||||
[swiftRouterStatus setRouterStatus: false];
|
||||
[swiftRouterStatus setRouterRanByUs: false];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_stop" details:@"error shutdown"];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_exception" details:[e reason]];
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
sendUserNotification(@"An error occured, can't start the I2P Router", [e reason]);
|
||||
return 0;
|
||||
|
@@ -36,16 +36,15 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:instance];
|
||||
[instance execute];
|
||||
sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
|
||||
auto pid = [instance getPID];
|
||||
NSLog(@"Got pid: %d", pid);
|
||||
if (routerStatus != nil) {
|
||||
[routerStatus setRouterStatus: true];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
[routerStatus triggerEventWithEn:@"router_start" details:@"normal start"];
|
||||
[routerStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
|
||||
}
|
||||
sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
|
||||
auto pid = [instance getPID];
|
||||
NSLog(@"Got pid: %d", pid);
|
||||
|
||||
if (routerStatus != nil) [routerStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
|
||||
|
||||
return std::async(std::launch::async, [&pid]{
|
||||
return pid;
|
||||
@@ -59,8 +58,6 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
|
||||
if (routerStatus != nil) {
|
||||
[routerStatus setRouterStatus: false];
|
||||
[routerStatus setRouterRanByUs: false];
|
||||
[routerStatus triggerEventWithEn:@"router_exception" details:errStr];
|
||||
}
|
||||
|
||||
|
@@ -107,23 +107,16 @@ using namespace subprocess;
|
||||
for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
|
||||
|
||||
NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
|
||||
try {
|
||||
sendUserNotification(APP_IDSTR, @"Please hold on while we extract I2P. You'll get a new message once done!");
|
||||
int extractStatus = Popen(execStr.c_str(), environment{{
|
||||
{"ZIPPATH", zippath.c_str()},
|
||||
{"I2PBASE", basePath.c_str()}
|
||||
}}).wait();
|
||||
NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
|
||||
if (extractStatus == 0)
|
||||
{
|
||||
NSLog(@"Extraction complete!");
|
||||
}
|
||||
|
||||
} catch (subprocess::OSError &err) {
|
||||
auto errMsg = [NSString stringWithUTF8String:err.what()];
|
||||
//success = NO;
|
||||
NSLog(@"Exception: %@", errMsg);
|
||||
sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
|
||||
sendUserNotification(APP_IDSTR, @"Please hold on while we extract I2P. You'll get a new message once done!");
|
||||
int extractStatus = Popen(execStr.c_str(), environment{{
|
||||
{"ZIPPATH", zippath.c_str()},
|
||||
{"I2PBASE", basePath.c_str()}
|
||||
}}).wait();
|
||||
NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
|
||||
if (extractStatus == 0) {
|
||||
NSLog(@"Extraction process done");
|
||||
} else {
|
||||
NSLog(@"Something went wrong");
|
||||
}
|
||||
|
||||
// All done. Assume success and error are already set.
|
||||
@@ -137,6 +130,7 @@ using namespace subprocess;
|
||||
} catch (OSError &err) {
|
||||
auto errMsg = [NSString stringWithUTF8String:err.what()];
|
||||
NSLog(@"Exception: %@", errMsg);
|
||||
sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -224,27 +218,52 @@ using namespace subprocess;
|
||||
|
||||
// This will trigger the router start after an upgrade.
|
||||
[routerStatus listenForEventWithEventName:@"router_must_upgrade" callbackActionFn:^(NSString* information) {
|
||||
NSLog(@"Got signal, router must be upgraded");
|
||||
NSLog(@"Got signal, router must be deployed from base.zip");
|
||||
[self extractI2PBaseDir:^(BOOL success, NSError *error) {
|
||||
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
|
||||
NSLog(@"Done extracting I2P");
|
||||
[routerStatus triggerEventWithEn:@"router_can_start" details:@"upgrade complete"];
|
||||
if (success && error != nil) {
|
||||
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
|
||||
NSLog(@"Done extracting I2P");
|
||||
[routerStatus triggerEventWithEn:@"extract_completed" details:@"upgrade complete"];
|
||||
} else {
|
||||
NSLog(@"Error while extracting I2P");
|
||||
[routerStatus triggerEventWithEn:@"extract_errored" details:[NSString stringWithFormat:@"%@", error]];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
// Initialize the Swift environment (the UI components)
|
||||
[self.swiftRuntime applicationDidFinishLaunching];
|
||||
|
||||
NSString *nsI2PBaseStr = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
|
||||
|
||||
struct stat sb;
|
||||
if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
|
||||
|
||||
//struct stat sb;
|
||||
//if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
|
||||
BOOL shouldBeTrueOnReturnDir = YES;
|
||||
if (! [NSFileManager.defaultManager fileExistsAtPath: nsI2PBaseStr isDirectory: &shouldBeTrueOnReturnDir])
|
||||
{
|
||||
// I2P is not extracted.
|
||||
if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
|
||||
[routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
|
||||
if (shouldBeTrueOnReturnDir) {
|
||||
if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
|
||||
[routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
|
||||
} else {
|
||||
// TODO: handle if i2p path exists but it's not a dir.
|
||||
}
|
||||
} else {
|
||||
// I2P was already found extracted
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
NSString *nsI2pJar = [NSString stringWithFormat:@"%@/lib/i2p.jar", nsI2PBaseStr];
|
||||
|
||||
// But does I2PBASE/lib/i2p.jar exists?
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:nsI2pJar]) {
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
} else {
|
||||
// The directory exists, but not i2p.jar - most likely we're in mid-extraction state.
|
||||
[routerStatus listenForEventWithEventName:@"extract_completed" callbackActionFn:^(NSString* information) {
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
. .sign-secrets
|
||||
|
||||
APP_NAME="I2PLauncher"
|
||||
VERSION="0.9.36"
|
||||
DMG_BACKGROUND_IMG="Background.png"
|
||||
@@ -98,6 +100,8 @@ hdiutil detach "${DEVICE}"
|
||||
echo "Creating compressed image"
|
||||
hdiutil convert "${DMG_TMP}" -format UDZO -imagekey zlib-level=9 -o "${DMG_FINAL}"
|
||||
|
||||
codesign --force --sign "${APPLE_CODE_SIGNER_ID}" "${DMG_FINAL}"
|
||||
|
||||
# clean up
|
||||
rm -rf "${DMG_TMP}"
|
||||
rm -rf "${STAGING_DIR}"
|
||||
|
Reference in New Issue
Block a user