forked from I2P_Developers/i2p.i2p
Fixed a load of issues related to my "sync" approach, and Mac OSX's "async" API.
This commit is contained in:
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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 :)")
|
||||
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
75
launchers/macosx/obj-cpp/RouterTask.h
Normal file
75
launchers/macosx/obj-cpp/RouterTask.h
Normal 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;
|
||||
};
|
||||
|
||||
|
141
launchers/macosx/obj-cpp/RouterTask.mm
Normal file
141
launchers/macosx/obj-cpp/RouterTask.mm
Normal 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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <experimental/optional>
|
||||
#include "optional.hpp"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreFoundation/CFArray.h>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user