Refactored http communications to be more abstract and OOP

This commit is contained in:
Diego Waxemberg
2015-02-01 04:26:47 -05:00
parent 75d3f23f0a
commit 879f304a79
19 changed files with 460 additions and 240 deletions

View File

@@ -60,6 +60,10 @@
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; };
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD271A7C84ED00872C98 /* HttpResponse.m */; };
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */; };
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD361A7E02DB00872C98 /* HttpRequest.m */; };
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; };
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; };
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; };
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; };
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
@@ -253,6 +257,14 @@
FB9AFD271A7C84ED00872C98 /* HttpResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpResponse.m; sourceTree = "<group>"; };
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetRetriever.h; sourceTree = "<group>"; };
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetRetriever.m; sourceTree = "<group>"; };
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = "<group>"; };
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = "<group>"; };
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfoResponse.h; sourceTree = "<group>"; };
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerInfoResponse.m; sourceTree = "<group>"; };
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetResponse.h; sourceTree = "<group>"; };
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = "<group>"; };
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
@@ -677,8 +689,16 @@
children = (
FB89460F19F646E200339C8A /* HttpManager.h */,
FB89461019F646E200339C8A /* HttpManager.m */,
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */,
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */,
FB9AFD261A7C84ED00872C98 /* HttpResponse.h */,
FB9AFD271A7C84ED00872C98 /* HttpResponse.m */,
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */,
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */,
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */,
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */,
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */,
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */,
);
name = Http;
sourceTree = "<group>";
@@ -849,6 +869,7 @@
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
FBD3495E1A004412002D2A60 /* Settings.m in Sources */,
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */,
FB89463419F646E200339C8A /* Utils.m in Sources */,
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */,
FB89462F19F646E200339C8A /* Connection.m in Sources */,
@@ -870,12 +891,15 @@
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
FB290D0019B2C406004C83CF /* main.m in Sources */,
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */,
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -0,0 +1,16 @@
//
// AppAssetResponse.h
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "HttpResponse.h"
@interface AppAssetResponse : NSObject <Response>
@end

View File

@@ -0,0 +1,25 @@
//
// AppAssetResponse.m
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "AppAssetResponse.h"
@implementation AppAssetResponse
@synthesize data, statusCode, statusMessage;
- (void)populateWithData:(NSData *)imageData {
self.data = imageData;
self.statusMessage = @"App asset has no status message";
self.statusCode = -1;
}
- (UIImage*) getImage {
UIImage* appImage = [[UIImage alloc] initWithData:self.data];
return appImage;
}
@end

View File

@@ -9,7 +9,8 @@
#import "AppAssetRetriever.h"
#import "HttpManager.h"
#import "CryptoManager.h"
#import "HttpResponse.h"
#import "AppAssetResponse.h"
#import "HttpRequest.h"
@implementation AppAssetRetriever
static const double RETRY_DELAY = 1; // seconds
@@ -29,9 +30,10 @@ static const double RETRY_DELAY = 1; // seconds
}
if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
HttpResponse* appAssetResp = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:self.app.appId]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]];
appImage = [UIImage imageWithData:appAssetResp.responseData];
appImage = [UIImage imageWithData:appAssetResp.data];
self.app.appImage = appImage;
if (appImage != nil) {
@synchronized(self.cache) {

View File

@@ -0,0 +1,17 @@
//
// AppListResponse.h
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "HttpResponse.h"
@interface AppListResponse : NSObject <Response>
- (void)populateWithData:(NSData *)data;
- (NSArray*) getAppList;
- (BOOL) isStatusOk;
@end

View File

@@ -0,0 +1,106 @@
//
// AppListResponse.m
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "AppListResponse.h"
#import "App.h"
#import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse {
NSMutableArray* _appList;
}
@synthesize data, statusCode, statusMessage;
static const char* TAG_APP = "App";
static const char* TAG_APP_TITLE = "AppTitle";
static const char* TAG_APP_ID = "ID";
static const char* TAG_APP_IS_RUNNING = "IsRunning";
- (void)populateWithData:(NSData *)xml {
self.data = xml;
_appList = [[NSMutableArray alloc] init];
[self parseData];
}
- (void) parseData {
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
if (node == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return;
}
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
self.statusCode = status;
}
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
self.statusMessage = statusMsg;
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName;
NSString* appId;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_ID)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
}
appInfoNode = appInfoNode->next;
}
App* app = [[App alloc] init];
app.appName = appName;
app.appId = appId;
app.isRunning = appIsRunning;
[_appList addObject:app];
}
node = node->next;
}
xmlFreeDoc(docPtr);
}
- (NSArray*) getAppList {
return _appList;
}
- (BOOL) isStatusOk {
return self.statusCode == 200;
}
@end

