From 7dbf5682128233b938a3c45e58dcdff8f662cd4a Mon Sep 17 00:00:00 2001
From: meeh <meeh@mail.i2p>
Date: Thu, 11 Oct 2018 11:55:05 +0000
Subject: [PATCH] OSX Launcher: Refactor deployment code to own file, + code
 cleanups.

---
 launchers/macosx/AppDelegate.h |  18 +++--
 launchers/macosx/Deployer.h    |   8 ++-
 launchers/macosx/Deployer.m    |  13 ----
 launchers/macosx/Deployer.mm   | 120 +++++++++++++++++++++++++++++++++
 launchers/macosx/main.mm       | 110 ++++++------------------------
 5 files changed, 160 insertions(+), 109 deletions(-)
 delete mode 100644 launchers/macosx/Deployer.m
 create mode 100644 launchers/macosx/Deployer.mm

diff --git a/launchers/macosx/AppDelegate.h b/launchers/macosx/AppDelegate.h
index 33c2a0ade0..c1ea98d460 100644
--- a/launchers/macosx/AppDelegate.h
+++ b/launchers/macosx/AppDelegate.h
@@ -18,12 +18,7 @@
 
 #include "RouterTask.h"
 
-
-#define DEF_I2P_VERSION "0.9.36"
-#define APPDOMAIN "net.i2p.launcher"
-#define NSAPPDOMAIN @APPDOMAIN
-#define CFAPPDOMAIN CFSTR(APPDOMAIN)
-#define APP_IDSTR @"I2P Launcher"
+#include "version.h"
 
 @class SwiftMainDelegate;
 
@@ -61,6 +56,17 @@ inline std::string getDefaultBaseDir()
   return i2pBaseDir;
 }
 
