source: launchers/macosx/main.mm @ e36a3b3

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

Mac OSX Launcher:

  • Fixed startup option so the launcher can start at OSX login/bootup.
  • Added I2P Browser to the list of "firefox" browsers to detect.
  • Changed hardcoded path lookup to native "registry" lookup for firefox application.
  • Made the advanced preferences table editable by the user.
  • Cleanup of old and/or unused code.
  • Bugfixes.
  • Property mode set to 100644
File size: 7.6 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#include <CoreFoundation/CFPreferences.h>
15
16#import <objc/Object.h>
17#import <Cocoa/Cocoa.h>
18#import <AppKit/AppKit.h>
19#import <AppKit/NSApplication.h>
20
21#import "I2PLauncher-Swift.h"
22
23#include "AppDelegate.h"
24#include "RouterTask.h"
25#include "include/fn.h"
26#include "include/portcheck.h"
27#import "SBridge.h"
28#import "Deployer.h"
29#include "logger_c.h"
30
31#ifdef __cplusplus
32#include <string>
33
34#include "include/subprocess.hpp"
35#include "include/strutil.hpp"
36
37#include "Logger.h"
38#include "LoggerWorker.hpp"
39
40using namespace subprocess;
41#endif
42
43#define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
44
45
46
47@interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
48@end
49
50
51@implementation ExtractMetaInfo : NSObject
52@end
53
54
55@implementation AppDelegate
56
57- (void) awakeFromNib {
58}
59
60
61- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
62     shouldPresentNotification:(NSUserNotification *)notification {
63  return YES;
64}
65
66- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
67{
68  self.deployer = [[I2PDeployer alloc] initWithMetaInfo:self.metaInfo];
69  [self.deployer extractI2PBaseDir:completion];
70}
71
72- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
73  // Init application here
74 
75  self.swiftRuntime = [[SwiftMainDelegate alloc] init];
76 
77  // This setup allows the application to send notifications
78  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
79 
80 
81  // Start with user preferences
82  self.userPreferences = [NSUserDefaults standardUserDefaults];
83  // In case we are unbundled, make us a proper UI application
84  [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
85  [NSApp activateIgnoringOtherApps:YES];
86
87
88#ifdef __cplusplus
89
90  RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
91  std::string i2pBaseDir(getDefaultBaseDir());
92  MLOG(INFO) << "i2pBaseDir = " << i2pBaseDir.c_str();
93  bool shouldAutoStartRouter = false;
94 
95  // Initialize the Swift environment (the UI components)
96  [self.swiftRuntime applicationDidFinishLaunching];
97 
98  NSInteger portNum = [self.userPreferences integerForKey:@"consolePortCheckNum"];
99  if (port_check((int)portNum) != 0)
100  {
101    NSLog(@"Seems i2p is already running - I will not start the router (port %d is in use..)", (int)portNum);
102    sendUserNotification(@"Found already running router", @"TCP port 7657 seem to be used by another i2p instance.");
103   
104    [routerStatus setRouterStatus: true];
105    [routerStatus setRouterRanByUs: false];
106    shouldAutoStartRouter = false;
107  } else {
108    shouldAutoStartRouter = true;
109  }
110  if (![self.userPreferences boolForKey:@"startRouterAtLogin"] && ![self.userPreferences boolForKey:@"startRouterAtStartup"])
111  {
112    // In this case we don't want to find a running service
113    std::string launchdFile(RealHomeDirectory());
114    launchdFile += "/Library/LaunchAgents/net.i2p.macosx.I2PRouter.plist";
115   
116  }
117
118  NSBundle *launcherBundle = [NSBundle mainBundle];
119 
120 
121  // Helper object to hold statefull path information
122  self.metaInfo = [[ExtractMetaInfo alloc] init];
123  self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
124  self.metaInfo.javaBinary = [routerStatus getJavaHome];
125  self.metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
126  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
127
128  std::string basearg("-Di2p.dir.base=");
129  basearg += i2pBaseDir;
130
131  std::string jarfile("-cp ");
132  jarfile += [self.metaInfo.zipFile UTF8String];
133 
134  // This will trigger the router start after an upgrade.
135  [routerStatus listenForEventWithEventName:@"router_must_upgrade" callbackActionFn:^(NSString* information) {
136    NSLog(@"Got signal, router must be deployed from base.zip");
137    [self extractI2PBaseDir:^(BOOL success, NSError *error) {
138      if (success) {
139        sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
140        NSLog(@"Done extracting I2P");
141        [routerStatus triggerEventWithEn:@"extract_completed" details:@"upgrade complete"];
142      } else {
143        NSLog(@"Error while extracting I2P");
144        [routerStatus triggerEventWithEn:@"extract_errored" details:[NSString stringWithFormat:@"%@", error]];
145      }
146    }];
147  }];
148 
149  NSString *nsI2PBaseStr = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
150
151  [routerStatus listenForEventWithEventName:@"extract_completed" callbackActionFn:^(NSString* information) {
152    NSLog(@"Time to detect I2P version in install directory");
153    [self.swiftRuntime findInstalledI2PVersion];
154  }];
155 
156  //struct stat sb;
157  //if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
158  BOOL shouldBeTrueOnReturnDir = YES;
159  if (! [NSFileManager.defaultManager fileExistsAtPath: nsI2PBaseStr isDirectory: &shouldBeTrueOnReturnDir])
160  {
161    // I2P is not extracted.
162    if (shouldBeTrueOnReturnDir) {
163      if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
164      [routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
165    } else {
166      // TODO: handle if i2p path exists but it's not a dir.
167    }
168  } else {
169    // I2P was already found extracted
170    NSString *nsI2pJar = [NSString stringWithFormat:@"%@/lib/i2p.jar", nsI2PBaseStr];
171   
172    // But does I2PBASE/lib/i2p.jar exists?
173    if ([NSFileManager.defaultManager fileExistsAtPath:nsI2pJar]) {
174      NSLog(@"Time to detect I2P version in install directory");
175      [self.swiftRuntime findInstalledI2PVersion];
176    } else {
177      // The directory exists, but not i2p.jar - most likely we're in mid-extraction state.
178      [routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
179    }
180  }
181 
182#endif
183}
184
185/**
186 *
187 * Exit sequence
188 *
189 **/
190- (void)applicationWillTerminate:(NSNotification *)aNotification {
191  // Tear down here
192  [self.swiftRuntime applicationWillTerminate];
193  NSString *string = @"applicationWillTerminate executed";
194  NSLog(@"%@", string);
195  [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
196}
197
198
199/* wrapper for main */
200- (AppDelegate *)initWithArgc:(int)argc argv:(const char **)argv {
201  return self;
202}
203@end
204
205#ifdef __cplusplus
206namespace {
207  const std::string logDirectory = getDefaultLogDir();
208}
209#endif
210
211int main(int argc, const char **argv)
212{
213  NSApplication *app = [NSApplication sharedApplication];
214
215#ifdef __cplusplus
216  mkdir(logDirectory.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
217 
218  SharedLogWorker logger("I2PLauncher", logDirectory);
219  MeehLog::initializeLogging(&logger);
220 
221  MLOG(INFO) << "Application is starting up";
222#endif
223 
224  AppDelegate *appDelegate = [[AppDelegate alloc] initWithArgc:argc argv:argv];
225  app.delegate = appDelegate;
226  auto mainBundle = [NSBundle mainBundle];
227  NSString* stringNameBundle = [mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
228  if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:[mainBundle bundleIdentifier]] count] > 1) {
229    [[NSAlert alertWithMessageText:[NSString stringWithFormat:@"Another copy of %@ is already running.",stringNameBundle]
230                     defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"This copy will now quit."] runModal];
231   
232    [NSApp terminate:nil];
233  }
234#pragma GCC diagnostic push
235#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
236  [NSBundle loadNibNamed:@"I2Launcher" owner:NSApp];
237#pragma GCC diagnostic pop
238 
239  [NSApp run];
240  return 0;
241}
242
243
244
Note: See TracBrowser for help on using the repository browser.