View File

@@ -12,6 +12,7 @@
#import "Utils.h"
#import "DataManager.h"
#import "DiscoveryWorker.h"
#import "ServerInfoResponse.h"
@implementation DiscoveryManager {
NSMutableArray* _hostQueue;
@@ -39,7 +40,8 @@
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback {
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* serverInfoResponse = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]];
Host* host = nil;
if ([serverInfoResponse isStatusOk]) {

View File

@@ -9,6 +9,8 @@
#import "DiscoveryWorker.h"
#import "Utils.h"
#import "HttpManager.h"
#import "ServerInfoResponse.h"
#import "HttpRequest.h"
@implementation DiscoveryWorker {
Host* _host;
@@ -43,7 +45,9 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
BOOL receivedResponse = NO;
if (!self.cancelled && _host.localAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
_host.address = _host.localAddress;
@@ -52,7 +56,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
}
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc]init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
_host.address = _host.externalAddress;
@@ -62,7 +67,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
if (!self.cancelled && !receivedResponse && _host.address != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
if ([serverInfoResp isStatusOk]) {
[serverInfoResp populateHost:_host];
receivedResponse = YES;
@@ -70,7 +76,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
}
_host.online = receivedResponse;
if (receivedResponse) {
NSLog(@"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online);
NSLog(@"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online);
} else {
// If the host is not online, we do not know the pairstate
_host.pairState = PairStateUnknown;

View File

@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import "Host.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
@@ -25,8 +26,8 @@
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
- (NSURLRequest*) newQuitAppRequest;
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request;
- (void) executeRequest:(NSURLRequest*)request;
- (void) executeRequestSynchronously:(HttpRequest*)request;
- (void) executeRequest:(HttpRequest*)request;
@end

View File

@@ -7,6 +7,7 @@
//
#import "HttpManager.h"
#import "HttpRequest.h"
#import "CryptoManager.h"
#import "App.h"
@@ -46,18 +47,20 @@ static const NSString* PORT = @"47984";
return self;
}
- (HttpResponse*) executeRequestSynchronously:(NSURLRequest*)request {
- (void) executeRequestSynchronously:(HttpRequest*)request {
NSLog(@"Making Request: %@", request);
[_respData setLength:0];
dispatch_sync(dispatch_get_main_queue(), ^{
[NSURLConnection connectionWithRequest:request delegate:self];
[NSURLConnection connectionWithRequest:request.request delegate:self];
});
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
return [HttpResponse responseWithData:_requestResp];
if (request.response) {
[request.response populateWithData:_requestResp];
}
}
- (void) executeRequest:(NSURLRequest*)request {
[NSURLConnection connectionWithRequest:request delegate:self];
- (void) executeRequest:(HttpRequest*)request {
[NSURLConnection connectionWithRequest:request.request delegate:self];
}
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {

View File

@@ -0,0 +1,20 @@
//
// HttpRequest.h
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "HttpResponse.h"
@interface HttpRequest : NSObject
@property (nonatomic) id<Response> response;
@property (nonatomic) NSURLRequest* request;
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
@end

View File

@@ -0,0 +1,28 @@
//
// HttpRequest.m
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "HttpRequest.h"
#import "HttpResponse.h"
#import "HttpManager.h"
@implementation HttpRequest
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
request.response = response;
return request;
}
+ (HttpRequest*) requestWithUrlRequest:(NSURLRequest*)req {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
return request;
}
@end

View File

@@ -9,18 +9,25 @@
#import <Foundation/Foundation.h>
#import "Host.h"
@interface HttpResponse : NSObject
static NSString* TAG_STATUS_CODE = @"status_code";
static NSString* TAG_STATUS_MESSAGE = @"status_message";
@protocol Response <NSObject>
- (void) populateWithData:(NSData*)data;
@property (nonatomic) NSInteger statusCode;
@property (nonatomic) NSString* statusMessage;
@property (nonatomic) NSData* responseData;
+ (HttpResponse*) responseWithData:(NSData*)xml;
- (NSString*) parseStringTag:(NSString*)tag;
- (BOOL)parseIntTag:(NSString *)tag value:(NSInteger*)value;
- (BOOL) isStatusOk;
- (BOOL) populateHost:(Host*)host;
- (NSArray*) getAppList;
@property (nonatomic) NSData* data;
@end
@interface HttpResponse : NSObject <Response>
- (void) populateWithData:(NSData*)data;
- (void) parseData;
- (NSString*) getStringTag:(NSString*)tag;
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value;
- (BOOL) isStatusOk;
@end

View File

@@ -10,86 +10,22 @@
#import "App.h"
#import <libxml2/libxml/xmlreader.h>
@implementation HttpResponse
@implementation HttpResponse {
NSMutableDictionary* _elements;
}
@synthesize data, statusCode, statusMessage;
+ (HttpResponse*) responseWithData:(NSData*)xml {
HttpResponse* response = [[HttpResponse alloc] init];
response.responseData = xml;
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return response;
}
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
if (rootNode == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return response;
}
xmlChar* statusStr = xmlGetProp(rootNode, (const xmlChar*)"status_code");
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
response.statusCode = status;
}
xmlChar* statusMsgXml = xmlGetProp(rootNode, (const xmlChar*)"status_message");
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
response.statusMessage = statusMsg;
return response;
- (void) populateWithData:(NSData*)xml {
self.data = xml;
[self parseData];
}
- (NSString*)parseStringTag:(NSString *)tag {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return nil;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return nil;
}
// Skip the root node
node = node->children;
NSString* value;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
}
node = node->next;
}
//NSLog(@"xmlValue: %@", value);
xmlFreeDoc(docPtr);
return value;
- (NSString*) getStringTag:(NSString*)tag {
return [_elements objectForKey:tag];
}
- (BOOL)parseIntTag:(NSString *)tag value:(NSInteger*)value {
NSString* stringVal = [self parseStringTag:tag];
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value {
NSString* stringVal = [self getStringTag:tag];
if (stringVal != nil) {
*value = [stringVal integerValue];
return true;
@@ -102,121 +38,57 @@
return self.statusCode == 200;
}
- (BOOL) populateHost:(Host*)host {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
- (void) parseData {
_elements = [[NSMutableDictionary alloc] init];
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return false;
return;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
if (node == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return false;
return;
}
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
self.statusCode = status;
}
// Skip the root node
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
self.statusMessage = statusMsg;
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"hostname")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.name = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"ExternalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.externalAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"LocalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.localAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"uniqueid")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.uuid = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"mac")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.mac = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"PairStatus")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.pairState = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
xmlFree(nodeVal);
}
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
node = node->next;
}
xmlFreeDoc(docPtr);
return true;
}
- (NSArray*) getAppList {
xmlDocPtr docPtr = xmlParseMemory([self.responseData bytes], (int)[self.responseData length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return nil;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![self isStatusOk]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return nil;
}
// Skip the root node
node = node->children;
NSMutableArray* appList = [[NSMutableArray alloc] init];
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName;
NSString* appId;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
//NSLog(@"appInfoNode: %s", appInfoNode->name);
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"IsRunning")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
}
appInfoNode = appInfoNode->next;
}
App* app = [[App alloc] init];
app.appName = appName;
app.appId = appId;
app.isRunning = appIsRunning;
[appList addObject:app];
NSString* value;
if (nodeVal == NULL) {
value = @"";
} else {
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
}
NSString* key = [[NSString alloc] initWithCString:(const char*)node->name encoding:NSUTF8StringEncoding];
[_elements setObject:value forKey:key];
xmlFree(nodeVal);
node = node->next;
}
xmlFreeDoc(docPtr);
return appList;
}
@end

