Fixed a load of issues related to my "sync" approach, and Mac OSX's "async" API.

This commit is contained in:
meeh
2018-07-13 06:30:16 +00:00
parent 21b3864dfd
commit 6d0f80fa1e
14 changed files with 498 additions and 163 deletions

View File

@ -62,7 +62,7 @@ object RouterLauncherApp extends App {
val configPath = Option(System.getProperty("i2p.dir.config")).getOrElse(System.getenv("I2PCONFIG"))
println(s"basePath => ${basePath}\nconfigPath => ${configPath}")
/*
object ErrorUtils {
def errorMessageInJson(message: String, solution: String) : JObject = JObject(
List(
@ -91,7 +91,7 @@ object RouterLauncherApp extends App {
if (!new File(basePath).exists()) ErrorUtils.printErrorAndExit("I2P Base path don't exist", "Reinstall the Browser Bundle")
if (!new File(configPath).exists()) ErrorUtils.printErrorAndExit("I2P Config path don't exist", "Delete your config directory for the Browser Bundle")
*/
val deployer = new DeployProfile(configPath,basePath)
deployer.verifyExistenceOfConfig()

View File

@ -40,8 +40,8 @@ lazy val browserbundle = (project in file("browserbundle"))
lazy val macosx = (project in file("macosx"))
.settings(
commonSettings,
name := "RouterPack.jar",
mainClass in assembly := Some("net.i2p.launchers.osx.LauncherAppMain")
name := "routerLauncher",
mainClass in assembly := Some("net.i2p.launchers.SimpleOSXLauncher")
).dependsOn(common)

View File

@ -21,21 +21,23 @@ resourceDirectory in Compile := baseDirectory.value / ".." / ".." / "installer"
// Unmanaged base will be included in a fat jar
unmanagedBase in Compile := baseDirectory.value / ".." / ".." / "pkg-temp" / "lib"
// Unmanaged classpath will be available at compile time
unmanagedClasspath in Compile ++= Seq(
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "*.jar"
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "*.jar"
)
assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false, includeDependency = false)
assemblyJarName in assembly := s"launcher.jar"
assemblyExcludedJars in assembly := {
val cp = (fullClasspath in assembly).value
cp filter { c => jarsForCopy.toList.contains(c.data.getName) }
val cp = (fullClasspath in assembly).value
cp filter { c => jarsForCopy.toList.contains(c.data.getName) }
}
/*
assemblyJarName in assembly := s"package.jar"
// TODO: MEEH: Add assemblyExcludedJars and load the router from own jar files, to handle upgrades better.
// In fact, most likely the bundle never would need an update except for the router jars/wars.
@ -104,3 +106,4 @@ buildAppBundleTask := {
println(s"Zip placed into bundle :)")
}
*/

View File

