Starting to get stable and usable. Basically everything is based on callbacks.

This commit is contained in:
meeh
2018-07-13 09:11:46 +00:00
parent 818e70d3a7
commit c8490a3140
7 changed files with 254 additions and 122 deletions

View File

@ -16,28 +16,48 @@
#include <glob.h> #include <glob.h>
#include <vector> #include <vector>
#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 namespace neither;
using maybeAnRouterRunner = std::experimental::optional<RouterTask*>;
extern JvmListSharedPtr gRawJvmList; extern JvmListSharedPtr gRawJvmList;
// DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY. // DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY.
maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{}; static std::mutex globalRouterStatusMutex;
static maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{};
maybeAnRouterRunner getGlobalRouterObject() maybeAnRouterRunner getGlobalRouterObject();
{ void setGlobalRouterObject(RouterTask* newRouter);
std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
return globalRouterStatus;
}
void setGlobalRouterObject(RouterTask* newRouter) @class ExtractMetaInfo;
{ @interface ExtractMetaInfo : NSObject
std::lock_guard<std::mutex> lock(globalRouterStatusMutex); @property (strong) NSString* i2pBase;
globalRouterStatus.emplace(newRouter); @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<std::string> globVector(const std::string& pattern){ [[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:userNotification];
};
inline std::vector<std::string> globVector(const std::string& pattern){
glob_t glob_result; glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result); glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
std::vector<std::string> files; std::vector<std::string> files;
@ -63,6 +83,7 @@ std::vector<std::string> globVector(const std::string& pattern){
- (void) btnPressedAction:(id)sender; - (void) btnPressedAction:(id)sender;
- (void) menuWillOpen:(NSMenu *)menu; - (void) menuWillOpen:(NSMenu *)menu;
- (void) openRouterConsoleBtnHandler: (NSMenuItem *) menuItem;
- (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem; - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem;
- (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem; - (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem;
- (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem; - (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem;
@ -85,6 +106,9 @@ std::vector<std::string> globVector(const std::string& pattern){
@property (strong) NSUserDefaults *userPreferences; @property (strong) NSUserDefaults *userPreferences;
@property BOOL enableLogging; @property BOOL enableLogging;
@property BOOL enableVerboseLogging; @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)applicationDidFinishLaunching:(NSNotification *)aNotification;
- (void)applicationWillTerminate:(NSNotification *)aNotification; - (void)applicationWillTerminate:(NSNotification *)aNotification;
- (void)setApplicationDefaultPreferences; - (void)setApplicationDefaultPreferences;

View File

@ -26,12 +26,6 @@
using namespace subprocess; using namespace subprocess;
using namespace neither; using namespace neither;
using maybeAnRouterRunner = std::experimental::optional<RouterTask*>;
extern std::mutex globalRouterStatusMutex;
extern maybeAnRouterRunner globalRouterStatus;
#define DEF_MIN_JVM_VER "1.7+" #define DEF_MIN_JVM_VER "1.7+"
class JvmVersion class JvmVersion

View File

@ -30,8 +30,12 @@
@property (strong) NSMutableData *totalLogData; @property (strong) NSMutableData *totalLogData;
@property (strong) NSPipe *processPipe; @property (strong) NSPipe *processPipe;
@property (strong) NSFileHandle *input; @property (strong) NSFileHandle *input;
@property (atomic) BOOL userRequestedRestart;
- (instancetype) initWithOptions : (RTaskOptions*) options; - (instancetype) initWithOptions : (RTaskOptions*) options;
- (int) execute; - (int) execute;
- (void) requestShutdown;
- (void) requestRestart;
- (BOOL) isRunning;
- (int) getPID; - (int) getPID;
@end @end

View File

@ -6,6 +6,7 @@
#include "optional.hpp" #include "optional.hpp"
#include "subprocess.hpp" #include "subprocess.hpp"
#include "PidWatcher.h"
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
@ -14,8 +15,10 @@
@implementation RouterTask @implementation RouterTask
- (instancetype) initWithOptions : (RTaskOptions*) options - (instancetype) initWithOptions : (RTaskOptions*) options
{ {
self.userRequestedRestart = FALSE;
self.input = [NSFileHandle fileHandleWithStandardInput]; self.input = [NSFileHandle fileHandleWithStandardInput];
self.routerTask = [NSTask new]; self.routerTask = [NSTask new];
self.processPipe = [NSPipe new]; self.processPipe = [NSPipe new];
@ -27,6 +30,9 @@
[self.routerTask setEnvironment: envDict]; [self.routerTask setEnvironment: envDict];
[self.routerTask setStandardOutput:self.processPipe]; [self.routerTask setStandardOutput:self.processPipe];
[self.routerTask setStandardError:self.processPipe]; [self.routerTask setStandardError:self.processPipe];
[self.routerTask setTerminationHandler:^(NSTask* task) {
NSLog(@"termHandler triggered!");
}];
/* /*
self.readLogHandle = [self.processPipe fileHandleForReading]; self.readLogHandle = [self.processPipe fileHandleForReading];
NSData *inData = nil; NSData *inData = nil;
@ -40,10 +46,26 @@
return self; return self;
} }
- (void) requestShutdown
{
[self.routerTask interrupt];
}
- (void) requestRestart
{
self.userRequestedRestart = TRUE;
}
- (BOOL) isRunning
{
return self.routerTask.running;
}
- (int) execute - (int) execute
{ {
//@try { //@try {
[self.routerTask launch]; [self.routerTask launch];
watchPid([self.routerTask processIdentifier]);
[self.input waitForDataInBackgroundAndNotify]; [self.input waitForDataInBackgroundAndNotify];
[[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify]; [[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
@ -84,8 +106,6 @@
using namespace subprocess; using namespace subprocess;
std::mutex globalRouterStatusMutex;
const std::vector<NSString*> JavaRunner::defaultStartupFlags { const std::vector<NSString*> JavaRunner::defaultStartupFlags {
@"-Xmx512M", @"-Xmx512M",
@"-Xms128m", @"-Xms128m",

View File

@ -1,5 +1,6 @@
cxx = clang++ 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 ldflags = -framework CoreFoundation -framework Foundation -framework Cocoa -g -rdynamic

View File

@ -14,7 +14,7 @@
#include <CoreFoundation/CFArray.h> #include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFString.h> #include <CoreFoundation/CFString.h>
std::string strprintf(const char *fromat, ...) inline std::string strprintf(const char *fromat, ...)
{ {
std::string s; std::string s;
s.resize(128); // best guess s.resize(128); // best guess
@ -37,7 +37,7 @@ std::string strprintf(const char *fromat, ...)
return s; // move semantics FTW return s; // move semantics FTW
} }
std::string extractString(CFStringRef value) inline std::string extractString(CFStringRef value)
{ {
const char * data = CFStringGetCStringPtr(value, kCFStringEncodingUTF8); const char * data = CFStringGetCStringPtr(value, kCFStringEncodingUTF8);
if (data != NULL) if (data != NULL)
@ -56,7 +56,7 @@ std::string extractString(CFStringRef value)
using std::experimental::optional; using std::experimental::optional;
// Use CFStringRef instead of NSString*, otherwise disable ARC // Use CFStringRef instead of NSString*, otherwise disable ARC
optional<CFStringRef> optionalString(bool val) { inline optional<CFStringRef> optionalString(bool val) {
optional<CFStringRef> myOptString; optional<CFStringRef> myOptString;
if(val) { if(val) {
// Cast to corresponding CoreFoundation object // Cast to corresponding CoreFoundation object

View File

@ -31,11 +31,6 @@
#include "fn.h" #include "fn.h"
#include "optional.hpp" #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__]); #define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
JvmListSharedPtr gRawJvmList = nullptr; JvmListSharedPtr gRawJvmList = nullptr;
@ -48,6 +43,18 @@ JvmListSharedPtr gRawJvmList = nullptr;
@end @end
maybeAnRouterRunner getGlobalRouterObject()
{
std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
return globalRouterStatus;
}
void setGlobalRouterObject(RouterTask* newRouter)
{
std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
globalRouterStatus.emplace(newRouter);
}
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) { std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
/* /*
NSLog(@"Arguments: %@", [NSString stringWithUTF8String:arguments.c_str()]); NSLog(@"Arguments: %@", [NSString stringWithUTF8String:arguments.c_str()]);
@ -72,7 +79,7 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
return 0; return 0;
}); });
*/ */
CFShow(arguments); //CFShow(arguments);
@try { @try {
RTaskOptions* options = [RTaskOptions alloc]; RTaskOptions* options = [RTaskOptions alloc];
@ -80,22 +87,31 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
options.arguments = arguments; options.arguments = arguments;
options.i2pBaseDir = i2pBaseDir; options.i2pBaseDir = i2pBaseDir;
auto instance = [[[RouterTask alloc] initWithOptions: options] autorelease]; auto instance = [[[RouterTask alloc] initWithOptions: options] autorelease];
//auto pid = [instance execute]; setGlobalRouterObject(instance);
//NSThread *thr = [[NSThread alloc] initWithTarget:instance selector:@selector(execute) object:nil]; //NSThread *thr = [[NSThread alloc] initWithTarget:instance selector:@selector(execute) object:nil];
[instance execute]; [instance execute];
return std::async(std::launch::async, [&instance]{ sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
return 1;//[instance getPID]; auto pid = [instance getPID];
return std::async(std::launch::async, [&pid]{
return pid;
}); });
} }
@catch (NSException *e) @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 std::async(std::launch::async, [&]{
return 0; return 0;
}); });
} }
} }
void openUrl(NSString* url)
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: url]];
}
@implementation MenuBarCtrl @implementation MenuBarCtrl
@ -123,6 +139,12 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
NSEvent *event = [NSApp currentEvent]; NSEvent *event = [NSApp currentEvent];
} }
- (void) openRouterConsoleBtnHandler: (NSMenuItem *) menuItem
{
NSLog(@"Clicked openRouterConsoleBtnHandler");
openUrl(@"http://127.0.0.1:7657");
}
- (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem
{ {
NSLog(@"Clicked startJavaRouterBtnHandler"); NSLog(@"Clicked startJavaRouterBtnHandler");
@ -131,6 +153,12 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
- (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem - (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem
{ {
NSLog(@"Clicked restartJavaRouterBtnHandler"); 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 - (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem
@ -138,7 +166,8 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
NSLog(@"Clicked stopJavaRouterBtnHandler"); NSLog(@"Clicked stopJavaRouterBtnHandler");
if (getGlobalRouterObject().has_value()) if (getGlobalRouterObject().has_value())
{ {
//getGlobalRouterObject().value()->requestRouterShutdown(); sendUserNotification(APP_IDSTR, @"Requesting the I2P router to shutdown.");
[getGlobalRouterObject().value() requestShutdown];
NSLog(@"Requested shutdown"); NSLog(@"Requested shutdown");
} }
} }
@ -185,6 +214,14 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
{ {
NSMenu *menu = [[NSMenu alloc] init]; NSMenu *menu = [[NSMenu alloc] init];
[menu setAutoenablesItems:NO]; [menu setAutoenablesItems:NO];
NSMenuItem *openConsoleI2Pbtn =
[[NSMenuItem alloc] initWithTitle:@"Open Console"
action:@selector(openRouterConsoleBtnHandler:)
keyEquivalent:@""];
[openConsoleI2Pbtn setTarget:self];
[openConsoleI2Pbtn setEnabled:YES];
NSMenuItem *startI2Pbtn = NSMenuItem *startI2Pbtn =
[[NSMenuItem alloc] initWithTitle:@"Start I2P" [[NSMenuItem alloc] initWithTitle:@"Start I2P"
action:@selector(startJavaRouterBtnHandler:) action:@selector(startJavaRouterBtnHandler:)
@ -219,6 +256,7 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
[quitWrapperBtn setEnabled:YES]; [quitWrapperBtn setEnabled:YES];
[menu addItem:openConsoleI2Pbtn];
[menu addItem:startI2Pbtn]; [menu addItem:startI2Pbtn];
[menu addItem:stopI2Pbtn]; [menu addItem:stopI2Pbtn];
[menu addItem:restartI2Pbtn]; [menu addItem:restartI2Pbtn];
@ -228,9 +266,127 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
@end @end
@implementation ExtractMetaInfo
@end
@implementation AppDelegate @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<std::string> {
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 - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification { shouldPresentNotification:(NSUserNotification *)notification {
return YES; return YES;
@ -302,6 +458,12 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"]; self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"];
self.enableVerboseLogging = [self.userPreferences boolForKey:@"enableVerboseLogging"]; 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<JvmVersionPtr> >(std::list<JvmVersionPtr>()); gRawJvmList = std::make_shared<std::list<JvmVersionPtr> >(std::list<JvmVersionPtr>());
// In case we are unbundled, make us a proper UI application // In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
@ -360,109 +522,36 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
return globVector(basePath+std::string("/lib/*.jar")); return globVector(basePath+std::string("/lib/*.jar"));
}; };
auto sendUserNotification = [&](NSString* title, NSString* informativeText) -> void {
NSUserNotification *userNotification = [[[NSUserNotification alloc] init] autorelease];
userNotification.title = title; auto metaInfo = [ExtractMetaInfo alloc];
userNotification.informativeText = informativeText; metaInfo.i2pBase = [NSString stringWithUTF8String:buffer];
userNotification.soundName = NSUserNotificationDefaultSoundName; metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()];
metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
[[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:userNotification]; metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
};
// Get paths
NSBundle *launcherBundle = [NSBundle mainBundle];
std::string basearg("-Di2p.dir.base="); std::string basearg("-Di2p.dir.base=");
basearg += i2pBaseDir; basearg += i2pBaseDir;
std::string zippath("-Di2p.base.zip=");
zippath += [[launcherBundle pathForResource:@"base" ofType:@"zip"] UTF8String];
std::string jarfile("-cp "); std::string jarfile("-cp ");
jarfile += [[launcherBundle pathForResource:@"launcher" ofType:@"jar"] UTF8String]; jarfile += [metaInfo.zipFile UTF8String];
struct stat sb; struct stat sb;
if ( !(stat(buffer, &sb) == 0 && S_ISDIR(sb.st_mode)) ) if ( !(stat(buffer, &sb) == 0 && S_ISDIR(sb.st_mode)) )
{ {
// I2P is not extracted. // 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 [self extractI2PBaseDir: metaInfo completion:^(BOOL success, NSError *error) {
mkdir(buffer, S_IRUSR | S_IWUSR | S_IXUSR); //__typeof__(self) strongSelf = weakSelf;
//if (strongSelf == nil) return;
auto cli = JavaRunner::defaultFlagsForExtractorJob; [self startupI2PRouter:metaInfo];
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());
}
} else { } 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;
}
} }