+inline std::string getDefaultLogDir()
+{
+  // Figure out log directory
+  auto homeDir = RealHomeDirectory();
+  const char* pathFromHome = "%s/Library/Logs/I2P";
+  char buffer[strlen(homeDir)+strlen(pathFromHome)];
+  sprintf(buffer, pathFromHome, homeDir);
+  std::string i2pBaseDir(buffer);
+  return i2pBaseDir;
+}
+
 inline void sendUserNotification(NSString* title, NSString* informativeText, bool makeSound = false) {
   NSUserNotification *userNotification = [[NSUserNotification alloc] init];
   
diff --git a/launchers/macosx/Deployer.h b/launchers/macosx/Deployer.h
index 13ffc5a743..96f6a20a8f 100644
--- a/launchers/macosx/Deployer.h
+++ b/launchers/macosx/Deployer.h
@@ -7,9 +7,15 @@
 //
 
 #import <Foundation/Foundation.h>
+#import <Foundation/NSError.h>
+#import "AppDelegate.h"
 
+@class ExtractMetaInfo;
 
-@interface NSObject ()
 
+@interface I2PDeployer : NSObject
+@property (assign) ExtractMetaInfo *metaInfo;
+- (I2PDeployer *) initWithMetaInfo:(ExtractMetaInfo*)mi;
+- (void) extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion;
 @end
 
diff --git a/launchers/macosx/Deployer.m b/launchers/macosx/Deployer.m
deleted file mode 100644
index 835237201f..0000000000
--- a/launchers/macosx/Deployer.m
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-//  Deployer.m
-//  I2PLauncher
-//
-//  Created by Mikal Villa on 19/09/2018.
-//  Copyright © 2018 The I2P Project. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import "Deployer.h"
-
-
-
diff --git a/launchers/macosx/Deployer.mm b/launchers/macosx/Deployer.mm
new file mode 100644
index 0000000000..ff9ed9e3eb
--- /dev/null
+++ b/launchers/macosx/Deployer.mm
@@ -0,0 +1,120 @@
+//
+//  Deployer.m
+//  I2PLauncher
+//
+//  Created by Mikal Villa on 19/09/2018.
+//  Copyright © 2018 The I2P Project. All rights reserved.
+//
+#include <functional>
+#include <memory>
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <list>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <future>
+#include <vector>
+
+#import <Foundation/Foundation.h>
+#import <Foundation/NSFileManager.h>
+#include <CoreFoundation/CFPreferences.h>
+
+#import <objc/Object.h>
+#import <Cocoa/Cocoa.h>
+#import <AppKit/AppKit.h>
+#import <AppKit/NSApplication.h>
+
+#import "I2PLauncher-Swift.h"
+
+#include "AppDelegate.h"
+#include "include/fn.h"
+#import "SBridge.h"
+#include "logger_c.h"
+
+#include <string>
+
+#include "include/subprocess.hpp"
+#include "include/strutil.hpp"
+
+#include "Logger.h"
+#include "LoggerWorker.hpp"
+
+#import "Deployer.h"
+
+#include <string.h>
+
+using namespace subprocess;
+
+@implementation I2PDeployer
+
+- (I2PDeployer *) initWithMetaInfo:(ExtractMetaInfo*)mi
+{
+  self.metaInfo = mi;
+  return self;
+}
+
+- (void) extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
+{
+#ifdef __cplusplus
+  NSBundle *launcherBundle = [NSBundle mainBundle];
+  auto homeDir = RealHomeDirectory();
+  NSLog(@"Home directory is %s", homeDir);
+  
+  std::string basePath(homeDir);
+  basePath.append("/Library/I2P");
+  
+  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
+  
+  NSParameterAssert(basePath.c_str());
+  NSError *error = NULL;
+  BOOL success = YES;
+  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+    
+    
+    try {
+      // Create directory
+      mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
+      
+      auto cli = defaultFlagsForExtractorJob;
+      setenv("I2PBASE", basePath.c_str(), true);
+      //setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true);
+      
+      chdir(basePath.c_str());
+      
+      // Everything behind --exec java - would be passed as arguments to the java executable.
+      std::string execStr = "/usr/bin/unzip "; //std::string([rs.getJavaHome UTF8String]);
+      execStr += [self.metaInfo.zipFile UTF8String];
+      //for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
+      
+      NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
+      sendUserNotification(APP_IDSTR, @"Please hold on while we extract I2P. You'll get a new message once done!");
+      int extractStatus = Popen(execStr.c_str(), environment{{
+        {"I2PBASE", basePath.c_str()}
+      }}).wait();
+      NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
+      if (extractStatus == 0) {
+        NSLog(@"Extraction process done");
+      } else {
+        NSLog(@"Something went wrong");
+      }
+      
+      // All done. Assume success and error are already set.
+      dispatch_async(dispatch_get_main_queue(), ^{
+        if (completion) {
+          completion(YES, error);
+        }
+      });
+      
+      
+    } catch (OSError &err) {
+      auto errMsg = [NSString stringWithUTF8String:err.what()];
+      NSLog(@"Exception: %@", errMsg);
+      sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
+    }
+  });
+#endif
+}
+
+@end
+
diff --git a/launchers/macosx/main.mm b/launchers/macosx/main.mm
index f7eba9c349..06aa715c3f 100644
--- a/launchers/macosx/main.mm
+++ b/launchers/macosx/main.mm
@@ -25,6 +25,8 @@
 #include "include/fn.h"
 #include "include/portcheck.h"
 #import "SBridge.h"
+#import "Deployer.h"
+#include "logger_c.h"
 
 #ifdef __cplusplus
 #include <string>
@@ -61,83 +63,10 @@ using namespace subprocess;
   return YES;
 }
 
-#ifdef __cplusplus
-
 - (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
 {
-  
-  NSBundle *launcherBundle = [NSBundle mainBundle];
-  auto homeDir = RealHomeDirectory();
-  NSLog(@"Home directory is %s", homeDir);
-  
-  std::string basePath(homeDir);
-  basePath.append("/Library/I2P");
-  
-  auto jarResPath = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
-  NSLog(@"Trying to load launcher.jar from url = %@", jarResPath);
-  self.metaInfo.jarFile = jarResPath;
-  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
-  
-  NSParameterAssert(basePath.c_str());
-  NSError *error = NULL;
-  BOOL success = NO;
-  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-
-
-    try {
-      std::string basearg("-Di2p.dir.base=");
-      basearg += basePath;
-
-      std::string zippath("-Di2p.base.zip=");
-      zippath += [self.metaInfo.zipFile UTF8String];
-
-      std::string jarfile("-cp ");
-      jarfile += [self.metaInfo.jarFile UTF8String];
-
-      // Create directory
-      mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
-
-      auto cli = 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 rs = [[RouterProcessStatus alloc] init];
-      
-      std::string execStr = std::string([rs.getJavaHome UTF8String]);
-      for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
-
-      NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
-      sendUserNotification(APP_IDSTR, @"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", basePath.c_str()}
-      }}).wait();
-      NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
-      if (extractStatus == 0) {
-        NSLog(@"Extraction process done");
-      } else {
-        NSLog(@"Something went wrong");
-      }
-
-      // All done. Assume success and error are already set.
-      dispatch_async(dispatch_get_main_queue(), ^{
-        if (completion) {
-          completion(success, error);
-        }
-      });
-      
-      
-    } catch (OSError &err) {
-      auto errMsg = [NSString stringWithUTF8String:err.what()];
-      NSLog(@"Exception: %@", errMsg);
-      sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
-    }
-  });
+  auto deployer = [[I2PDeployer alloc] initWithMetaInfo:self.metaInfo];
+  [deployer extractI2PBaseDir:completion];
 }
 
 - (void)setApplicationDefaultPreferences {
@@ -145,6 +74,9 @@ using namespace subprocess;
     @"enableLogging": @YES,
     @"enableVerboseLogging": @YES,
     @"autoStartRouter": @YES,
+    @"startRouterAtLogin": @NO,
+    @"startRouterAtStartup": @NO,
+    @"letRouterLiveEvenLauncherDied": @NO,
     @"i2pBaseDirectory": (NSString *)CFStringCreateWithCString(NULL, const_cast<const char *>(getDefaultBaseDir().c_str()), kCFStringEncodingUTF8)
   }];
 