@ -9,9 +9,45 @@
#include "StatusItemButton.h"
#include "JavaHelper.h"
#include "RouterTask.h"
#include "neither/maybe.hpp"
#include "optional.hpp"
#include "subprocess.hpp"
#include <glob.h>
#include <vector>
using namespace neither;
extern JvmListSharedPtr gRawJvmList;
// DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY.
maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{};
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::vector<std::string> globVector(const std::string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
std::vector<std::string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(std::string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
@interface MenuBarCtrl : NSObject <StatusItemButtonDelegate, NSMenuDelegate>
@property BOOL enableLogging;
@property BOOL enableVerboseLogging;
@ -55,6 +91,8 @@ extern JvmListSharedPtr gRawJvmList;
- (void)userChooseJavaHome;
- (AppDelegate *)initWithArgc:(int)argc argv:(const char **)argv;
- (NSString *)userSelectJavaHome:(JvmListPtr)rawJvmList;
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification;
@end

View File

@ -26,6 +26,8 @@
<string>I2P</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>NSUserNotificationAlertStyle</key>
<string>alert</string>
<key>NSAppleScriptEnabled</key>
<true/>
<key>CGDisableCoalescedUpdates</key>

View File

@ -7,7 +7,6 @@
#include <cstring>
#include <sstream>
#include <list>
#include <experimental/optional>
#include <stdlib.h>
#include <Foundation/Foundation.h>
@ -18,10 +17,19 @@
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFString.h>
#include "optional.hpp"
#include "strutil.hpp"
#include "subprocess.hpp"
#include "neither/maybe.hpp"
#include "RouterTask.h"
using namespace subprocess;
using namespace neither;
using maybeAnRouterRunner = std::experimental::optional<RouterTask*>;
extern std::mutex globalRouterStatusMutex;
extern maybeAnRouterRunner globalRouterStatus;
#define DEF_MIN_JVM_VER "1.7+"
@ -133,7 +141,7 @@ static void processJvmPlistEntries (const void* item, void* context) {
auto d = extractString((CFStringRef)value);
currentJvm->JVMPlatformVersion = trim_copy(d);
}
}
};
@ -150,7 +158,7 @@ static void listAllJavaInstallsAvailable()
{
auto javaHomeRes = check_output({"/usr/libexec/java_home","-v",DEF_MIN_JVM_VER,"-X"});
CFDataRef javaHomes = CFDataCreate(NULL, (const UInt8 *)javaHomeRes.buf.data(), strlen(javaHomeRes.buf.data()));
//CFErrorRef err;
CFPropertyListRef propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, javaHomes, kCFPropertyListImmutable, NULL, NULL);
/*if (err)

View File

@ -1,34 +0,0 @@
#include "JavaRunner.h"
#include <dispatch/dispatch.h>
#include <subprocess.hpp>
#include <future>
using namespace subprocess;
using namespace std::experimental;
JavaRunner::JavaRunner(std::string javaBin, const fp_proc_t& execFn, const fp_t& cb)
: javaBinaryPath(javaBin), executingFn(execFn), exitCallbackFn(cb)
{
javaProcess = std::shared_ptr<Popen>(new Popen({javaBin.c_str(), "-version"}, defer_spawn{true}));
}
optional<std::future<int> > JavaRunner::execute()
{
try {
auto executingFn = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
this->executingFn(this);
});
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), executingFn);
dispatch_block_wait(executingFn, DISPATCH_TIME_FOREVER);
// Here, the process is done executing.
printf("Finished executingFn - Runs callbackFn\n");
this->exitCallbackFn();
return std::async(std::launch::async, []{ return 0; });
} catch (std::exception* ex) {
printf("ERROR: %s\n", ex->what());
return nullopt;
}
}

View File

@ -1,72 +0,0 @@
#pragma once
#include <dispatch/dispatch.h>
#include <functional>
#include <memory>
#include <string>
#include <list>
#include <subprocess.hpp>
#include <optional.hpp>
using namespace subprocess;
using namespace std::experimental;
class JavaRunner;
struct CRouterState
{
enum State {
C_STOPPED = 0,
C_STARTED,
C_RUNNING
};
};
typedef std::function<void(void)> fp_t;
typedef std::function<void(JavaRunner *ptr)> fp_proc_t;
/**
*
* class JavaRunner
*
**/
class JavaRunner
{
public:
// copy fn
JavaRunner(std::string javaBin, const fp_proc_t& executingFn, const fp_t& cb);
~JavaRunner() = default;
const std::list<std::string> defaultStartupFlags {
"-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",
"-Di2p.dir.base=$BASEPATH",
"-Djava.library.path=$BASEPATH",
"$JAVA_OPTS",
"net.i2p.launchers.SimpleOSXLauncher"
};
const std::list<std::string> defaultFlagsForExtractorJob {
"-Xmx512M",
"-Xms128m",
"-Djava.awt.headless=true",
"-Di2p.dir.base=$BASEPATH",
"-Di2p.dir.zip=$ZIPPATH",
"net.i2p.launchers.BaseExtractor",
"extract"
};
optional<std::future<int> > execute();
std::shared_ptr<Popen> javaProcess;
std::string javaBinaryPath;
private:
const fp_proc_t& executingFn;
const fp_t& exitCallbackFn;
};

