Moved some logic to C++, which will extract i2p if it's not already,

and then secondly fire up the router in a second java process when 
extraction is completed. Gonna use "optional" type in C++ to make
global variables a bit less painful to use.
This commit is contained in:
meeh
2018-07-08 13:16:07 +00:00
parent 27a0d4e51e
commit 21b3864dfd
8 changed files with 165 additions and 49 deletions

View File

@ -6,3 +6,4 @@ However, this is a thin wrapper launching both Mac OS X trayicon and the I2P rou
More code will be merged in, it's just a f* mess which Meeh needs to clean up and move into repo. More code will be merged in, it's just a f* mess which Meeh needs to clean up and move into repo.
`./fullBuild.sh` triggers Ant jobs and prepare the base.zip, as well as starting the ninja build.

View File

@ -8,41 +8,12 @@ lazy val buildAppBundleTask = taskKey[Unit](s"Build an Mac OS X bundle for I2P $
lazy val buildDeployZipTask = taskKey[String](s"Build an zipfile with base directory for I2P ${i2pVersion}.") lazy val buildDeployZipTask = taskKey[String](s"Build an zipfile with base directory for I2P ${i2pVersion}.")
lazy val bundleBuildPath = new File("./output") lazy val bundleBuildPath = new File("./output")
lazy val staticFiles = List(
"blocklist.txt",
"clients.config",
"continents.txt",
"countries.txt",
"hosts.txt",
"geoip.txt",
"router.config",
"webapps.config"
)
lazy val resDir = new File("./../installer/resources") lazy val resDir = new File("./../installer/resources")
lazy val i2pBuildDir = new File("./../pkg-temp") lazy val i2pBuildDir = new File("./../pkg-temp")
lazy val warsForCopy = new File(i2pBuildDir, "webapps").list.filter { f => f.endsWith(".war") } lazy val warsForCopy = new File(i2pBuildDir, "webapps").list.filter { f => f.endsWith(".war") }
lazy val jarsForCopy = new File(i2pBuildDir, "lib").list.filter { f => f.endsWith(".jar") } lazy val jarsForCopy = new File(i2pBuildDir, "lib").list.filter { f => f.endsWith(".jar") }
// TODO: Meeh: To be removed - logic is moved to obj-cpp
def defaultOSXLauncherShellScript(javaOpts: Seq[String] = Seq.empty): Seq[String] = {
val javaOptsString = javaOpts.map(_ + " ").mkString
Seq(
"#!/usr/bin/env sh",
s"""
|echo "I2P - Mac OS X Launcher starting up"
|export I2P=$$HOME/Library/I2P
|for jar in `ls $${I2P}/lib/*.jar`; do
| if [ ! -z $$CP ]; then
| CP=$${CP}:$${jar};
| else
| CP=$${jar}
| fi
|done
|export CLASSPATH=$$CP
|exec java -jar $javaOptsString$$JAVA_OPTS "$$0" "$$@"""".stripMargin,
"")
}
// Pointing the resources directory to the "installer" directory // Pointing the resources directory to the "installer" directory
resourceDirectory in Compile := baseDirectory.value / ".." / ".." / "installer" / "resources" resourceDirectory in Compile := baseDirectory.value / ".." / ".." / "installer" / "resources"
@ -55,22 +26,10 @@ unmanagedClasspath in Compile ++= Seq(
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "*.jar" baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "*.jar"
) )
assemblyOption in assembly := (assemblyOption in assembly).value.copy( assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false, includeDependency = false)
prependShellScript = Some(defaultOSXLauncherShellScript(
Seq(
"-Xmx512M",
"-Xms128m",
"-Dwrapper.logfile=/tmp/router.log",
"-Dwrapper.logfile.loglevel=DEBUG",
"-Dwrapper.java.pidfile=/tmp/routerjvm.pid",
"-Dwrapper.console.loglevel=DEBUG",
"-Di2p.dir.base=$I2P",
"-Djava.library.path=$I2P"
)))
)
assemblyJarName in assembly := s"OSXLauncher" assemblyJarName in assembly := s"launcher.jar"
assemblyExcludedJars in assembly := { assemblyExcludedJars in assembly := {
val cp = (fullClasspath in assembly).value val cp = (fullClasspath in assembly).value

View File

@ -2,8 +2,10 @@
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#include <subprocess.hpp> #include <subprocess.hpp>
#include <future>
using namespace subprocess; using namespace subprocess;
using namespace std::experimental;
JavaRunner::JavaRunner(std::string javaBin, const fp_proc_t& execFn, const fp_t& cb) JavaRunner::JavaRunner(std::string javaBin, const fp_proc_t& execFn, const fp_t& cb)
: javaBinaryPath(javaBin), executingFn(execFn), exitCallbackFn(cb) : javaBinaryPath(javaBin), executingFn(execFn), exitCallbackFn(cb)
@ -11,7 +13,7 @@ JavaRunner::JavaRunner(std::string javaBin, const fp_proc_t& execFn, const fp_t&
javaProcess = std::shared_ptr<Popen>(new Popen({javaBin.c_str(), "-version"}, defer_spawn{true})); javaProcess = std::shared_ptr<Popen>(new Popen({javaBin.c_str(), "-version"}, defer_spawn{true}));
} }
void JavaRunner::execute() optional<std::future<int> > JavaRunner::execute()
{ {
try { try {
auto executingFn = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{ auto executingFn = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
@ -24,7 +26,9 @@ void JavaRunner::execute()
printf("Finished executingFn - Runs callbackFn\n"); printf("Finished executingFn - Runs callbackFn\n");
this->exitCallbackFn(); this->exitCallbackFn();
return std::async(std::launch::async, []{ return 0; });
} catch (std::exception* ex) { } catch (std::exception* ex) {
printf("ERROR: %s\n", ex->what()); printf("ERROR: %s\n", ex->what());
return nullopt;
} }
} }

View File

@ -3,10 +3,14 @@
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string>
#include <list>
#include <subprocess.hpp> #include <subprocess.hpp>
#include <optional.hpp>
using namespace subprocess; using namespace subprocess;
using namespace std::experimental;
class JavaRunner; class JavaRunner;
@ -34,7 +38,31 @@ public:
JavaRunner(std::string javaBin, const fp_proc_t& executingFn, const fp_t& cb); JavaRunner(std::string javaBin, const fp_proc_t& executingFn, const fp_t& cb);
~JavaRunner() = default; ~JavaRunner() = default;
void execute(); 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::shared_ptr<Popen> javaProcess;
std::string javaBinaryPath; std::string javaBinaryPath;
private: private:

View File

@ -22,8 +22,11 @@ rule ar
rule cleanup rule cleanup
command = rm -fr *.o clauncher I2PLauncher.app command = rm -fr *.o clauncher I2PLauncher.app
# TODO: There must exists a cleaner way to solve this.
rule bundledir rule bundledir
command = mkdir -p I2PLauncher.app/Contents/{MacOS,Resources,Frameworks} && cp Info.plist I2PLauncher.app/Contents/Info.plist 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
rule copytobundledir rule copytobundledir
command = cp clauncher I2PLauncher.app/Contents/MacOS/I2PLauncher command = cp clauncher I2PLauncher.app/Contents/MacOS/I2PLauncher
@ -31,6 +34,9 @@ rule copytobundledir
rule copyimgtobundle rule copyimgtobundle
command = cp ItoopieTransparent.png I2PLauncher.app/Contents/Resources/ItoopieTransparent.png command = cp ItoopieTransparent.png I2PLauncher.app/Contents/Resources/ItoopieTransparent.png
rule builddir
command = mkdir -p build
build main.o: cxx main.mm build main.o: cxx main.mm
build StatusItemButton.o: cxx StatusItemButton.mm build StatusItemButton.o: cxx StatusItemButton.mm
build JavaRunner.o: cxx JavaRunner.cpp build JavaRunner.o: cxx JavaRunner.cpp
@ -43,4 +49,5 @@ build copytobundle: copytobundledir | bundle clauncher
build clauncher: link main.o StatusItemButton.o JavaRunner.o build clauncher: link main.o StatusItemButton.o JavaRunner.o
build appbundle: copyimgtobundle | clauncher bundle copytobundle build appbundle: copyimgtobundle | clauncher bundle copytobundle
#build all: clauncher
default appbundle

View File

@ -0,0 +1,65 @@
package net.i2p.launchers;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* As the name suggest, it extracts the base path.
*
* @author Meeh
* @since 0.9.35
*/
public class BaseExtractor extends EnvCheck {
private void runExtract(String zipFilename, String destinationPath) {
try(ZipFile file = new ZipFile(zipFilename)) {
FileSystem fileSystem = FileSystems.getDefault();
Enumeration<? extends ZipEntry> entries = file.entries();
Files.createDirectory(fileSystem.getPath(destinationPath));
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.isDirectory()) {
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();
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());
}
}
} catch (IOException e) {
//
}
}
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);
}
}

