source: launchers/macosx/main.mm @ e046418f

Last change on this file since e046418f was e046418f, checked in by meeh <meeh@…>, 23 months ago

Cleaning up the code base, remove dead code and failed attempts.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1#include <functional>
2#include <memory>
3#include <iostream>
4#include <algorithm>
5#include <string>
6#include <list>
7#include <sys/stat.h>
8#include <stdlib.h>
9#include <future>
10#include <vector>
11
12#import <Foundation/Foundation.h>
13#import <Foundation/NSFileManager.h>
14
15
16#include <CoreFoundation/CoreFoundation.h>
17#include <CoreFoundation/CFStream.h>
18#include <CoreFoundation/CFPropertyList.h>
19#include <CoreFoundation/CFDictionary.h>
20#include <CoreFoundation/CFArray.h>
21#include <CoreFoundation/CFString.h>
22#include <CoreFoundation/CFPreferences.h>
23
24#import <objc/Object.h>
25#import <Cocoa/Cocoa.h>
26#import <AppKit/AppKit.h>
27#import <AppKit/NSApplication.h>
28
29#import "I2PLauncher-Swift.h"
30
31#include "AppDelegate.h"
32#include "RouterTask.h"
33#include "JavaHelper.h"
34#include "include/fn.h"
35#include "include/portcheck.h"
36
37#ifdef __cplusplus
38#import "SBridge.h"
39
40#include "include/subprocess.hpp"
41#include "include/strutil.hpp"
42
43using namespace subprocess;
44
45JvmListSharedPtr gRawJvmList = nullptr;
46
47maybeAnRouterRunner getGlobalRouterObject()
48{
49  std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
50  return globalRouterStatus; // Remember this might be nullptr now.
51}
52
53void setGlobalRouterObject(I2PRouterTask* newRouter)
54{
55  std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
56  globalRouterStatus = newRouter;
57}
58
59
60pthread_mutex_t mutex;
61
62bool getGlobalRouterIsRunning()
63{
64  pthread_mutex_lock(&mutex);
65  bool current = isRuterRunning;
66  pthread_mutex_unlock(&mutex);
67  return current;
68}
69void setGlobalRouterIsRunning(bool running)
70{
71  pthread_mutex_lock(&mutex);
72  isRuterRunning = running;
73  pthread_mutex_unlock(&mutex);
74}
75
76#endif
77
78#define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
79
80@interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
81@end
82
83
84@implementation ExtractMetaInfo : NSObject
85@end
86
87
88@implementation AppDelegate
89
90- (void) awakeFromNib {
91}
92
93#ifdef __cplusplus
94
95- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
96{
97 
98  NSBundle *launcherBundle = [NSBundle mainBundle];
99  auto homeDir = RealHomeDirectory();
100  NSLog(@"Home directory is %s", homeDir);
101 
102  std::string basePath(homeDir);
103  basePath.append("/Library/I2P");
104  auto jarResPath = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
105  NSLog(@"Trying to load launcher.jar from url = %@", jarResPath);
106  self.metaInfo.jarFile = jarResPath;
107  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
108 
109  NSParameterAssert(basePath.c_str());
110  NSError *error = NULL;
111  BOOL success = NO;
112  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
113
114
115    try {
116      std::string basearg("-Di2p.dir.base=");
117      basearg += basePath;
118
119      std::string zippath("-Di2p.base.zip=");
120      zippath += [self.metaInfo.zipFile UTF8String];
121
122      std::string jarfile("-cp ");
123      jarfile += [self.metaInfo.jarFile UTF8String];
124
125      // Create directory
126      mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
127
128      auto cli = JavaRunner::defaultFlagsForExtractorJob;
129      setenv("I2PBASE", basePath.c_str(), true);
130      setenv("ZIPPATH", zippath.c_str(), true);
131      //setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true);
132
133      cli.push_back(basearg);
134      cli.push_back(zippath);
135      cli.push_back(jarfile);
136      cli.push_back("net.i2p.launchers.BaseExtractor");
137      auto rs = [[RouterProcessStatus alloc] init];
138      NSString* jh = [rs getJavaHome];
139      if (jh != nil) {
140        NSLog(@"jh er %@", jh);
141      }
142     
143      NSString* newString = [NSString stringWithFormat:@"file://%@", rs.getJavaHome];
144      NSURL *baseURL = [NSURL fileURLWithPath:newString];
145     
146      NSLog(@"MEEH URL PATH: %s", [baseURL fileSystemRepresentation]);
147
148      auto charCli = map(cli, [](std::string str){ return str.c_str(); });
149      std::string execStr = std::string([rs.getJavaHome UTF8String]);
150      // TODO: Cheap hack, make it better.
151      replace(execStr, "Internet Plug-Ins", "Internet\\ Plug-Ins");
152      replace(execStr, "\n", "");
153      NSLog(@"Java path1 = %s", execStr.c_str());
154      [rs setJavaHome: [NSString stringWithFormat:@"%s", execStr.c_str()]];
155      for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
156     
157      //execStr = replace(execStr, "\\\\ ", "\\ ");
158      //NSLog(@"Java path2 = %s", execStr.c_str());
159
160      NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
161      try {
162        sendUserNotification(APP_IDSTR, @"Please hold on while we extract I2P. You'll get a new message once done!");
163        int extractStatus = Popen(execStr.c_str(), environment{{
164          {"ZIPPATH", zippath.c_str()},
165          {"I2PBASE", basePath.c_str()}
166        }}).wait();
167        NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
168        if (extractStatus == 0)
169        {
170          //success = YES;
171          NSLog(@"Time to detect I2P version in install directory");
172          [self.swiftRuntime findInstalledI2PVersion];
173        }
174     
175      } catch (subprocess::OSError &err) {
176          auto errMsg = [NSString stringWithUTF8String:err.what()];
177          //success = NO;
178          NSLog(@"Exception: %@", errMsg);
179          sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
180      }
181
182      // All done. Assume success and error are already set.
183      dispatch_async(dispatch_get_main_queue(), ^{
184        //sendUserNotification(APP_IDSTR, @"Extraction complete!", self.contentImage);
185        if (completion) {
186          completion(success, error);
187        }
188      });
189     
190     
191    } catch (OSError &err) {
192      auto errMsg = [NSString stringWithUTF8String:err.what()];
193      NSLog(@"Exception: %@", errMsg);
194    }
195  });
196   
197 
198}
199
200#endif
201
202- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
203                               shouldPresentNotification:(NSUserNotification *)notification {
204    return YES;
205}
206
207
208#ifdef __cplusplus
209
210- (NSString *)userSelectJavaHome:(JvmListPtr)rawJvmList
211{
212  NSString *appleScriptString = @"set jvmlist to {\"Newest\"";
213  for (auto item : *rawJvmList) {
214    auto str = strprintf(",\"%s\"", item->JVMName.c_str()).c_str();
215    NSString* tmp = [NSString stringWithUTF8String:str];
216    appleScriptString = [appleScriptString stringByAppendingString:tmp];
217  }
218  appleScriptString = [appleScriptString stringByAppendingString:@"}\nchoose from list jvmlist\n"];
219  NSAppleScript *theScript = [[NSAppleScript alloc] initWithSource:appleScriptString];
220  NSDictionary *theError = nil;
221  NSString* userResult = [[theScript executeAndReturnError: &theError] stringValue];
222  NSLog(@"User choosed %@.\n", userResult);
223  if (theError != nil)
224  {
225    NSLog(@"Error: %@.\n", theError);
226  }
227  return userResult;
228}
229
230
231- (void)userChooseJavaHome {
232  listAllJavaInstallsAvailable();
233  std::shared_ptr<JvmHomeContext> appContext = std::shared_ptr<JvmHomeContext>( new JvmHomeContext() );
234  for (auto item : *appContext->getJvmList()) {
235    printf("JVM %s (Version: %s, Directory: %s)\n", item->JVMName.c_str(), item->JVMPlatformVersion.c_str(), item->JVMHomePath.c_str());
236  }
237  JvmListPtr rawJvmList = appContext->getJvmList();
238  NSString * userJavaHome = [self userSelectJavaHome: rawJvmList];
239  // TODO: Add logic so user can set preferred JVM
240}
241
242#endif
243
244- (void)setApplicationDefaultPreferences {
245  auto defaultJVMHome = check_output({"/usr/libexec/java_home","-v",DEF_MIN_JVM_VER});
246  auto tmpStdStr = std::string(defaultJVMHome.buf.data());
247  trim(tmpStdStr);
248  auto cfDefaultHome  = CFStringCreateWithCString(NULL, const_cast<const char *>(tmpStdStr.c_str()), kCFStringEncodingUTF8);
249  /*[self.userPreferences registerDefaults:@{
250    @"javaHome" : (NSString *)cfDefaultHome,
251    @"lastI2PVersion" : (NSString *)CFSTR(DEF_I2P_VERSION),
252    @"enableLogging": @YES,
253    @"enableVerboseLogging": @YES,
254    @"autoStartRouter": @YES,
255    @"i2pBaseDirectory": (NSString *)CFStringCreateWithCString(NULL, const_cast<const char *>(getDefaultBaseDir().c_str()), kCFStringEncodingUTF8)
256  }];*/
257  if (self.enableVerboseLogging) NSLog(@"Default JVM home preference set to: %@", cfDefaultHome);
258
259  auto dict = [self.userPreferences dictionaryRepresentation];
260  [self.userPreferences setPersistentDomain:dict forName:NSAPPDOMAIN];
261
262  CFPreferencesSetMultiple((CFDictionaryRef)dict, NULL, CFAPPDOMAIN, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
263  CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
264
265  if (self.enableVerboseLogging) NSLog(@"Default preferences stored!");
266}
267
268
269- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
270  // Init application here
271 
272  self.swiftRuntime = [[SwiftMainDelegate alloc] init];
273 
274  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
275  // Start with user preferences
276  self.userPreferences = [NSUserDefaults standardUserDefaults];
277  [self setApplicationDefaultPreferences];
278  self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"];
279  self.enableVerboseLogging = [self.userPreferences boolForKey:@"enableVerboseLogging"];
280
281
282#ifdef __cplusplus
283  gRawJvmList = std::make_shared<std::list<JvmVersionPtr> >(std::list<JvmVersionPtr>());
284#endif
285  // In case we are unbundled, make us a proper UI application
286  [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
287  [NSApp activateIgnoringOtherApps:YES];
288
289  // TODO: Also check for new installations from time to time.
290 
291#ifdef __cplusplus
292  auto javaHomePref = [self.userPreferences stringForKey:@"javaHome"];
293  if (self.enableVerboseLogging)
294  {
295    NSLog(@"Java home from preferences: %@", javaHomePref);
296  }
297
298  if (self.enableVerboseLogging)
299  {
300    NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
301    NSLog(@"Appdomain is: %@", appDomain);
302  }
303
304  NSLog(@"We should have started the statusbar object by now...");
305  RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
306
307  std::string i2pBaseDir(getDefaultBaseDir());
308
309  auto pref = self.userPreferences;
310 
311  bool shouldAutoStartRouter = false;
312
313  if (port_check(7657) != 0)
314  {
315    NSLog(@"Seems i2p is already running - I will not start the router (port 7657 is in use..)");
316    sendUserNotification(@"Found already running router", @"TCP port 7657 seem to be used by another i2p instance.");
317   
318    [routerStatus setRouterStatus: true];
319    [routerStatus setRouterRanByUs: false];
320    return;
321  } else {
322    shouldAutoStartRouter = true;
323  }
324
325  if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
326
327  auto getJavaBin = [&pref,&self]() -> std::string {
328    // Get Java home
329    /*NSString* val = @"";
330    val = [pref stringForKey:@"javaHome"];
331    if (val == NULL) val = @"";
332    if (self.enableVerboseLogging) NSLog(@"Javahome: %@", val);
333    auto javaHome = std::string([val UTF8String]);
334    //trim(javaHome); // Trim to remove endline
335    auto javaBin = std::string(javaHome);
336    javaBin += "/bin/java"; // Append java binary to path.
337    return javaBin;*/
338    DetectJava *dt = [[DetectJava alloc] init];
339    [dt findIt];
340    if ([dt isJavaFound]) {
341      return [dt.javaHome UTF8String];
342    } else {
343      throw new std::runtime_error("Java home fatal error");
344    }
345  };
346
347
348  NSBundle *launcherBundle = [NSBundle mainBundle];
349 
350  auto jarResPath = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
351  NSLog(@"Trying to load launcher.jar from url = %@", jarResPath);
352   
353  self.metaInfo = [[ExtractMetaInfo alloc] init];
354  //self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
355  self.metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()];
356  self.metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
357  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
358
359  std::string basearg("-Di2p.dir.base=");
360  //basearg += i2pBaseDir;
361
362  std::string jarfile("-cp ");
363  jarfile += [self.metaInfo.zipFile UTF8String];
364 
365
366  struct stat sb;
367  if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
368  {
369    // I2P is not extracted.
370    if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
371
372    [self extractI2PBaseDir:^(BOOL success, NSError *error) {
373      sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
374      [self.swiftRuntime applicationDidFinishLaunching];
375      NSLog(@"Done extracting I2P");
376      if (shouldAutoStartRouter) [self startupI2PRouter];
377    }];
378
379  } else {
380    if (self.enableVerboseLogging) NSLog(@"I2P directory found!");
381    if (shouldAutoStartRouter) [self startupI2PRouter];
382    [self.swiftRuntime applicationDidFinishLaunching];
383  }
384 
385#endif
386}
387
388
389
390/**
391 *
392 * Exit sequence
393 *
394 **/
395- (void)applicationWillTerminate:(NSNotification *)aNotification {
396  // Tear down here
397  NSString *string = @"applicationWillTerminate executed";
398  NSLog(@"%@", string);
399  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
400}
401
402
403/* wrapper for main */
404- (AppDelegate *)initWithArgc:(int)argc argv:(const char **)argv {
405  return self;
406}
407@end
408
409
410
411int main(int argc, const char **argv)
412{
413  NSApplication *app = [NSApplication sharedApplication];
414  //NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
415
416  AppDelegate *appDelegate = [[AppDelegate alloc] initWithArgc:argc argv:argv];
417  app.delegate = appDelegate;
418  [NSBundle loadNibNamed:@"I2Launcher" owner:NSApp];
419
420  [NSApp run];
421  // Handle any errors
422  //[pool drain];
423  return 0;
424}
425
426
427
Note: See TracBrowser for help on using the repository browser.