View File

@ -0,0 +1,75 @@
#pragma once
#include <dispatch/dispatch.h>
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#include "optional.hpp"
#include "subprocess.hpp"
@class RTaskOptions;
@interface RTaskOptions : NSObject
@property (strong) NSString* binPath;
@property (strong) NSArray<NSString *>* arguments;
@property (strong) NSString* i2pBaseDir;
@end
@class RouterTask;
@interface RouterTask : NSObject
@property (strong) NSTask* routerTask;
@property (strong) NSUserDefaults *userPreferences;
@property (strong) NSFileHandle *readLogHandle;
@property (strong) NSMutableData *totalLogData;
@property (strong) NSPipe *processPipe;
@property (strong) NSFileHandle *input;
- (instancetype) initWithOptions : (RTaskOptions*) options;
- (int) execute;
- (int) getPID;
@end
using namespace subprocess;
class JavaRunner;
typedef std::function<void(void)> fp_t;
typedef std::function<void(JavaRunner *ptr)> fp_proc_t;
/**
*
* class JavaRunner
*
**/
class JavaRunner
{
public:
// copy fn
JavaRunner(std::string& javaBin, std::string& arguments, std::string& i2pBaseDir, const fp_proc_t& executingFn, const fp_t& cb);
~JavaRunner() = default;
static const std::vector<NSString*> defaultStartupFlags;
static const std::vector<std::string> defaultFlagsForExtractorJob;
void requestRouterShutdown();
std::experimental::optional<std::future<int> > execute();
std::shared_ptr<Popen> javaProcess;
std::string javaBinaryPath;
std::string javaRouterArgs;
std::string execLine;
std::string _i2pBaseDir;
private:
const fp_proc_t& executingFn;
const fp_t& exitCallbackFn;
};

View File

@ -0,0 +1,141 @@
#include "RouterTask.h"
#include <dispatch/dispatch.h>
#include <future>
#include <stdlib.h>
#include "optional.hpp"
#include "subprocess.hpp"
#import <AppKit/AppKit.h>
@implementation RTaskOptions
@end
@implementation RouterTask
- (instancetype) initWithOptions : (RTaskOptions*) options
{
self.input = [NSFileHandle fileHandleWithStandardInput];
self.routerTask = [NSTask new];
self.processPipe = [NSPipe new];
[self.routerTask setLaunchPath:options.binPath];
[self.routerTask setArguments:options.arguments];
NSDictionary *envDict = @{
@"I2PBASE": options.i2pBaseDir
};
[self.routerTask setEnvironment: envDict];
[self.routerTask setStandardOutput:self.processPipe];
[self.routerTask setStandardError:self.processPipe];
/*
self.readLogHandle = [self.processPipe fileHandleForReading];
NSData *inData = nil;
self.totalLogData = [[[NSMutableData alloc] init] autorelease];
while ((inData = [self.readLogHandle availableData]) &&
[inData length]) {
[self.totalLogData appendData:inData];
}
*/
return self;
}
- (int) execute
{
//@try {
[self.routerTask launch];
[self.input waitForDataInBackgroundAndNotify];
[[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
object:[self.processPipe fileHandleForReading] queue:nil
usingBlock:^(NSNotification *note)
{
// Read from shell output
NSData *outData = [[self.processPipe fileHandleForReading] availableData];
NSString *outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
if ([outStr length] > 1) {
NSLog(@"output: %@", outStr);
}
// Continue waiting for shell output.
[[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
}];
//[self.routerTask waitUntilExit];
//NSThread *thr = [[NSThread alloc] initWithTarget:self.routerTask selector:@selector(launch) object:nil];
//[self.routerTask waitUntilExit];
return 1;
/*}
@catch (NSException *e)
{
NSLog(@"Expection occurred %@", [e reason]);
return 0;
}*/
}
- (int) getPID
{
return [self.routerTask processIdentifier];
}
@end
using namespace subprocess;
std::mutex globalRouterStatusMutex;
const std::vector<NSString*> JavaRunner::defaultStartupFlags {
@"-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"
};
const std::vector<std::string> JavaRunner::defaultFlagsForExtractorJob {
"-Xmx512M",
"-Xms128m",
"-Djava.awt.headless=true"
};
JavaRunner::JavaRunner(std::string& javaBin, std::string& arguments, std::string& i2pBaseDir, const fp_proc_t& execFn, const fp_t& cb)
: javaBinaryPath(javaBin), javaRouterArgs(arguments), _i2pBaseDir(i2pBaseDir), executingFn(execFn), exitCallbackFn(cb)
{
execLine = javaBinaryPath;
execLine += " " + std::string(javaRouterArgs.c_str());
printf("CLI: %s\n",execLine.c_str());
javaProcess = std::shared_ptr<Popen>(new Popen(execLine, environment{{
{"I2PBASE", _i2pBaseDir},
{"JAVA_OPTS", getenv("JAVA_OPTS")}
}}, defer_spawn{true}));
}
void JavaRunner::requestRouterShutdown()
{
// SIGHUP
javaProcess->kill(1);
}
std::experimental::optional<std::future<int> > JavaRunner::execute()
{
try {
auto executingFn = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
this->executingFn(this);
});
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), executingFn);
dispatch_block_wait(executingFn, DISPATCH_TIME_FOREVER);
// Here, the process is done executing.
printf("Finished executingFn - Runs callbackFn\n");
this->exitCallbackFn();
return std::async(std::launch::async, []{ return 0; });
} catch (std::exception* ex) {
printf("ERROR: %s\n", ex->what());
return std::experimental::nullopt;
}
}

