replace ServiceCom with objc class

This commit is contained in:
Grant Limberg 2016-08-06 19:45:58 -07:00
parent a0db48571d
commit b51d68a419
9 changed files with 323 additions and 234 deletions

View File

@ -14,7 +14,6 @@
932D47361D1CDC9B004BCFE2 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 932D47341D1CDC9B004BCFE2 /* AboutViewController.swift */; };
932D47371D1CDC9B004BCFE2 /* AboutViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 932D47351D1CDC9B004BCFE2 /* AboutViewController.xib */; };
932D473A1D220D63004BCFE2 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 932D47391D220D63004BCFE2 /* LaunchAtLoginController.m */; };
9330F1351CEAB4C400687EC8 /* ServiceCom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9330F1341CEAB4C400687EC8 /* ServiceCom.swift */; };
9330F13B1CF534E500687EC8 /* NetworkInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9330F13A1CF534E500687EC8 /* NetworkInfoCell.swift */; };
93326BDC1CE7C816005CA2AC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93326BDB1CE7C816005CA2AC /* AppDelegate.swift */; };
93326BDE1CE7C816005CA2AC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 93326BDD1CE7C816005CA2AC /* Assets.xcassets */; };
@ -39,7 +38,6 @@
932D47351D1CDC9B004BCFE2 /* AboutViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutViewController.xib; sourceTree = "<group>"; };
932D47381D220D63004BCFE2 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = "<group>"; };
932D47391D220D63004BCFE2 /* LaunchAtLoginController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = "<group>"; };
9330F1341CEAB4C400687EC8 /* ServiceCom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceCom.swift; sourceTree = "<group>"; };
9330F13A1CF534E500687EC8 /* NetworkInfoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkInfoCell.swift; sourceTree = "<group>"; };
93326BD81CE7C816005CA2AC /* ZeroTier One.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ZeroTier One.app"; sourceTree = BUILT_PRODUCTS_DIR; };
93326BDB1CE7C816005CA2AC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -97,7 +95,6 @@
93326BE81CE7D9B9005CA2AC /* JoinNetworkViewController.swift */,
9330F13A1CF534E500687EC8 /* NetworkInfoCell.swift */,
93326BEC1CE7DA30005CA2AC /* ShowNetworksViewController.swift */,
9330F1341CEAB4C400687EC8 /* ServiceCom.swift */,
93326BDD1CE7C816005CA2AC /* Assets.xcassets */,
93326BDF1CE7C816005CA2AC /* MainMenu.xib */,
93326BE21CE7C816005CA2AC /* Info.plist */,
@ -212,7 +209,6 @@
93D1675F1D54191C00330C99 /* NodeStatus.m in Sources */,
932D47361D1CDC9B004BCFE2 /* AboutViewController.swift in Sources */,
93D167661D54308200330C99 /* Network.m in Sources */,
9330F1351CEAB4C400687EC8 /* ServiceCom.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -244,10 +244,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
let id = String(network.nwid, radix: 16)
if network.connected {
ServiceCom.sharedInstance.leaveNetwork(id)
ServiceCom.sharedInstance().leaveNetwork(id)
}
else {
ServiceCom.sharedInstance.joinNetwork(id)
ServiceCom.sharedInstance().joinNetwork(id, allowManaged: true, allowGlobal: false, allowDefault: false)
}
}

View File

@ -69,7 +69,7 @@ class JoinNetworkViewController: NSViewController, NSComboBoxDelegate, NSComboBo
@IBAction func onJoinClicked(sender: AnyObject?) {
let networkString = network.stringValue
ServiceCom.sharedInstance.joinNetwork(networkString,
ServiceCom.sharedInstance().joinNetwork(networkString,
allowManaged: allowManagedCheckBox.state == NSOnState,
allowGlobal: allowGlobalCheckBox.state == NSOnState,
allowDefault: allowDefaultCheckBox.state == NSOnState)

View File

@ -56,14 +56,14 @@ class NetworkInfoCell: NSTableCellView {
}
func joinNetwork(nwid: String) {
ServiceCom.sharedInstance.joinNetwork(nwid,
ServiceCom.sharedInstance().joinNetwork(nwid,
allowManaged: allowManaged.state == NSOnState,
allowGlobal: allowGlobal.state == NSOnState,
allowDefault: !Network.defaultRouteExists(parent.networkList) && (allowDefault.state == NSOnState))
}
func leaveNetwork(nwid: String) {
ServiceCom.sharedInstance.leaveNetwork(nwid)
ServiceCom.sharedInstance().leaveNetwork(nwid)
}
@IBAction func onAllowStatusChanged(sender: NSButton) {

View File

@ -63,7 +63,7 @@ class NetworkMonitor: NSObject {
}
}
ServiceCom.sharedInstance.getNetworkList() { (networkList) -> Void in
ServiceCom.sharedInstance().getNetworklist() { (networkList) -> Void in
self.receivedNetworks = networkList
NSOperationQueue.mainQueue().addOperationWithBlock() { () -> Void in
@ -71,7 +71,7 @@ class NetworkMonitor: NSObject {
}
}
ServiceCom.sharedInstance.getNodeStatus() { nodeStatus -> Void in
ServiceCom.sharedInstance().getNodeStatus() { nodeStatus -> Void in
NSOperationQueue.mainQueue().addOperationWithBlock() { () -> Void in
let nc = NSNotificationCenter.defaultCenter()

28
ZeroTier One/ServiceCom.h Normal file
View File

@ -0,0 +1,28 @@
//
// ServiceCom.h
// ZeroTier One
//
// Created by Grant Limberg on 8/4/16.
// Copyright © 2016 ZeroTier, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class NodeStatus;
@class Network;
@interface ServiceCom : NSObject
{
NSString *baseURL;
NSURLSession *session;
}
+ (ServiceCom*)sharedInstance;
- (id)init;
- (void)getNetworklist:(void (^)(NSArray<Network*>*))completionHandler;
- (void)getNodeStatus:(void (^)(NodeStatus*))completionHandler;
- (void)joinNetwork:(NSString*)networkId allowManaged:(BOOL)allowManaged allowGlobal:(BOOL)allowGlobal allowDefault:(BOOL)allowDefault;
- (void)leaveNetwork:(NSString*)networkId;
@end

286
ZeroTier One/ServiceCom.m Normal file
View File

@ -0,0 +1,286 @@
//
// ServiceCom.m
// ZeroTier One
//
// Created by Grant Limberg on 8/4/16.
// Copyright © 2016 ZeroTier, Inc. All rights reserved.
//
#import "ServiceCom.h"
#import "AuthtokenCopy.h"
#import "Network.h"
#import "NodeStatus.h"
@interface ServiceCom (Private)
- (NSString*)key;
@end
@implementation ServiceCom
+ (ServiceCom*)sharedInstance {
static ServiceCom *sc = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sc = [[ServiceCom alloc] init];
});
return sc;
}
- (id)init
{
self = [super init];
if(self) {
baseURL = @"http://localhost:9993";
session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
}
return self;
}
- (NSString*)key
{
static NSString *k = nil;
if (k == nil) {
NSError *error = nil;
NSURL *appSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
if (error) {
NSLog(@"Error: %@", error);
return @"";
}
appSupportDir = [[appSupportDir URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"];
NSURL *authtokenURL = [appSupportDir URLByAppendingPathComponent:@"authtoken.secret"];
if ([[NSFileManager defaultManager] fileExistsAtPath:[authtokenURL path]]) {
k = [NSString stringWithContentsOfURL:authtokenURL
encoding:NSUTF8StringEncoding
error:&error];
if (error) {
NSLog(@"Error: %@", error);
k = nil;
return @"";
}
}
else {
[[NSFileManager defaultManager] createDirectoryAtURL:appSupportDir
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error) {
NSLog(@"Error: %@", error);
k = nil;
return @"";
}
AuthorizationRef authRef;
OSStatus status = AuthorizationCreate(nil, nil, kAuthorizationFlagDefaults, &authRef);
if (status != errAuthorizationSuccess) {
NSLog(@"Authorization Failed! %d", status);
return @"";
}
AuthorizationItem authItem;
authItem.name = kAuthorizationRightExecute;
authItem.valueLength = 0;
authItem.flags = 0;
AuthorizationRights authRights;
authRights.count = 1;
authRights.items = &authItem;
AuthorizationFlags authFlags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
status = AuthorizationCopyRights(authRef, &authRights, nil, authFlags, nil);
if (status != errAuthorizationSuccess) {
NSLog(@"Authorization Failed! %d", status);
return @"";
}
NSString *localKey = getAdminAuthToken(authRef);
AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
if (localKey != nil && [localKey lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > 0) {
k = localKey;
[localKey writeToURL:authtokenURL
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
if (error) {
NSLog(@"Error writing token to disk: %@", error);
}
}
}
}
if (k == nil) {
return @"";
}
return k;
}
- (void)getNetworklist:(void (^)(NSArray*))completionHandler
{
NSString *urlString = [[baseURL stringByAppendingString:@"/network?auth="] stringByAppendingString:[self key]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionDataTask *task =
[session dataTaskWithURL:url
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"Error: %@", error);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSInteger status = [httpResponse statusCode];
NSError *err;
if (status == 200) {
NSArray *json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&err];
if (err) {
NSLog(@"Error fetching network list: %@", err);
return;
}
NSMutableArray<Network*> *networks = [[NSMutableArray<Network*> alloc] init];
for(NSDictionary *dict in json) {
[networks addObject:[[Network alloc] initWithJsonData:dict]];
}
completionHandler(networks);
}
}];
[task resume];
}
- (void)getNodeStatus:(void (^)(NodeStatus*))completionHandler
{
NSString *urlString = [[baseURL stringByAppendingString:@"/status?auth="] stringByAppendingString:[self key]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionDataTask *task =
[session dataTaskWithURL:url
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(error) {
NSLog(@"Error: %@", error);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSInteger status = [httpResponse statusCode];
NSError *err;
if(status == 200) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&err];
if(err) {
NSLog(@"Error fetching node status: %@", err);
return;
}
NodeStatus *status = [[NodeStatus alloc] initWithJsonData:json];
completionHandler(status);
}
}];
[task resume];
}
- (void)joinNetwork:(NSString*)networkId allowManaged:(BOOL)allowManaged allowGlobal:(BOOL)allowGlobal allowDefault:(BOOL)allowDefault
{
NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"] stringByAppendingString:networkId] stringByAppendingString:@"?auth="] stringByAppendingString:[self key]];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableDictionary *jsonDict = [NSMutableDictionary dictionary];
[jsonDict setObject:[NSNumber numberWithBool:allowManaged] forKey:@"allowManaged"];
[jsonDict setObject:[NSNumber numberWithBool:allowGlobal] forKey:@"allowGlobal"];
[jsonDict setObject:[NSNumber numberWithBool:allowDefault] forKey:@"allowDefault"];
NSError *err = nil;
NSData *json = [NSJSONSerialization dataWithJSONObject:jsonDict
options:0
error:&err];
if(err) {
NSLog(@"Error creating json data: %@", err);
return;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = json;
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSURLSessionDataTask *task =
[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(error) {
NSLog(@"Error posting join request: %@", error);
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSInteger status = [httpResponse statusCode];
if(status == 200) {
NSLog(@"join ok");
}
else {
NSLog(@"join error: %ld", (long)status);
}
}];
[task resume];
}
- (void)leaveNetwork:(NSString*)networkId
{
NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"] stringByAppendingString:networkId] stringByAppendingString:@"?auth="] stringByAppendingString:[self key]];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"DELETE";
NSURLSessionDataTask *task =
[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(error) {
NSLog(@"Error posting delete request: %@", error);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSInteger status = httpResponse.statusCode;
if(status == 200) {
NSLog(@"leave ok");
}
else {
NSLog(@"leave error: %ld", status);
}
}];
[task resume];
}
@end

View File

@ -1,222 +0,0 @@
//
// ServiceCom.swift
// ZeroTier One
//
// Created by Grant Limberg on 5/16/16.
// Copyright © 2016 ZeroTier, Inc. All rights reserved.
//
import Cocoa
class ServiceCom: NSObject {
static let sharedInstance = ServiceCom()
let baseURL = "http://localhost:9993"
let session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration())
private override init() {
super.init()
}
private func getKey() -> String {
struct Holder {
static var key: String? = nil
}
if Holder.key == nil {
do {
// Check the user's ZeroTier application support directory. If
// authtoken.secret exists, use it.
var appSupportDir = try NSFileManager.defaultManager().URLForDirectory(.ApplicationSupportDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
appSupportDir = appSupportDir.URLByAppendingPathComponent("ZeroTier")
appSupportDir = appSupportDir.URLByAppendingPathComponent("One")
let authtokenURL = appSupportDir.URLByAppendingPathComponent("authtoken.secret")
if NSFileManager.defaultManager().fileExistsAtPath(authtokenURL.path!) {
Holder.key = try String(contentsOfURL: authtokenURL)
}
else {
try NSFileManager.defaultManager().createDirectoryAtURL(appSupportDir, withIntermediateDirectories: true, attributes: nil)
var authRef: AuthorizationRef = nil
var status = AuthorizationCreate(nil, nil, .Defaults, &authRef)
if status != errAuthorizationSuccess {
NSLog("Authorization Failed! \(status)")
return ""
}
var authItem = AuthorizationItem(name: kAuthorizationRightExecute, valueLength: 0, value: nil, flags: 0)
var authRights = AuthorizationRights(count: 1, items: &authItem)
let authFlags: AuthorizationFlags = [.Defaults, .InteractionAllowed, .PreAuthorize, .ExtendRights]
status = AuthorizationCopyRights(authRef, &authRights, nil, authFlags, nil)
if status != errAuthorizationSuccess {
NSLog("Authorization Failed! \(status)")
return ""
}
let localKey = getAdminAuthToken(authRef)
AuthorizationFree(authRef, .DestroyRights)
if localKey != nil && localKey.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0 {
NSLog("\(localKey)")
Holder.key = localKey
try localKey.writeToURL(authtokenURL, atomically: true, encoding: NSUTF8StringEncoding)
}
}
}
catch {
NSLog("Error getting app support dir: \(error)")
Holder.key = nil
}
}
if let k = Holder.key {
return k
}
else {
return ""
}
}
func getNetworkList(completionHandler: ([Network]) -> Void) {
let urlString = baseURL + "/network?auth=\(getKey())"
let url = NSURL(string: urlString)
if let u = url {
let task = session.dataTaskWithURL(u) { (data, response, error) in
if error != nil{
NSLog("\(error)")
return
}
let httpResponse = response as! NSHTTPURLResponse
let status = httpResponse.statusCode
if status == 200 {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as! [[String: AnyObject]]
var networks = [Network]()
for jobj in json {
networks.append(Network(jsonData: jobj))
}
completionHandler(networks)
}
catch {
}
}
}
task.resume()
}
else {
print("bad URL")
}
}
func getNodeStatus(completionHandler: (NodeStatus -> Void)) {
let urlString = baseURL + "/status?auth=\(getKey())"
if let u = NSURL(string: urlString) {
let task = session.dataTaskWithURL(u) { (data, response, error) in
if error != nil{
NSLog("\(error)")
return
}
let httpResponse = response as! NSHTTPURLResponse
let status = httpResponse.statusCode
if status == 200 {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as! [String: AnyObject]
let status = NodeStatus(jsonData: json)
completionHandler(status)
}
catch {
}
}
}
task.resume()
}
else {
NSLog("bad URL")
}
}
func joinNetwork(network: String, allowManaged: Bool = true, allowGlobal: Bool = false, allowDefault: Bool = false) {
let urlString = baseURL + "/network/\(network)?auth=\(getKey())"
let url = NSURL(string: urlString)
var jsonDict = [String: AnyObject]()
jsonDict["allowManaged"] = NSNumber(bool: allowManaged)
jsonDict["allowGlobal"] = NSNumber(bool: allowGlobal)
jsonDict["allowDefault"] = NSNumber(bool: allowDefault)
do {
let json = try NSJSONSerialization.dataWithJSONObject(jsonDict, options: NSJSONWritingOptions())
if let u = url {
let request = NSMutableURLRequest(URL: u)
request.HTTPMethod = "POST"
request.HTTPBody = json
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = session.dataTaskWithRequest(request) { (data, response, error) in
let httpResponse = response as! NSHTTPURLResponse
let status = httpResponse.statusCode
if status == 200 {
NSLog("join ok")
}
else {
NSLog("join error: \(status)")
}
}
task.resume()
}
}
catch {
NSLog("\(error)")
}
}
func leaveNetwork(network: String) {
let urlString = baseURL + "/network/\(network)?auth=\(getKey())"
if let u = NSURL(string: urlString) {
let request = NSMutableURLRequest(URL: u)
request.HTTPMethod = "DELETE"
let task = session.dataTaskWithRequest(request) { (data, response, error) in
let httpResponse = response as! NSHTTPURLResponse
let status = httpResponse.statusCode
if status == 200 {
NSLog("leave ok")
}
else {
NSLog("leave error: \(status)")
}
}
task.resume()
}
}
}

View File

@ -5,4 +5,5 @@
#import "AuthtokenCopy.h"
#import "LaunchAtLoginController.h"
#import "NodeStatus.h"
#import "Network.h"
#import "Network.h"
#import "ServiceCom.h"