View File

@@ -10,6 +10,8 @@
#import "CryptoManager.h"
#import "Utils.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
#import "ServerInfoResponse.h"
#include <dispatch/dispatch.h>
@@ -28,15 +30,16 @@
}
- (void) main {
HttpResponse* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
if (serverInfo == nil) {
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]];
if (serverInfoResp == nil) {
[_callback pairFailed:@"Unable to connect to PC"];
return;
}
if ([serverInfo isStatusOk]) {
if (![[serverInfo parseStringTag:@"currentgame"] isEqual:@"0"]) {
if ([serverInfoResp isStatusOk]) {
if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
} else if (![[serverInfo parseStringTag:@"PairStatus"] isEqual:@"1"]) {
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair];
} else {
[_callback alreadyPaired];
@@ -50,18 +53,19 @@
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt);
[_callback showPIN:PIN];
HttpResponse* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
HttpResponse* pairResp = [[HttpResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt]]];
if (![self verifyResponseStatus:pairResp]) {
return;
}
NSInteger pairedStatus;
if (![pairResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing was declined by the target."];
return;
}
NSString* plainCert = [pairResp parseStringTag:@"plaincert"];
NSString* plainCert = [pairResp getStringTag:@"plaincert"];
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
@@ -69,17 +73,18 @@
NSData* randomChallenge = [Utils randomBytes:16];
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
HttpResponse* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
HttpResponse* challengeResp = [[HttpResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:challengeResp withUrlRequest:[_httpManager newChallengeRequest:encryptedChallenge]]];
if (![self verifyResponseStatus:challengeResp]) {
return;
}
if (![challengeResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #2 failed"];
return;
}
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp parseStringTag:@"challengeresponse"]];
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]];
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
@@ -89,50 +94,53 @@
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
HttpResponse* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
HttpResponse* secretResp = [[HttpResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:secretResp withUrlRequest:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]];
if (![self verifyResponseStatus:secretResp]) {
return;
}
if (![secretResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #3 failed"];
return;
}
NSData* serverSecretResp = [Utils hexToBytes:[secretResp parseStringTag:@"pairingsecret"]];
NSData* serverSecretResp = [Utils hexToBytes:[secretResp getStringTag:@"pairingsecret"]];
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Server certificate invalid"];
return;
}
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
if (![serverChallengeRespHash isEqual:serverResponse]) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Incorrect PIN"];
return;
}
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
HttpResponse* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
HttpResponse* clientSecretResp = [[HttpResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientSecretResp withUrlRequest:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]];
if (![self verifyResponseStatus:clientSecretResp]) {
return;
}
if (![clientSecretResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #4 failed"];
return;
}
HttpResponse* clientPairChallengeResp = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
HttpResponse* clientPairChallengeResp = [[HttpResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientPairChallengeResp withUrlRequest:[_httpManager newPairChallenge]]];
if (![self verifyResponseStatus:clientPairChallengeResp]) {
return;
}
if (![clientPairChallengeResp parseIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #5 failed"];
return;
}
@@ -141,11 +149,11 @@
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
if (resp == nil) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Network error occured."];
return false;
} else if (![resp isStatusOk]) {
[_httpManager executeRequest:[_httpManager newUnpairRequest]];
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:resp.statusMessage];
return false;
} else {

View File

@@ -0,0 +1,16 @@
//
// ServerInfoResponse.h
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "HttpResponse.h"
@interface ServerInfoResponse : HttpResponse <Response>
- (void) populateWithData:(NSData *)data;
- (void) populateHost:(Host*)host;
@end

View File

@@ -0,0 +1,55 @@
//
// ServerInfoResponse.m
// Limelight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved.
//
#import "ServerInfoResponse.h"
#import <libxml2/libxml/xmlreader.h>
@implementation ServerInfoResponse
@synthesize data, statusCode, statusMessage;
static NSString* TAG_HOSTNAME = @"hostname";
static NSString* TAG_EXTERNAL_IP = @"ExternalIP";
static NSString* TAG_LOCAL_IP = @"LocalIP";
static NSString* TAG_UNIQUE_ID = @"uniqueid";
static NSString* TAG_MAC_ADDRESS = @"mac";
static NSString* TAG_PAIR_STATUS = @"PairStatus";
- (void) populateWithData:(NSData *)xml {
self.data = xml;
[super parseData];
}
- (void) populateHost:(Host*)host {
NSString* hostname = [self getStringTag:TAG_HOSTNAME];
NSString* externalIp = [self getStringTag:TAG_EXTERNAL_IP];
NSString* localIp = [self getStringTag:TAG_LOCAL_IP];
NSString* uniqueId = [self getStringTag:TAG_UNIQUE_ID];
NSString* macAddress = [self getStringTag:TAG_MAC_ADDRESS];
NSString* pairStatus = [self getStringTag:TAG_PAIR_STATUS];
if (hostname) {
host.name = hostname;
}
if (externalIp) {
host.externalAddress = externalIp;
}
if (localIp) {
host.localAddress = localIp;
}
if (uniqueId) {
host.uuid = uniqueId;
}
if (macAddress) {
host.mac = macAddress;
}
if (pairStatus) {
host.pairState = [pairStatus isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
}
}
@end

View File

@@ -12,6 +12,9 @@
#import "Utils.h"
#import "OnScreenControls.h"
#import "StreamView.h"
#import "ServerInfoResponse.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
@implementation StreamManager {
StreamConfiguration* _config;
@@ -41,10 +44,11 @@
deviceName:@"roth"
cert:cert];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
NSString* currentGame = [serverInfoResp parseStringTag:@"currentgame"];
NSString* pairStatus = [serverInfoResp parseStringTag:@"PairStatus"];
NSString* currentClient = [serverInfoResp parseStringTag:@"CurrentClient"];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL) {
[_callbacks launchFailed:@"Failed to connect to PC"];
return;
@@ -102,14 +106,15 @@
}
- (BOOL) launchApp:(HttpManager*)hMan {
HttpResponse* launchResp = [hMan executeRequestSynchronously:
HttpResponse* launchResp = [[HttpResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest:
[hMan newLaunchRequest:_config.appID
width:_config.width
height:_config.height
refreshRate:_config.frameRate
rikey:[Utils bytesToHex:_config.riKey]
rikeyid:_config.riKeyId]];
NSString *gameSession = [launchResp parseStringTag:@"gamesession"];
rikeyid:_config.riKeyId]]];
NSString *gameSession = [launchResp getStringTag:@"gamesession"];
if (launchResp == NULL || ![launchResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to launch app"];
NSLog(@"Failed Launch Response: %@", launchResp.statusMessage);
@@ -124,10 +129,11 @@
}
- (BOOL) resumeApp:(HttpManager*)hMan {
HttpResponse* resumeResp = [hMan executeRequestSynchronously:
HttpResponse* resumeResp = [[HttpResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:resumeResp withUrlRequest:
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
riKeyId:_config.riKeyId]];
NSString* resume = [resumeResp parseStringTag:@"resume"];
riKeyId:_config.riKeyId]]];
NSString* resume = [resumeResp getStringTag:@"resume"];
if (resumeResp == NULL || ![resumeResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to resume app"];
NSLog(@"Failed Resume Response: %@", resumeResp.statusMessage);

View File

@@ -19,6 +19,8 @@
#import "DataManager.h"
#import "Settings.h"
#import "WakeOnLanManager.h"
#import "AppListResponse.h"
#import "ServerInfoResponse.h"
@implementation MainFrameViewController {
NSOperationQueue* _opQueue;
@@ -72,7 +74,9 @@ static StreamConfiguration* streamConfig;
[self.navigationController.navigationBar setNeedsLayout];
});
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
AppListResponse* appListResp = [[AppListResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
if (appListResp == nil || ![appListResp isStatusOk]) {
NSLog(@"Failed to get applist: %@", appListResp.statusMessage);
} else {
@@ -115,11 +119,13 @@ static StreamConfiguration* streamConfig;
_selectedHost = host;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
HttpResponse* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
NSLog(@"Failed to get server info: %@", serverInfoResp.statusMessage);
} else {
if ([[serverInfoResp parseStringTag:@"PairStatus"] isEqualToString:@"1"]) {
NSLog(@"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
NSLog(@"Already Paired");
[self alreadyPaired];
} else {
@@ -140,7 +146,7 @@ static StreamConfiguration* streamConfig;
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
[hMan executeRequestSynchronously:[hMan newUnpairRequest]];
[hMan executeRequest:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]];
});
}]];
} else {
@@ -250,7 +256,7 @@ static StreamConfiguration* streamConfig;
NSLog(@"Quitting application: %@", currentApp.appName);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
[hMan executeRequestSynchronously:[hMan newQuitAppRequest]];
[hMan executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[hMan newQuitAppRequest]]];
// TODO: handle failure to quit app
currentApp.isRunning = NO;