View File

@ -1,5 +1,5 @@
cxx = clang++
cflags = -std=c++14 -g -Wall -I./include -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-variable -mmacosx-version-min=10.10
ldflags = -framework CoreFoundation -framework Foundation -framework Cocoa -g -rdynamic
@ -26,7 +26,8 @@ rule cleanup
rule bundledir
command = mkdir -p I2PLauncher.app/Contents/{MacOS,Resources,Frameworks} $
&& cp Info.plist I2PLauncher.app/Contents/Info.plist $
&& cp base.zip I2PLauncher.app/Contents/Resources/base.zip
&& cp base.zip I2PLauncher.app/Contents/Resources/base.zip $
&& cp ../target/scala-2.11/routerLauncher-assembly-0.1.0-SNAPSHOT.jar I2PLauncher.app/Contents/Resources/launcher.jar
rule copytobundledir
command = cp clauncher I2PLauncher.app/Contents/MacOS/I2PLauncher
@ -39,14 +40,14 @@ rule builddir
build main.o: cxx main.mm
build StatusItemButton.o: cxx StatusItemButton.mm
build JavaRunner.o: cxx JavaRunner.cpp
build RouterTask.o: cxx RouterTask.mm
build clean: cleanup
build bundle: bundledir
build copytobundle: copytobundledir | bundle clauncher
build clauncher: link main.o StatusItemButton.o JavaRunner.o
build clauncher: link main.o StatusItemButton.o RouterTask.o
build appbundle: copyimgtobundle | clauncher bundle copytobundle

View File

@ -8,7 +8,7 @@
#include <iostream>
#include <cctype>
#include <locale>
#include <experimental/optional>
#include "optional.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFArray.h>

View File