View File

@ -0,0 +1,27 @@
package net.i2p.launchers;
/**
* Both the extractor class and the launcher class needs to be able to verify
* the environment (variables) to work. This is a base class implementing it.
*
* @author Meeh
* @since 0.9.35
*/
public class EnvCheck {
protected String baseDirPath = null;
protected boolean isBaseDirectorySet() {
baseDirPath = System.getProperty("i2p.base.dir");
if (baseDirPath == null) {
baseDirPath = System.getenv("I2PBASE");
}
return (baseDirPath != null);
}
public EnvCheck(String[] args) {
if (!isBaseDirectorySet()) {
throw new RuntimeException("Can't detect I2P's base directory!");
}
}
}

View File

@ -0,0 +1,25 @@
package net.i2p.launchers;
import net.i2p.router.Router;
public class SimpleOSXLauncher extends EnvCheck {
protected Router i2pRouter;
/**
*
* This is bairly a abstraction layer for the Router.
* Why? I suspect we will add some spesific osx launcher code at startup
* in the jvm somewhere, and this seem like a nice place to not make a mess everywhere.
*
* @author Meeh
* @since 0.9.35
*/
public SimpleOSXLauncher(String[] args) {
super(args);
i2pRouter = new Router();
}
public static void main(String[] args) {
new SimpleOSXLauncher(args);
}
}