diff --git a/launchers/macosx/obj-cpp/AppDelegate.h b/launchers/macosx/obj-cpp/AppDelegate.h index 066be4b001..ad20e10c36 100644 --- a/launchers/macosx/obj-cpp/AppDelegate.h +++ b/launchers/macosx/obj-cpp/AppDelegate.h @@ -16,28 +16,48 @@ #include #include + +#define DEF_I2P_VERSION "0.9.35" +#define APPDOMAIN "net.i2p.launcher" +#define NSAPPDOMAIN @APPDOMAIN +#define CFAPPDOMAIN CFSTR(APPDOMAIN) +#define APP_IDSTR @"I2P Launcher" + + using namespace neither; +using maybeAnRouterRunner = std::experimental::optional; + + extern JvmListSharedPtr gRawJvmList; // DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY. -maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{}; +static std::mutex globalRouterStatusMutex; +static maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{}; -maybeAnRouterRunner getGlobalRouterObject() -{ - std::lock_guard lock(globalRouterStatusMutex); - return globalRouterStatus; -} +maybeAnRouterRunner getGlobalRouterObject(); +void setGlobalRouterObject(RouterTask* newRouter); -void setGlobalRouterObject(RouterTask* newRouter) -{ - std::lock_guard lock(globalRouterStatusMutex); - globalRouterStatus.emplace(newRouter); -} +@class ExtractMetaInfo; +@interface ExtractMetaInfo : NSObject +@property (strong) NSString* i2pBase; +@property (strong) NSString* javaBinary; +@property (strong) NSString* zipFile; +@property (strong) NSString* jarFile; +@end +inline void sendUserNotification(NSString* title, NSString* informativeText, NSImage* contentImage = NULL, bool makeSound = false) { + NSUserNotification *userNotification = [[[NSUserNotification alloc] init] autorelease]; + userNotification.title = title; + userNotification.informativeText = informativeText; + if (contentImage != NULL) userNotification.contentImage = contentImage; + if (makeSound) userNotification.soundName = NSUserNotificationDefaultSoundName; -std::vector globVector(const std::string& pattern){ + [[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:userNotification]; +}; + +inline std::vector globVector(const std::string& pattern){ glob_t glob_result; glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result); std::vector files; @@ -63,6 +83,7 @@ std::vector globVector(const std::string& pattern){ - (void) btnPressedAction:(id)sender; - (void) menuWillOpen:(NSMenu *)menu; +- (void) openRouterConsoleBtnHandler: (NSMenuItem *) menuItem; - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem; - (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem; - (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem; @@ -85,6 +106,9 @@ std::vector globVector(const std::string& pattern){ @property (strong) NSUserDefaults *userPreferences; @property BOOL enableLogging; @property BOOL enableVerboseLogging; +@property (copy) NSImage *contentImage NS_AVAILABLE(10_9, NA); +- (void)extractI2PBaseDir:(ExtractMetaInfo *)metaInfo completion:(void(^)(BOOL success, NSError *error))completion; +- (void)startupI2PRouter:(ExtractMetaInfo *)metaInfo; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification; - (void)applicationWillTerminate:(NSNotification *)aNotification; - (void)setApplicationDefaultPreferences; diff --git a/launchers/macosx/obj-cpp/JavaHelper.h b/launchers/macosx/obj-cpp/JavaHelper.h index dc8080757c..06c90e51e1 100644 --- a/launchers/macosx/obj-cpp/JavaHelper.h +++ b/launchers/macosx/obj-cpp/JavaHelper.h @@ -26,12 +26,6 @@ using namespace subprocess; using namespace neither; -using maybeAnRouterRunner = std::experimental::optional; - -extern std::mutex globalRouterStatusMutex; -extern maybeAnRouterRunner globalRouterStatus; - - #define DEF_MIN_JVM_VER "1.7+" class JvmVersion diff --git a/launchers/macosx/obj-cpp/RouterTask.h b/launchers/macosx/obj-cpp/RouterTask.h index cc93fa7d71..9c29a1d521 100644 --- a/launchers/macosx/obj-cpp/RouterTask.h +++ b/launchers/macosx/obj-cpp/RouterTask.h @@ -30,8 +30,12 @@ @property (strong) NSMutableData *totalLogData; @property (strong) NSPipe *processPipe; @property (strong) NSFileHandle *input; +@property (atomic) BOOL userRequestedRestart; - (instancetype) initWithOptions : (RTaskOptions*) options; - (int) execute; +- (void) requestShutdown; +- (void) requestRestart; +- (BOOL) isRunning; - (int) getPID; @end diff --git a/launchers/macosx/obj-cpp/RouterTask.mm b/launchers/macosx/obj-cpp/RouterTask.mm index e3f6772124..fb54ead119 100644 --- a/launchers/macosx/obj-cpp/RouterTask.mm +++ b/launchers/macosx/obj-cpp/RouterTask.mm @@ -6,6 +6,7 @@ #include "optional.hpp" #include "subprocess.hpp" +#include "PidWatcher.h" #import @@ -14,8 +15,10 @@ @implementation RouterTask + - (instancetype) initWithOptions : (RTaskOptions*) options { + self.userRequestedRestart = FALSE; self.input = [NSFileHandle fileHandleWithStandardInput]; self.routerTask = [NSTask new]; self.processPipe = [NSPipe new]; @@ -27,6 +30,9 @@ [self.routerTask setEnvironment: envDict]; [self.routerTask setStandardOutput:self.processPipe]; [self.routerTask setStandardError:self.processPipe]; + [self.routerTask setTerminationHandler:^(NSTask* task) { + NSLog(@"termHandler triggered!"); + }]; /* self.readLogHandle = [self.processPipe fileHandleForReading]; NSData *inData = nil; @@ -40,10 +46,26 @@ return self; } +- (void) requestShutdown +{ + [self.routerTask interrupt]; +} + +- (void) requestRestart +{ + self.userRequestedRestart = TRUE; +} + +- (BOOL) isRunning +{ + return self.routerTask.running; +} + - (int) execute { //@try { [self.routerTask launch]; + watchPid([self.routerTask processIdentifier]); [self.input waitForDataInBackgroundAndNotify]; [[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify]; [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification @@ -84,8 +106,6 @@ using namespace subprocess; -std::mutex globalRouterStatusMutex; - const std::vector JavaRunner::defaultStartupFlags { @"-Xmx512M", @"-Xms128m", diff --git a/launchers/macosx/obj-cpp/build.ninja b/launchers/macosx/obj-cpp/build.ninja index d5e9aa8f8f..ef74c5d440 100644 --- a/launchers/macosx/obj-cpp/build.ninja +++ b/launchers/macosx/obj-cpp/build.ninja @@ -1,5 +1,6 @@ cxx = clang++ -cflags = -std=c++14 -g -Wall -I./include -I./include/neither -I/usr/local/include -I/usr/include -Wno-unused-variable -mmacosx-version-min=10.10 +cflags = -std=c++14 -g -Wall -I./include -I./include/neither -I/usr/local/include -I/usr/include $ + -Wno-unused-function -Wno-incomplete-implementation -Wno-unused-variable -mmacosx-version-min=10.10 ldflags = -framework CoreFoundation -framework Foundation -framework Cocoa -g -rdynamic diff --git a/launchers/macosx/obj-cpp/include/strutil.hpp b/launchers/macosx/obj-cpp/include/strutil.hpp index a906b46cce..b27d4f70ed 100644 --- a/launchers/macosx/obj-cpp/include/strutil.hpp +++ b/launchers/macosx/obj-cpp/include/strutil.hpp @@ -14,7 +14,7 @@ #include #include -std::string strprintf(const char *fromat, ...) +inline std::string strprintf(const char *fromat, ...) { std::string s; s.resize(128); // best guess @@ -37,7 +37,7 @@ std::string strprintf(const char *fromat, ...) return s; // move semantics FTW } -std::string extractString(CFStringRef value) +inline std::string extractString(CFStringRef value) { const char * data = CFStringGetCStringPtr(value, kCFStringEncodingUTF8); if (data != NULL) @@ -56,7 +56,7 @@ std::string extractString(CFStringRef value) using std::experimental::optional; // Use CFStringRef instead of NSString*, otherwise disable ARC -optional optionalString(bool val) { +inline optional optionalString(bool val) { optional myOptString; if(val) { // Cast to corresponding CoreFoundation object diff --git a/launchers/macosx/obj-cpp/main.mm b/launchers/macosx/obj-cpp/main.mm index 345c53e7d1..e5f6583227 100644 --- a/launchers/macosx/obj-cpp/main.mm +++ b/launchers/macosx/obj-cpp/main.mm @@ -31,11 +31,6 @@ #include "fn.h" #include "optional.hpp" -#define DEF_I2P_VERSION "0.9.35" -#define APPDOMAIN "net.i2p.launcher" -#define NSAPPDOMAIN @APPDOMAIN -#define CFAPPDOMAIN CFSTR(APPDOMAIN) - #define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]); JvmListSharedPtr gRawJvmList = nullptr; @@ -48,6 +43,18 @@ JvmListSharedPtr gRawJvmList = nullptr; @end +maybeAnRouterRunner getGlobalRouterObject() +{ + std::lock_guard lock(globalRouterStatusMutex); + return globalRouterStatus; +} + +void setGlobalRouterObject(RouterTask* newRouter) +{ + std::lock_guard lock(globalRouterStatusMutex); + globalRouterStatus.emplace(newRouter); +} + std::future startupRouter(NSString* javaBin, NSArray* arguments, NSString* i2pBaseDir) { /* NSLog(@"Arguments: %@", [NSString stringWithUTF8String:arguments.c_str()]); @@ -72,7 +79,7 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, return 0; }); */ - CFShow(arguments); + //CFShow(arguments); @try { RTaskOptions* options = [RTaskOptions alloc]; @@ -80,22 +87,31 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, options.arguments = arguments; options.i2pBaseDir = i2pBaseDir; auto instance = [[[RouterTask alloc] initWithOptions: options] autorelease]; - //auto pid = [instance execute]; + setGlobalRouterObject(instance); //NSThread *thr = [[NSThread alloc] initWithTarget:instance selector:@selector(execute) object:nil]; [instance execute]; - return std::async(std::launch::async, [&instance]{ - return 1;//[instance getPID]; + sendUserNotification(APP_IDSTR, @"The I2P router is starting up."); + auto pid = [instance getPID]; + return std::async(std::launch::async, [&pid]{ + return pid; }); } @catch (NSException *e) { - NSLog(@"Expection occurred %@", [e reason]); + auto errStr = [NSString stringWithFormat:@"Expection occurred %@",[e reason]]; + NSLog(@"%@", errStr); + sendUserNotification(APP_IDSTR, errStr); return std::async(std::launch::async, [&]{ return 0; }); } } +void openUrl(NSString* url) +{ + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: url]]; +} + @implementation MenuBarCtrl @@ -123,6 +139,12 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, NSEvent *event = [NSApp currentEvent]; } +- (void) openRouterConsoleBtnHandler: (NSMenuItem *) menuItem +{ + NSLog(@"Clicked openRouterConsoleBtnHandler"); + openUrl(@"http://127.0.0.1:7657"); +} + - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem { NSLog(@"Clicked startJavaRouterBtnHandler"); @@ -131,6 +153,12 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, - (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem { NSLog(@"Clicked restartJavaRouterBtnHandler"); + if (getGlobalRouterObject().has_value()) + { + sendUserNotification(APP_IDSTR, @"Requesting the I2P router to restart."); + [getGlobalRouterObject().value() requestRestart]; + NSLog(@"Requested restart"); + } } - (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem @@ -138,7 +166,8 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, NSLog(@"Clicked stopJavaRouterBtnHandler"); if (getGlobalRouterObject().has_value()) { - //getGlobalRouterObject().value()->requestRouterShutdown(); + sendUserNotification(APP_IDSTR, @"Requesting the I2P router to shutdown."); + [getGlobalRouterObject().value() requestShutdown]; NSLog(@"Requested shutdown"); } } @@ -185,6 +214,14 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, { NSMenu *menu = [[NSMenu alloc] init]; [menu setAutoenablesItems:NO]; + + NSMenuItem *openConsoleI2Pbtn = + [[NSMenuItem alloc] initWithTitle:@"Open Console" + action:@selector(openRouterConsoleBtnHandler:) + keyEquivalent:@""]; + [openConsoleI2Pbtn setTarget:self]; + [openConsoleI2Pbtn setEnabled:YES]; + NSMenuItem *startI2Pbtn = [[NSMenuItem alloc] initWithTitle:@"Start I2P" action:@selector(startJavaRouterBtnHandler:) @@ -219,6 +256,7 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, [quitWrapperBtn setEnabled:YES]; + [menu addItem:openConsoleI2Pbtn]; [menu addItem:startI2Pbtn]; [menu addItem:stopI2Pbtn]; [menu addItem:restartI2Pbtn]; @@ -228,9 +266,127 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, @end +@implementation ExtractMetaInfo +@end @implementation AppDelegate +- (void)extractI2PBaseDir:(ExtractMetaInfo *)metaInfo completion:(void(^)(BOOL success, NSError *error))completion +{ + std::string basePath([metaInfo.i2pBase UTF8String]); + NSParameterAssert(metaInfo.i2pBase); + NSError *error = NULL; + BOOL success; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + // Get paths + NSBundle *launcherBundle = [NSBundle mainBundle]; + + std::string basearg("-Di2p.dir.base="); + basearg += basePath; + + std::string zippath("-Di2p.base.zip="); + zippath += [metaInfo.zipFile UTF8String]; + + std::string jarfile("-cp "); + jarfile += [metaInfo.jarFile UTF8String]; + + // Create directory + mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); + + auto cli = JavaRunner::defaultFlagsForExtractorJob; + setenv("I2PBASE", basePath.c_str(), true); + setenv("ZIPPATH", zippath.c_str(), true); + //setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true); + + cli.push_back(basearg); + cli.push_back(zippath); + cli.push_back(jarfile); + cli.push_back("net.i2p.launchers.BaseExtractor"); + + //auto charCli = map(cli, [](std::string str){ return str.c_str(); }); + std::string execStr = [metaInfo.javaBinary UTF8String]; + 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!", self.contentImage); + 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) + { + //success = YES; + } + } catch (subprocess::OSError &err) { + auto errMsg = [NSString stringWithUTF8String:err.what()]; + //success = NO; + NSLog(@"Exception: %@", errMsg); + sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg], self.contentImage); + } + + // All done. Assume success and error are already set. + dispatch_async(dispatch_get_main_queue(), ^{ + sendUserNotification(APP_IDSTR, @"Extraction complete!", self.contentImage); + if (completion) { + completion(success, error); + } + }); + }); +} + +- (void)startupI2PRouter:(ExtractMetaInfo *)metaInfo +{ + std::string basePath([metaInfo.i2pBase UTF8String]); + auto buildClassPath = [](std::string basePath) -> std::vector { + return globVector(basePath+std::string("/lib/*.jar")); + }; + // Expect base to be extracted by now. + + // Get paths + NSBundle *launcherBundle = [NSBundle mainBundle]; + auto jarList = buildClassPath(basePath); + std::string classpathStrHead = "-classpath"; + std::string classpathStr = ""; + classpathStr += [[launcherBundle pathForResource:@"launcher" ofType:@"jar"] UTF8String]; + std::string prefix(basePath); + prefix += "/lib/"; + for_each(jarList, [&classpathStr](std::string str){ classpathStr += std::string(":") + str; }); + //if (self.enableVerboseLogging) NSLog(@"Classpath: %@\n",[NSString stringWithUTF8String:classpathStr.c_str()]); + + try { + auto argList = JavaRunner::defaultStartupFlags; + + std::string baseDirArg("-Di2p.dir.base="); + baseDirArg += basePath; + std::string javaLibArg("-Djava.library.path="); + javaLibArg += basePath; + // TODO: pass this to JVM + auto java_opts = getenv("JAVA_OPTS"); + + argList.push_back([NSString stringWithUTF8String:baseDirArg.c_str()]); + argList.push_back([NSString stringWithUTF8String:javaLibArg.c_str()]); + argList.push_back([NSString stringWithUTF8String:classpathStrHead.c_str()]); + argList.push_back([NSString stringWithUTF8String:classpathStr.c_str()]); + argList.push_back(@"net.i2p.router.Router"); + auto javaBin = std::string([metaInfo.javaBinary UTF8String]); + + + sendUserNotification(APP_IDSTR, @"I2P Router is starting up!", self.contentImage); + auto nsJavaBin = metaInfo.javaBinary; + auto nsBasePath = metaInfo.i2pBase; + NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()]; + startupRouter(nsJavaBin, arrArguments, nsBasePath); + //if (self.enableVerboseLogging) NSLog(@"Defaults: %@", [pref dictionaryRepresentation]); + } catch (std::exception &err) { + auto errMsg = [NSString stringWithUTF8String:err.what()]; + NSLog(@"Exception: %@", errMsg); + sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg], self.contentImage); + } +} + - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { return YES; @@ -302,6 +458,12 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"]; self.enableVerboseLogging = [self.userPreferences boolForKey:@"enableVerboseLogging"]; + + // Get paths + NSBundle *launcherBundle = [NSBundle mainBundle]; + auto iconImage = [launcherBundle pathForResource:@"ItoopieTransparent" ofType:@"png"]; + self.contentImage = [NSImage imageNamed:iconImage]; + gRawJvmList = std::make_shared >(std::list()); // In case we are unbundled, make us a proper UI application [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; @@ -360,109 +522,36 @@ std::future startupRouter(NSString* javaBin, NSArray* arguments, return globVector(basePath+std::string("/lib/*.jar")); }; - auto sendUserNotification = [&](NSString* title, NSString* informativeText) -> void { - NSUserNotification *userNotification = [[[NSUserNotification alloc] init] autorelease]; - userNotification.title = title; - userNotification.informativeText = informativeText; - userNotification.soundName = NSUserNotificationDefaultSoundName; - - [[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:userNotification]; - }; - - - // Get paths - NSBundle *launcherBundle = [NSBundle mainBundle]; + auto metaInfo = [ExtractMetaInfo alloc]; + metaInfo.i2pBase = [NSString stringWithUTF8String:buffer]; + metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()]; + metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"]; + metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"]; std::string basearg("-Di2p.dir.base="); basearg += i2pBaseDir; - std::string zippath("-Di2p.base.zip="); - zippath += [[launcherBundle pathForResource:@"base" ofType:@"zip"] UTF8String]; - std::string jarfile("-cp "); - jarfile += [[launcherBundle pathForResource:@"launcher" ofType:@"jar"] UTF8String]; + jarfile += [metaInfo.zipFile UTF8String]; struct stat sb; if ( !(stat(buffer, &sb) == 0 && S_ISDIR(sb.st_mode)) ) { // I2P is not extracted. - if (self.enableVerboseLogging) printf("I2P Directory don't exists!\n"); + if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!"); - // Create directory - mkdir(buffer, S_IRUSR | S_IWUSR | S_IXUSR); - - auto cli = JavaRunner::defaultFlagsForExtractorJob; - setenv("I2PBASE", buffer, true); - setenv("ZIPPATH", zippath.c_str(), true); - //setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true); - - cli.push_back(basearg); - cli.push_back(zippath); - cli.push_back(jarfile); - cli.push_back("net.i2p.launchers.BaseExtractor"); - - //auto charCli = map(cli, [](std::string str){ return str.c_str(); }); - std::string execStr = getJavaBin(); - for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; }); - - printf("\n\nTrying cmd: %s\n\n", execStr.c_str()); - try { - sendUserNotification((NSString*)CFSTR("I2P Extraction"), (NSString*)CFSTR("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", buffer} - }}).wait(); - printf("Extraction exit code %d\n",extractStatus); - sendUserNotification((NSString*)CFSTR("I2P Extraction"), (NSString*)CFSTR("Extraction complete!")); - } catch (subprocess::OSError &err) { - printf("Something bad happened: %s\n", err.what()); - } + [self extractI2PBaseDir: metaInfo completion:^(BOOL success, NSError *error) { + //__typeof__(self) strongSelf = weakSelf; + //if (strongSelf == nil) return; + [self startupI2PRouter:metaInfo]; + }]; } else { - if (self.enableVerboseLogging) printf("I2P directory found!\n"); + if (self.enableVerboseLogging) NSLog(@"I2P directory found!"); + [self startupI2PRouter:metaInfo]; } - // Expect base to be extracted by now. - - auto jarList = buildClassPath(std::string(buffer)); - std::string classpathStrHead = "-classpath"; - std::string classpathStr = ""; - classpathStr += [[launcherBundle pathForResource:@"launcher" ofType:@"jar"] UTF8String]; - std::string prefix(i2pBaseDir); - prefix += "/lib/"; - for_each(jarList, [&classpathStr](std::string str){ classpathStr += std::string(":") + str; }); - //if (self.enableVerboseLogging) NSLog(@"Classpath: %@\n",[NSString stringWithUTF8String:classpathStr.c_str()]); - - - - try { - auto argList = JavaRunner::defaultStartupFlags; - - std::string baseDirArg("-Di2p.dir.base="); - baseDirArg += i2pBaseDir; - std::string javaLibArg("-Djava.library.path="); - javaLibArg += i2pBaseDir; - // TODO: pass this to JVM - auto java_opts = getenv("JAVA_OPTS"); - - argList.push_back([NSString stringWithUTF8String:baseDirArg.c_str()]); - argList.push_back([NSString stringWithUTF8String:javaLibArg.c_str()]); - argList.push_back([NSString stringWithUTF8String:classpathStrHead.c_str()]); - argList.push_back([NSString stringWithUTF8String:classpathStr.c_str()]); - argList.push_back(@"net.i2p.router.Router"); - auto javaBin = getJavaBin(); - - - sendUserNotification(@"I2P Launcher", @"I2P Router is starting up!"); - auto nsJavaBin = [NSString stringWithUTF8String:javaBin.c_str()]; - auto nsBasePath = [NSString stringWithUTF8String:i2pBaseDir.c_str()]; - NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()]; - startupRouter(nsJavaBin, arrArguments, nsBasePath); - //if (self.enableVerboseLogging) NSLog(@"Defaults: %@", [pref dictionaryRepresentation]); - } catch (std::exception &err) { - std::cerr << "Exception: " << err.what() << std::endl; - } }