@ -4,7 +4,10 @@
#include <algorithm>
#include <string>
#include <list>
#include <experimental/optional>
#include <sys/stat.h>
#include <stdlib.h>
#include <future>
#include <vector>
#import <Foundation/Foundation.h>
@ -23,8 +26,10 @@
#include "AppDelegate.h"
#include "StatusItemButton.h"
#include "JavaRunner.h"
#include "RouterTask.h"
#include "JavaHelper.h"
#include "fn.h"
#include "optional.hpp"
#define DEF_I2P_VERSION "0.9.35"
#define APPDOMAIN "net.i2p.launcher"
@ -43,6 +48,55 @@ JvmListSharedPtr gRawJvmList = nullptr;
@end
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
/*
NSLog(@"Arguments: %@", [NSString stringWithUTF8String:arguments.c_str()]);
auto launchLambda = [](JavaRunner *javaRun) {
javaRun->javaProcess->start_process();
auto pid = javaRun->javaProcess->pid();
std::cout << "I2P Router process id = " << pid << std::endl;
// Blocking
javaRun->javaProcess->wait();
};
auto callbackAfterExit = [](){
printf("Callback after exit\n");
};
NSLog(@"Still fine!");
setGlobalRouterObject(new JavaRunner{ javaBin, arguments, i2pBaseDir, std::move(launchLambda), std::move(callbackAfterExit) });
NSLog(@"Still fine!");
return std::async(std::launch::async, [&]{
getGlobalRouterObject().value()->execute();
return 0;
});
*/
CFShow(arguments);
@try {
RTaskOptions* options = [RTaskOptions alloc];
options.binPath = javaBin;
options.arguments = arguments;
options.i2pBaseDir = i2pBaseDir;
auto instance = [[[RouterTask alloc] initWithOptions: options] autorelease];
//auto pid = [instance execute];
//NSThread *thr = [[NSThread alloc] initWithTarget:instance selector:@selector(execute) object:nil];
[instance execute];
return std::async(std::launch::async, [&instance]{
return 1;//[instance getPID];
});
}
@catch (NSException *e)
{
NSLog(@"Expection occurred %@", [e reason]);
return std::async(std::launch::async, [&]{
return 0;
});
}
}
@implementation MenuBarCtrl
- (void) statusItemButtonLeftClick: (StatusItemButton *) button
@ -82,6 +136,11 @@ JvmListSharedPtr gRawJvmList = nullptr;
- (void) stopJavaRouterBtnHandler: (NSMenuItem *) menuItem
{
NSLog(@"Clicked stopJavaRouterBtnHandler");
if (getGlobalRouterObject().has_value())
{
//getGlobalRouterObject().value()->requestRouterShutdown();
NSLog(@"Requested shutdown");
}
}
- (void) quitWrapperBtnHandler: (NSMenuItem *) menuItem
@ -172,6 +231,11 @@ JvmListSharedPtr gRawJvmList = nullptr;
@implementation AppDelegate
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification {
return YES;
}
- (NSString *)userSelectJavaHome:(JvmListPtr)rawJvmList
{
NSString *appleScriptString = @"set jvmlist to {\"Newest\"";
@ -224,13 +288,14 @@ JvmListSharedPtr gRawJvmList = nullptr;
CFPreferencesSetMultiple((CFDictionaryRef)dict, NULL, CFAPPDOMAIN, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
//CFPreferencesSetAppValue(@"javaHome", (CFPropertyListRef)cfDefaultHome, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
if (self.enableVerboseLogging) NSLog(@"Default preferences stored!");
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Init application here
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
// Start with user preferences
self.userPreferences = [NSUserDefaults standardUserDefaults];
[self setApplicationDefaultPreferences];
@ -246,7 +311,6 @@ JvmListSharedPtr gRawJvmList = nullptr;
auto javaHomePref = [self.userPreferences stringForKey:@"javaHome"];
if (self.enableVerboseLogging) NSLog(@"Java home from preferences: %@", javaHomePref);
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
// This is the only GUI the user experience on a regular basis.
self.menuBarCtrl = [[MenuBarCtrl alloc] init];
@ -255,6 +319,16 @@ JvmListSharedPtr gRawJvmList = nullptr;
if (self.enableVerboseLogging) NSLog(@"Appdomain is: %@", appDomain);
NSLog(@"We should have started the statusbar object by now...");
// Figure out base directory
const char* pathFromHome = "/Users/%s/Library/I2P";
auto username = getenv("USER");
char buffer[strlen(pathFromHome)+strlen(username)];
sprintf(buffer, pathFromHome, username);
std::string i2pBaseDir(buffer);
if (self.enableVerboseLogging) printf("Home directory is: %s\n", buffer);
//[statusBarButton setAction:@selector(itemClicked:)];
//dispatch_async(dispatch_get_main_queue(), ^{
//});
@ -273,33 +347,121 @@ JvmListSharedPtr gRawJvmList = nullptr;
return std::string([val UTF8String]);;
};
auto launchLambda = [&pref](JavaRunner *javaRun) {
javaRun->javaProcess->start_process();
auto pid = javaRun->javaProcess->pid();
std::cout << "I2P Router process id = " << pid << std::endl;
// Blocking
javaRun->javaProcess->wait();
};
auto callbackAfterExit = [=](){
printf("Callback after exit\n");
};
try {
// Get Java home
auto getJavaBin = [&getJavaHomeLambda]() -> std::string {
// Get Java home
auto javaHome = getJavaHomeLambda();
trim(javaHome); // Trim to remove endline
auto javaBin = std::string(javaHome);
javaBin += "/bin/java"; // Append java binary to path.
//printf("hello world: %s\n", javaBin.c_str());
if (self.enableVerboseLogging) NSLog(@"Defaults: %@", [pref dictionaryRepresentation]);
return javaBin;
};
auto r = new JavaRunner{ javaBin, launchLambda, callbackAfterExit };
r->execute();
auto buildClassPath = [](std::string basePath) -> std::vector<std::string> {
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];
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];
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");
// 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());
}
} else {
if (self.enableVerboseLogging) printf("I2P directory found!\n");
}
// 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;
std::cerr << "Exception: " << err.what() << std::endl;
}
}

