source: launchers/macosx/SBridge.mm @ a9bf9e06

Last change on this file since a9bf9e06 was b25dec1, checked in by meeh <meeh@…>, 22 months ago

OSX Launcher: some changes to the Swift↔Objective-C bridge

  • Property mode set to 100644
File size: 6.6 KB
Line 
1//
2//  SBridge.m
3//  I2PLauncher
4//
5//  Created by Mikal Villa on 18/09/2018.
6//  Copyright © 2018 The I2P Project. All rights reserved.
7//
8
9#import "SBridge.h"
10
11#ifdef __cplusplus
12#include <functional>
13#include <memory>
14#include <glob.h>
15#include <string>
16#include <list>
17#include <stdlib.h>
18#include <future>
19#include <vector>
20
21#import <AppKit/AppKit.h>
22#import "I2PLauncher-Swift.h"
23#include "LoggerWorker.hpp"
24#include "Logger.h"
25#include "logger_c.h"
26
27#include "AppDelegate.h"
28#include "include/fn.h"
29
30
31
32std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir, RouterProcessStatus* routerStatus) {
33  @try {
34   
35    /**
36     *
37     * The following code will do a test, where it lists all known processes in the OS (visibility depending on user rights)
38     * and scan for any command/arguments matching the substring "i2p.jar" - and in which case it won't start I2P itself.
39     *
40     **/
41    IIProcessInfo* processInfoObj = [[IIProcessInfo alloc] init];
42    [processInfoObj obtainFreshProcessList];
43    auto anyRouterLookingProcs = [processInfoObj findProcessWithStringInNameOrArguments:@"i2p.jar"];
44    if (anyRouterLookingProcs) {
45      /**
46       * The router was found running
47       */
48      auto errMessage = @"Seems i2p is already running - I've detected another process with i2p.jar in it's arguments.";
49      MLog(4, @"%@", errMessage);
50      sendUserNotification(APP_IDSTR, errMessage);
51      [routerStatus triggerEventWithEn:@"router_already_running" details:@"won't start - another router is running"];
52      return std::async(std::launch::async, []{
53        return -1;
54      });
55    } else {
56      /**
57       * No router was detected running
58       **/
59      RTaskOptions* options = [RTaskOptions alloc];
60      options.binPath = javaBin;
61      options.arguments = arguments;
62      options.i2pBaseDir = i2pBaseDir;
63      auto instance = [[I2PRouterTask alloc] initWithOptions: options];
64     
65      [[SBridge sharedInstance] setCurrentRouterInstance:instance];
66      [instance execute];
67      sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
68      auto pid = [instance getPID];
69      MLog(2, @"Got pid: %d", pid);
70      if (routerStatus != nil) {
71        // TODO: Merge events router_start and router_pid ?
72        [routerStatus triggerEventWithEn:@"router_start" details:@"normal start"];
73        [routerStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
74      }
75      NSString *applicationSupportDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
76      auto pidFile = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/i2p/router.pid", applicationSupportDirectory]];
77      NSError *err;
78     
79      if (![[NSString stringWithFormat:@"%d", pid] writeToURL:pidFile atomically:YES encoding:NSUTF8StringEncoding error:&err]) {
80        MLog(4, @"Error; %@", err);
81      } else {
82        MLog(3, @"Wrote pid file to %@", pidFile);
83      }
84     
85      return std::async(std::launch::async, [&pid]{
86        return pid;
87      });
88    }
89  }
90  @catch (NSException *e)
91  {
92    auto errStr = [NSString stringWithFormat:@"Expection occurred %@",[e reason]];
93    MLog(4, @"%@", errStr);
94    sendUserNotification(APP_IDSTR, errStr);
95    [[SBridge sharedInstance] setCurrentRouterInstance:nil];
96   
97    if (routerStatus != nil) {
98      [routerStatus triggerEventWithEn:@"router_exception" details:errStr];
99    }
100   
101    return std::async(std::launch::async, [&]{
102      return 0;
103    });
104  }
105}
106
107
108
109@implementation SBridge
110
111// this makes it a singleton
112+ (instancetype)sharedInstance {
113  static SBridge *sharedInstance = nil;
114  static dispatch_once_t onceToken;
115 
116  dispatch_once(&onceToken, ^{
117    sharedInstance = [[SBridge alloc] init];
118  });
119  return sharedInstance;
120}
121
122- (void) openUrl:(NSString*)url
123{
124  osx::openUrl(url);
125}
126
127- (NSString*) buildClassPath:(NSString*)i2pPath
128{
129  const char * basePath = [i2pPath UTF8String];
130  auto jarList = buildClassPathForObjC(basePath);
131  const char * classpath = jarList.c_str();
132  MLog(0, @"Classpath from ObjC = %s", classpath);
133  return [[NSString alloc] initWithUTF8String:classpath];
134}
135
136+ (void) logProxy:(int)level formattedMsg:(NSString*)formattedMsg
137{
138  MLog(level, formattedMsg);
139}
140
141
142- (void)startupI2PRouter:(NSString*)i2pRootPath
143{
144  std::string basePath([i2pRootPath UTF8String]);
145 
146  auto classPathStr = buildClassPathForObjC(basePath);
147 
148  RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
149 
150  NSString *confDir = [NSString stringWithFormat:@"%@/Library/Application\\ Support/i2p", NSHomeDirectory()];
151 
152  try {
153    std::vector<NSString*> argList = {
154      @"-v",
155      @"1.7+",
156      @"--exec",
157      @"java",
158      @"-Xmx512M",
159      @"-Xms128m",
160      @"-Djava.awt.headless=true",
161      [NSString stringWithFormat:@"-Dwrapper.logfile=%@/router.log", [NSString stringWithUTF8String:getDefaultLogDir().c_str()]],
162      @"-Dwrapper.logfile.loglevel=DEBUG",
163      [NSString stringWithFormat:@"-Dwrapper.java.pidfile=%@/router.pid", confDir],
164      @"-Dwrapper.console.loglevel=DEBUG"
165    };
166   
167    std::string baseDirArg("-Di2p.dir.base=");
168    baseDirArg += basePath;
169    std::string javaLibArg("-Djava.library.path=");
170    javaLibArg += basePath;
171    // TODO: pass this to JVM
172    //auto java_opts = getenv("JAVA_OPTS");
173   
174    std::string cpString = std::string("-cp");
175   
176    argList.push_back([NSString stringWithUTF8String:baseDirArg.c_str()]);
177    argList.push_back([NSString stringWithUTF8String:javaLibArg.c_str()]);
178    argList.push_back([NSString stringWithUTF8String:cpString.c_str()]);
179    argList.push_back([NSString stringWithUTF8String:classPathStr.c_str()]);
180    argList.push_back(@"net.i2p.router.Router");
181    auto javaBin = std::string("/usr/libexec/java_home");
182   
183   
184    sendUserNotification(APP_IDSTR, @"I2P Router is starting up!");
185    auto nsJavaBin = [NSString stringWithUTF8String:javaBin.c_str()];
186    auto nsBasePath = i2pRootPath;
187    NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()];
188   
189    MLog(0, @"Trying to run command: %@", nsJavaBin);
190    MLog(0, @"With I2P Base dir: %@", i2pRootPath);
191    MLog(0, @"And Arguments: %@", arrArguments);
192    startupRouter(nsJavaBin, arrArguments, nsBasePath, routerStatus);
193  } catch (std::exception &err) {
194    auto errMsg = [NSString stringWithUTF8String:err.what()];
195    MLog(4, @"Exception: %@", errMsg);
196    sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
197    [routerStatus setRouterStatus: false];
198    [routerStatus setRouterRanByUs: false];
199    [routerStatus triggerEventWithEn:@"router_exception" details:[NSString stringWithFormat:@"Error: %@", errMsg]];
200  }
201}
202@end
203
204
205#endif
Note: See TracBrowser for help on using the repository browser.