@@ -157,8 +89,6 @@ using namespace subprocess;
   if (self.enableVerboseLogging) NSLog(@"Default preferences stored!");
 }
 
-#endif
-
 
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
   // Init application here
@@ -183,9 +113,12 @@ using namespace subprocess;
 
   RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
   std::string i2pBaseDir(getDefaultBaseDir());
-  NSLog(@"i2pBaseDir = %s", i2pBaseDir.c_str());
+  MLOG(INFO) << "i2pBaseDir = " << i2pBaseDir.c_str();
   bool shouldAutoStartRouter = false;
   
+  // Initialize the Swift environment (the UI components)
+  [self.swiftRuntime applicationDidFinishLaunching];
+  
   // TODO: Make the port a setting which defaults to 7657
   if (port_check(7657) != 0)
   {
@@ -217,16 +150,16 @@ using namespace subprocess;
   
   // Might be hard to read if you're not used to Objective-C
   // But this is a "function call" that contains a "callback function"
-  [routerStatus listenForEventWithEventName:@"router_can_start" callbackActionFn:^(NSString* information) {
+  /*[routerStatus listenForEventWithEventName:@"router_can_start" callbackActionFn:^(NSString* information) {
     NSLog(@"Got signal, router can be started");
-    [[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
-  }];
+    [[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase];
+  }];*/
   
   // This will trigger the router start after an upgrade.
   [routerStatus listenForEventWithEventName:@"router_must_upgrade" callbackActionFn:^(NSString* information) {
     NSLog(@"Got signal, router must be deployed from base.zip");
     [self extractI2PBaseDir:^(BOOL success, NSError *error) {
-      if (success && error != nil) {
+      if (success) {
         sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
         NSLog(@"Done extracting I2P");
         [routerStatus triggerEventWithEn:@"extract_completed" details:@"upgrade complete"];
@@ -237,11 +170,12 @@ using namespace subprocess;
     }];
   }];
   
-  // Initialize the Swift environment (the UI components)
-  [self.swiftRuntime applicationDidFinishLaunching];
-  
   NSString *nsI2PBaseStr = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
 
+  [routerStatus listenForEventWithEventName:@"extract_completed" callbackActionFn:^(NSString* information) {
+    NSLog(@"Time to detect I2P version in install directory");
+    [self.swiftRuntime findInstalledI2PVersion];
+  }];
   
   //struct stat sb;
   //if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
@@ -265,10 +199,7 @@ using namespace subprocess;
       [self.swiftRuntime findInstalledI2PVersion];
     } else {
       // The directory exists, but not i2p.jar - most likely we're in mid-extraction state.
-      [routerStatus listenForEventWithEventName:@"extract_completed" callbackActionFn:^(NSString* information) {
-        NSLog(@"Time to detect I2P version in install directory");
-        [self.swiftRuntime findInstalledI2PVersion];
-      }];
+      [routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
     }
   }
   
@@ -282,6 +213,7 @@ using namespace subprocess;
  **/
 - (void)applicationWillTerminate:(NSNotification *)aNotification {
   // Tear down here
+  [self.swiftRuntime applicationWillTerminate];
   NSString *string = @"applicationWillTerminate executed";
   NSLog(@"%@", string);
   [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
-- 
GitLab