View File

@ -21,45 +21,56 @@ import java.util.zip.ZipFile;
*/
public class BaseExtractor extends EnvCheck {
private void runExtract(String zipFilename, String destinationPath) {
public boolean printDebug = false;
public void runExtract(String zipFilename) {
String destinationPath = this.baseDirPath;
try(ZipFile file = new ZipFile(zipFilename)) {
FileSystem fileSystem = FileSystems.getDefault();
Enumeration<? extends ZipEntry> entries = file.entries();
Files.createDirectory(fileSystem.getPath(destinationPath));
try {
Files.createDirectory(fileSystem.getPath(destinationPath));
} catch (IOException e) {
// It's OK to fail here.
}
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (printDebug) System.out.println("Found entry: "+entry.toString());
if (entry.isDirectory()) {
System.out.println("Creating Directory:" + destinationPath + entry.getName());
Files.createDirectories(fileSystem.getPath(destinationPath + entry.getName()));
if (printDebug) System.out.println("Creating Directory:" + destinationPath + "/" + entry.getName());
Files.createDirectories(fileSystem.getPath(destinationPath + "/" + entry.getName()));
} else {
InputStream is = file.getInputStream(entry);
BufferedInputStream bis = new BufferedInputStream(is);
String uncompressedFileName = destinationPath + entry.getName();
String uncompressedFileName = destinationPath + "/" + entry.getName();
Path uncompressedFilePath = fileSystem.getPath(uncompressedFileName);
Files.createFile(uncompressedFilePath);
FileOutputStream fileOutput = new FileOutputStream(uncompressedFileName);
while (bis.available() > 0) fileOutput.write(bis.read());
fileOutput.close();
System.out.println("Written :" + entry.getName());
if (printDebug) System.out.println("Written :" + entry.getName());
}
}
} catch (IOException e) {
//
System.err.println("Exception in extractor!");
System.err.println(e.toString());
}
}
public BaseExtractor(String[] args) {
super(args);
if (args.length == 2) {
if ("extract".equals(args[0])) {
// Start extract
}this.runExtract(System.getProperty("i2p.base.zip"),this.baseDirPath);
}
}
public static void main(String[] args) {
new BaseExtractor(args);
System.out.println("Starting extraction");
BaseExtractor be = new BaseExtractor(args);
String debug = System.getProperty("print.debug");
if (debug != null) {
be.printDebug = true;
}
be.runExtract(System.getProperty("i2p.base.zip"));
}
}