I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 7615b923 authored by meeh's avatar meeh
Browse files

Adding all new code, removed a lot obsolete code and fixed import paths etc.

Mac OS X launcher:
* UI built on Swift
  * Why?
    * Apple seems to on purpose make it harder to get into Objective-C these days
    * Swift is compiled to native code, but has easiness of Javascript in programming
    * Perfect for the OS X UI, many guides & tutorials as well
* "Backend" in Objective-C++ / C++14
  * Why?
    * Originally written in Objective-C / C++14 with C++17 backports
    * Only for backend because of the time the development takes
    *

Short summary of features:

* Java
  * It can detect java from:
    * JAVA_HOME environment variable
    * "Internet Plug-Ins" Apple stuff
    * By the /usr/libexec/java_home binary helper
  * It can unpack a new version of I2P
    * Unpacks to ~/Library/I2P
    * Can check currently unpacked version in ~/Library/I2P via i2p.jar's "net.i2p.CoreVersion"

  * User Interface (a popover, see https://youtu.be/k8L3lQ5rUq0 for example of this concept)
    * Router control tab view
      * It can start the router
      * It can stop the router
      * It can detect already running router, then avoid fireing up one
      * It can show basic information about the router state & version
    * Log view tab (not yet done)
  * While left-click triggers popover, right-click draws a minimal context menu
parent 1bddf552
No related branches found
No related tags found
No related merge requests found
Showing
with 976 additions and 41 deletions
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu id="TTS-U7-WkT" userLabel="statusBarContextMenu">
<items>
<menuItem title="Open Console" id="cOe-UL-1TW">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="openConsoleClicked:" target="-1" id="uR3-lb-ikG"/>
</connections>
</menuItem>
<menuItem title="Start I2P Router" id="RQ8-Q2-68A">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startRouterClicked:" target="-1" id="Vl3-cC-77e"/>
</connections>
</menuItem>
<menuItem title="Exit" id="hsL-CH-m3C">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="quickClicked:" target="-1" id="hiW-5d-nBX"/>
</connections>
</menuItem>
</items>
<point key="canvasLocation" x="17" y="167"/>
</menu>
</objects>
</document>
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "SBridge.h"
#import "AppleStuffExceptionHandler.h"
...@@ -3,47 +3,53 @@ ...@@ -3,47 +3,53 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>English</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>I2PLauncher</string> <string>$(EXECUTABLE_NAME)</string>
<key>NSHumanReadableCopyright</key>
<string>Public Domain</string>
<key>CFBundleGetInfoString</key>
<string>0.9.35-experimental</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>images/AppIcon.icns</string> <string></string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>net.i2p.launcher</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>I2P</string> <string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.1</string> <string>1.0</string>
<key>CFBundleSignature</key> <key>CFBundleURLTypes</key>
<string>I2P</string> <array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLIconFile</key>
<string>ItoopieTransparent</string>
<key>CFBundleURLName</key>
<string>http+i2p</string>
<key>CFBundleURLSchemes</key>
<array>
<string>http+i2p</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.0.1</string> <string>1</string>
<key>NSUserNotificationAlertStyle</key> <key>LSMinimumSystemVersion</key>
<string>alert</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSAppleScriptEnabled</key> <key>LSUIElement</key>
<true/> <true/>
<key>CGDisableCoalescedUpdates</key> <key>NSAppleScriptEnabled</key>
<true/> <true/>
<key>LSMinimumSystemVersion</key> <key>NSHumanReadableCopyright</key>
<string>10.5</string> <string>Copyright © 2018 The I2P Project. All rights reserved.</string>
<key>CFBundleDisplayName</key> <key>NSMainNibFile</key>
<string>I2P</string> <string>UserInterfaces</string>
<key>LSMinimumSystemVersionByArchitecture</key> <key>NSPrincipalClass</key>
<dict> <string>NSApplication</string>
<key>i386</key> <key>NSServices</key>
<string>10.5.0</string> <array>
<key>x86_64</key> <dict/>
<string>10.6.0</string> </array>
</dict>
<key>LSUIElement</key>
<string>1</string>
</dict> </dict>
</plist> </plist>
# The Objective-C++ part of the Mac OS X launcher
## Why?
Code signing, OS X integration.
## Howto build?
Preferred tool is [ninja](https://ninja-build.org/). A makefile is also available.
Build with: `ninja`
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="box content view" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--PopoverController-->
<scene sceneID="4eF-i8-6L0">
<objects>
<viewController identifier="PopoverView" storyboardIdentifier="PopoverView" id="Ii7-Rb-Ls8" userLabel="PopoverController" customClass="PopoverViewController" customModule="I2PLauncher" customModuleProvider="target" sceneMemberID="viewController">
<tabView key="view" allowsTruncatedLabels="NO" initialItem="Fle-u6-lgB" id="dmf-Go-6qY">
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="Router Status &amp; Control" identifier="" id="Fle-u6-lgB">
<view key="view" canDrawConcurrently="YES" id="xXg-Bt-RWR" customClass="RouterStatusView" customModule="I2PLauncher" customModuleProvider="target">
<rect key="frame" x="10" y="33" width="430" height="254"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<box fixedFrame="YES" title="Router information and status" translatesAutoresizingMaskIntoConstraints="NO" id="e8C-qI-SCp">
<rect key="frame" x="6" y="16" width="279" height="231"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" id="zBB-wE-VXr">
<rect key="frame" x="2" y="2" width="275" height="214"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField identifier="RouterStatusLabel" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Eo-re-5WK" userLabel="RouterStatusLabel">
<rect key="frame" x="6" y="190" width="245" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Router status: Unknown" id="m7V-Se-tnf">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="RouterVersionLabel" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sGy-NV-gmH" userLabel="RouterVersionLabel">
<rect key="frame" x="6" y="171" width="245" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Router version: Unknown" id="Mda-Os-8O9">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="RouterStartedByLabel" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tgG-IT-Ojg" userLabel="RouterStartedByLabel">
<rect key="frame" x="6" y="152" width="245" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Router started by launcher? No" id="WBg-nH-kwu">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="RouterUptimeLabel" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f2W-Kc-cxB" userLabel="RouterUptimeLabel">
<rect key="frame" x="6" y="133" width="245" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Router uptime: Unknown" id="uQ0-cW-tYL">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</box>
<box fixedFrame="YES" title="Quick Control" translatesAutoresizingMaskIntoConstraints="NO" id="IIP-Qi-7dp">
<rect key="frame" x="287" y="16" width="150" height="231"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView" identifier="QuickControlView" id="D8V-d8-0wT">
<rect key="frame" x="2" y="2" width="146" height="214"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button identifier="startstopRouterButton" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1eu-Qw-TD9" userLabel="start-stop-button">
<rect key="frame" x="0.0" y="176" width="147" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Start/Stop Router" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="OYN-sS-eQH">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button identifier="restartRouterButton" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C1m-1t-Xiq" userLabel="restart-button">
<rect key="frame" x="10" y="150" width="128" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Restart Router" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sih-uF-V06">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button identifier="openConsoleButton" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XZi-oz-5gy" userLabel="open-console-button">
<rect key="frame" x="11" y="123" width="126" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Open Console" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Yh8-lj-JFi">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
</view>
</box>
</subviews>
<connections>
<outlet property="quickControlView" destination="D8V-d8-0wT" id="4to-rN-2eL"/>
<outlet property="routerStartStopButton" destination="1eu-Qw-TD9" id="FLt-MK-y5u"/>
<outlet property="routerStartedByLabel" destination="tgG-IT-Ojg" id="dA0-3w-cuF"/>
<outlet property="routerStatusLabel" destination="0Eo-re-5WK" id="7dm-Et-eSn"/>
<outlet property="routerUptimeLabel" destination="f2W-Kc-cxB" id="4Ya-qU-eb3"/>
<outlet property="routerVersionLabel" destination="sGy-NV-gmH" id="tM5-4M-DKy"/>
</connections>
</view>
</tabViewItem>
<tabViewItem label="Router Log Viewer" identifier="" id="IFq-CR-cjD" customClass="LogViewerViewController" customModule="I2PLauncher" customModuleProvider="target">
<view key="view" id="7U9-d7-IVr">
<rect key="frame" x="10" y="33" width="430" height="254"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView identifier="LoggerTextScrollView" fixedFrame="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jca-Kn-cO2" userLabel="LoggerTextScrollView">
<rect key="frame" x="11" y="17" width="409" height="228"/>
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" ambiguous="YES" id="E5l-WA-qOn">
<rect key="frame" x="1" y="1" width="407" height="226"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView identifier="LoggerTextView" ambiguous="YES" importsGraphics="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="bgQ-8i-Xgb" userLabel="LoggerTextView">
<rect key="frame" x="0.0" y="0.0" width="407" height="226"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="407" height="226"/>
<size key="maxSize" width="463" height="10000000"/>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="MRF-Wt-zdZ">
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="Xq6-ur-WuT">
<rect key="frame" x="392" y="1" width="16" height="226"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
</view>
<connections>
<outlet property="scrollView" destination="jca-Kn-cO2" id="qAi-hi-PsC"/>
<outlet property="textFieldView" destination="bgQ-8i-Xgb" id="SbC-0r-xPR"/>
</connections>
</tabViewItem>
</tabViewItems>
</tabView>
</viewController>
<customObject id="d8g-wS-Zts" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-823" y="166"/>
</scene>
</scenes>
</document>
//
// SwiftMainDelegate.swift
// I2PLauncher
//
// Created by Mikal Villa on 17/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
import Cocoa
@objc class SwiftMainDelegate : NSObject {
//let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength )
let statusBarController = StatusBarController()
let javaDetector = DetectJava()
static let objCBridge = SBridge()
override init() {
super.init()
self.javaDetector.findIt()
if (!javaDetector.isJavaFound()) {
print("Could not find java....")
terminate("No java..")
}
let javaBinPath = self.javaDetector.javaHome
print("Found java home = ", javaBinPath)
let (portIsNotTaken, descPort) = RouterProcessStatus.checkTcpPortForListen(port: 7657)
if (!portIsNotTaken) {
RouterProcessStatus.isRouterRunning = true
RouterProcessStatus.isRouterChildProcess = false
print("I2P Router seems to be running")
} else {
RouterProcessStatus.isRouterRunning = false
print("I2P Router seems to NOT be running")
}
}
func findInstalledI2PVersion(jarPath: String, javaBin: String) {
var i2pPath = NSHomeDirectory()
i2pPath += "/Library/I2P"
var jExecPath:String = javaBin
// Sometimes, home will return the binary, sometimes the actual home dir. This fixes the diverge.
// If JRE is detected, binary follows - if it's JDK, home follows.
if (jExecPath.hasSuffix("Home")) {
jExecPath += "/jre/bin/java"
}
let subCmd = jExecPath + " -cp " + jarPath + " net.i2p.CoreVersion"
var cmdArgs:[String] = ["-c", subCmd]
print(cmdArgs)
let sub:Subprocess = Subprocess.init(executablePath: "/bin/sh", arguments: cmdArgs)
let results:ExecutionResult = sub.execute(captureOutput: true)!
if (results.didCaptureOutput) {
print("captured output")
let i2pVersion = results.outputLines.first?.replace(target: "I2P Core version: ", withString: "")
print("I2P version detected: ",i2pVersion!)
RouterProcessStatus.routerVersion = i2pVersion
} else {
print("did NOT captured output")
}
}
@objc func applicationDidFinishLaunching() {
print("Hello from swift!")
var i2pPath = NSHomeDirectory()
i2pPath += "/Library/I2P"
let javaBinPath = self.javaDetector.javaHome.replace(target: " ", withString: "\\ ")
let fileManager = FileManager()
var ok = ObjCBool(true)
let doesI2PDirExists = fileManager.fileExists(atPath: i2pPath, isDirectory: &ok)
if (!doesI2PDirExists) {
// Deploy
}
let i2pJarPath = i2pPath + "/lib/i2p.jar"
findInstalledI2PVersion(jarPath: i2pJarPath, javaBin: javaBinPath)
}
@objc static func openLink(url: String) {
objCBridge.openUrl(url)
}
@objc func applicationWillTerminate() {
// Shutdown stuff
}
@objc func terminate(_ why: Any?) {
print("Stopping cause of ", why!)
}
}
//
// ArrayExtension.swift
// I2PLauncher
//
// Created by Mikal Villa on 17/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
extension Array where Element: NSAttributedString {
func joined2(separator: NSAttributedString) -> NSAttributedString {
var isFirst = true
return self.reduce(NSMutableAttributedString()) {
(r, e) in
if isFirst {
isFirst = false
} else {
r.append(separator)
}
r.append(e)
return r
}
}
}
//
// DateTimeUtils.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
extension Date {
init(date: NSDate) {
self.init(timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate)
}
}
extension NSDate {
convenience init(date: Date) {
self.init(timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate)
}
}
class DateTimeUtils {
static func timeAgoSinceDate(date:NSDate, numericDates:Bool) -> String {
let calendar = NSCalendar.current
let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
let now = NSDate()
let earliest = now.earlierDate(date as Date)
let latest = (earliest == now as Date) ? date : now
let components = calendar.dateComponents(unitFlags, from: earliest as Date, to: latest as Date)
if (components.year! >= 2) {
return "\(components.year!) years ago"
} else if (components.year! >= 1){
if (numericDates){
return "1 year ago"
} else {
return "Last year"
}
} else if (components.month! >= 2) {
return "\(components.month!) months ago"
} else if (components.month! >= 1){
if (numericDates){
return "1 month ago"
} else {
return "Last month"
}
} else if (components.weekOfYear! >= 2) {
return "\(components.weekOfYear!) weeks ago"
} else if (components.weekOfYear! >= 1){
if (numericDates){
return "1 week ago"
} else {
return "Last week"
}
} else if (components.day! >= 2) {
return "\(components.day!) days ago"
} else if (components.day! >= 1){
if (numericDates){
return "1 day ago"
} else {
return "Yesterday"
}
} else if (components.hour! >= 2) {
return "\(components.hour!) hours ago"
} else if (components.hour! >= 1){
if (numericDates){
return "1 hour ago"
} else {
return "An hour ago"
}
} else if (components.minute! >= 2) {
return "\(components.minute!) minutes ago"
} else if (components.minute! >= 1){
if (numericDates){
return "1 minute ago"
} else {
return "A minute ago"
}
} else if (components.second! >= 3) {
return "\(components.second!) seconds ago"
} else {
return "Just now"
}
}
}
//
// EventMonitor.swift
// I2PLauncher
//
// Created by Mikal Villa on 02/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
import Cocoa
public class EventMonitor {
private var monitor: Any?
private let mask: NSEvent.EventTypeMask
private let handler: (NSEvent?) -> Void
public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) {
self.mask = mask
self.handler = handler
}
deinit {
stop()
}
public func start() {
monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler)
}
public func stop() {
if monitor != nil {
NSEvent.removeMonitor(monitor!)
monitor = nil
}
}
}
//
// ReflectionFunctions.swift
// I2PLauncher
//
// Created by Mikal Villa on 17/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
class ReflectionFunctions {
/// Given pointer to first element of a C array, invoke a function for each element
func enumerateCArray<T>(array: UnsafePointer<T>, count: UInt32, f: (UInt32, T) -> ()) {
var ptr = array
for i in 0..<count {
f(i, ptr.pointee)
ptr = ptr.successor()
}
}
/// Return name for a method
func methodName(m: Method) -> String? {
let sel = method_getName(m)
let nameCString = sel_getName(sel)
return String(cString: nameCString!)
}
/// Print the names for each method in a class
func printMethodNamesForClass(cls: AnyClass) {
var methodCount: UInt32 = 0
let methodList = class_copyMethodList(cls, &methodCount)
if methodList != nil && methodCount > 0 {
enumerateCArray(array: methodList!, count: methodCount) { i, m in
let name = methodName(m: m!) ?? "unknown"
print("#\(i): \(name)")
}
free(methodList)
}
}
/// Print the names for each method in a class with a specified name
func printMethodNamesForClassNamed(classname: String) {
// NSClassFromString() is declared to return AnyClass!, but should be AnyClass?
let maybeClass: AnyClass? = NSClassFromString(classname)
if let cls: AnyClass = maybeClass {
printMethodNamesForClass(cls: cls)
}
else {
print("\(classname): no such class")
}
}
}
//
// StringExtensions.swift
// I2PLauncher
//
// Created by Mikal Villa on 17/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
extension String {
func replace(target: String, withString: String) -> String
{
return self.replacingOccurrences(of: target, with: withString, options: NSString.CompareOptions.literal, range: nil)
}
/// Returns an array of string obtained splitting self at each newline ("\n").
/// If the last character is a newline, it will be ignored (no empty string
/// will be appended at the end of the array)
public func splitByNewline() -> [String] {
return self.split { $0 == "\n" }.map(String.init)
}
/// Returns an array of string obtained splitting self at each space, newline or TAB character
public func splitByWhitespace() -> [String] {
let whitespaces = Set<Character>([" ", "\n", "\t"])
return self.split { whitespaces.contains($0) }.map(String.init)
}
public func splitByColon() -> [String] {
return self.split { $0 == ":" }.map(String.init)
}
}
//
// DetectJava.swift
// JavaI2PWrapper
//
// Created by Mikal Villa on 24/03/2018.
// Copyright © 2018 I2P. All rights reserved.
//
import Foundation
class DetectJava : NSObject {
var hasJRE : Bool = false
var userWantJRE : Bool = false
var userAcceptOracleEULA : Bool = false
// Java checks
var javaHome: String = ""{
//Called before the change
willSet(newValue){
print("DetectJava.javaHome will change from "+self.javaHome+" to "+newValue)
}
//Called after the change
didSet{
hasJRE = true
print("MDetectJava.javaHome did change from "+oldValue+" to "+self.javaHome)
}
};
private var testedEnv : Bool = false
private var testedJH : Bool = false
private var testedDfl : Bool = false
func isJavaFound() -> Bool {
if !(self.javaHome.isEmpty) {
return true
}
return false
}
func findIt() {
print("Start with checking environment variable")
self.checkJavaEnvironmentVariable()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
return
}
print("Checking default JRE install path")
self.checkDefaultJREPath()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
return
}
print("Checking with the java_home util")
self.runJavaHomeCmd()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
return
}
}
func runJavaHomeCmd() {
let task = Process()
task.launchPath = "/usr/libexec/java_home"
task.arguments = []
let pipe = Pipe()
task.standardOutput = pipe
let outHandle = pipe.fileHandleForReading
outHandle.waitForDataInBackgroundAndNotify()
var obs1 : NSObjectProtocol!
obs1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable,
object: outHandle, queue: nil) { notification -> Void in
let data = outHandle.availableData
if data.count > 0 {
let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if (str != nil) {
let stringVal = str! as String
print("got output: "+stringVal)
self.javaHome = stringVal
}
// TODO: Found something, check it out
outHandle.waitForDataInBackgroundAndNotify()
} else {
print("EOF on stdout from process")
NotificationCenter.default.removeObserver(obs1)
// No JRE so far
}
}
var obs2 : NSObjectProtocol!
obs2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
object: task, queue: nil) { notification -> Void in
print("terminated")
NotificationCenter.default.removeObserver(obs2)
}
task.launch()
task.waitUntilExit()
self.testedJH = true
}
func checkDefaultJREPath() {
let defaultJREPath = "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
if FileManager.default.fileExists(atPath: defaultJREPath) {
// Found it!!
self.javaHome = defaultJREPath
}
self.testedDfl = true
// No JRE here
}
func getEnvironmentVar(_ name: String) -> String? {
guard let rawValue = getenv(name) else { return nil }
return String(utf8String: rawValue)
}
func checkJavaEnvironmentVariable() {
let dic = ProcessInfo.processInfo.environment
//ProcessInfo.processInfo.environment["JAVA_HOME"]
if let javaHomeEnv = dic["JAVA_HOME"] {
// Maybe we got an JRE
print("Found JAVA_HOME with value:")
print(javaHomeEnv)
self.javaHome = javaHomeEnv
}
self.testedEnv = true
print("JAVA HOME is not set")
}
}
//
// I2PSubprocess.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
protocol I2PSubprocess {
var subprocessPath: String? { get set }
var arguments: String? { get set }
var timeWhenStarted: Date? { get set }
func findJava();
}
extension I2PSubprocess {
func toString() -> String {
let jp = self.subprocessPath!
let args = self.arguments!
var presentation:String = "I2PSubprocess[ cmd="
presentation += jp
presentation += " , args="
presentation += args
presentation += "]"
return presentation
}
}
//
// RouterDeployer.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
class RouterDeployer: NSObject, I2PSubprocess {
var subprocessPath: String?
var timeWhenStarted: Date?
var arguments: String?
func findJava() {
//
}
let javaBinaryPath = RouterProcessStatus.knownJavaBinPath
let defaultFlagsForExtractorJob:[String] = [
"-Xmx512M",
"-Xms128m",
"-Djava.awt.headless=true"
]
}
//
// RouterProcessStatus+ObjectiveC.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
extension RouterProcessStatus {
static func createNewRouterProcess(i2pPath: String, javaBinPath: String) {
let bridge = SBridge()
let timeWhenStarted = Date()
RouterProcessStatus.routerStartedAt = timeWhenStarted
bridge.startupI2PRouter(i2pPath, javaBinPath: javaBinPath)
}
}
//
// RouterProcessStatus.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
import AppKit
class RouterProcessStatus : NSObject {
/**
*
* Why the functions bellow? Because the Objective-C bridge is limited, it can't do Swift "static's" over it.
*
**/
func setRouterStatus(_ isRunning: Bool = false) {
RouterProcessStatus.isRouterRunning = isRunning
}
func setRouterRanByUs(_ ranByUs: Bool = false) {
RouterProcessStatus.isRouterChildProcess = ranByUs
}
func getRouterIsRunning() -> Bool? {
return RouterProcessStatus.isRouterRunning
}
}
extension RouterProcessStatus {
static var isRouterRunning : Bool = false
static var isRouterChildProcess : Bool = false
static var routerVersion : String? = Optional.none
static var routerUptime : String? = Optional.none
static var routerStartedAt : Date? = Optional.none
static var knownJavaBinPath : String? = Optional.none
static var i2pDirectoryPath : String = NSHomeDirectory() + "/Library/I2P"
static var knownRouterSubTaskRef : I2PSubprocess? = Optional.none
}
extension RouterProcessStatus {
static func checkTcpPortForListen(port: in_port_t) -> (Bool, descr: String){
let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
if socketFileDescriptor == -1 {
return (false, "SocketCreationFailed, \(descriptionOfLastError())")
}
var addr = sockaddr_in()
let sizeOfSockkAddr = MemoryLayout<sockaddr_in>.size
addr.sin_len = __uint8_t(sizeOfSockkAddr)
addr.sin_family = sa_family_t(AF_INET)
addr.sin_port = Int(OSHostByteOrder()) == OSLittleEndian ? _OSSwapInt16(port) : port
addr.sin_addr = in_addr(s_addr: inet_addr("0.0.0.0"))
addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
var bind_addr = sockaddr()
memcpy(&bind_addr, &addr, Int(sizeOfSockkAddr))
if Darwin.bind(socketFileDescriptor, &bind_addr, socklen_t(sizeOfSockkAddr)) == -1 {
let details = descriptionOfLastError()
release(socket: socketFileDescriptor)
return (false, "\(port), BindFailed, \(details)")
}
if listen(socketFileDescriptor, SOMAXCONN ) == -1 {
let details = descriptionOfLastError()
release(socket: socketFileDescriptor)
return (false, "\(port), ListenFailed, \(details)")
}
release(socket: socketFileDescriptor)
return (true, "\(port) is free for use")
}
static func release(socket: Int32) {
Darwin.shutdown(socket, SHUT_RDWR)
close(socket)
}
static func descriptionOfLastError() -> String {
return String(cString: UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
}
}
//
// RouterRunner.swift
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
import Foundation
class RouterRunner: NSObject, I2PSubprocess {
var subprocessPath: String?
var arguments: String?
var timeWhenStarted: Date?
var currentRunningProcess: Subprocess?
var currentProcessResults: ExecutionResult?
func findJava() {
self.subprocessPath = RouterProcessStatus.knownJavaBinPath
}
let defaultStartupFlags:[String] = [
"-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"
]
private func subInit(cmdPath: String?, cmdArgs: String?) {
// Use this as common init
self.subprocessPath = cmdPath
self.arguments = cmdArgs
if (self.arguments?.isEmpty)! {
self.arguments = Optional.some(defaultStartupFlags.joined(separator: " "))
};
var newArgs:[String] = ["-c ",
self.subprocessPath!,
" ",
self.arguments!,
]
self.currentRunningProcess = Optional.some(Subprocess.init(executablePath: "/bin/sh", arguments: newArgs))
}
init(cmdPath: String?, _ cmdArgs: String? = Optional.none) {
super.init()
self.subInit(cmdPath: cmdPath, cmdArgs: cmdArgs)
}
init(coder: NSCoder) {
super.init()
self.subInit(cmdPath: Optional.none, cmdArgs: Optional.none)
}
func execute() {
if (self.currentRunningProcess != Optional.none!) {
print("Already executing! Process ", self.toString())
}
self.timeWhenStarted = Date()
RouterProcessStatus.routerStartedAt = self.timeWhenStarted
self.currentProcessResults = self.currentRunningProcess?.execute(captureOutput: true)
}
}
//
// AppleStuffExceptionHandler.h
// I2PLauncher
//
// Created by Mikal Villa on 17/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSException* __nullable AppleStuffExecuteWithPossibleExceptionInBlock(dispatch_block_t _Nonnull block);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment