1/* 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#import "ARDAppEngineClient.h" 12 13#import <WebRTC/RTCLogging.h> 14 15#import "ARDJoinResponse.h" 16#import "ARDMessageResponse.h" 17#import "ARDSignalingMessage.h" 18#import "ARDUtilities.h" 19 20// TODO(tkchin): move these to a configuration object. 21static NSString * const kARDRoomServerHostUrl = 22 @"https://appr.tc"; 23static NSString * const kARDRoomServerJoinFormat = 24 @"https://appr.tc/join/%@"; 25static NSString * const kARDRoomServerJoinFormatLoopback = 26 @"https://appr.tc/join/%@?debug=loopback"; 27static NSString * const kARDRoomServerMessageFormat = 28 @"https://appr.tc/message/%@/%@"; 29static NSString * const kARDRoomServerLeaveFormat = 30 @"https://appr.tc/leave/%@/%@"; 31 32static NSString * const kARDAppEngineClientErrorDomain = @"ARDAppEngineClient"; 33static NSInteger const kARDAppEngineClientErrorBadResponse = -1; 34 35@implementation ARDAppEngineClient 36 37#pragma mark - ARDRoomServerClient 38 39- (void)joinRoomWithRoomId:(NSString *)roomId 40 isLoopback:(BOOL)isLoopback 41 completionHandler:(void (^)(ARDJoinResponse *response, 42 NSError *error))completionHandler { 43 NSParameterAssert(roomId.length); 44 45 NSString *urlString = nil; 46 if (isLoopback) { 47 urlString = 48 [NSString stringWithFormat:kARDRoomServerJoinFormatLoopback, roomId]; 49 } else { 50 urlString = 51 [NSString stringWithFormat:kARDRoomServerJoinFormat, roomId]; 52 } 53 54 NSURL *roomURL = [NSURL URLWithString:urlString]; 55 RTCLog(@"Joining room:%@ on room server.", roomId); 56 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL]; 57 request.HTTPMethod = @"POST"; 58 [NSURLConnection sendAsyncRequest:request 59 completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 60 if (error) { 61 if (completionHandler) { 62 completionHandler(nil, error); 63 } 64 return; 65 } 66 ARDJoinResponse *joinResponse = [ARDJoinResponse responseFromJSONData:data]; 67 if (!joinResponse) { 68 if (completionHandler) { 69 NSError *error = [[self class] badResponseError]; 70 completionHandler(nil, error); 71 } 72 return; 73 } 74 if (completionHandler) { 75 completionHandler(joinResponse, nil); 76 } 77 }]; 78} 79 80- (void)sendMessage:(ARDSignalingMessage *)message 81 forRoomId:(NSString *)roomId 82 clientId:(NSString *)clientId 83 completionHandler:(void (^)(ARDMessageResponse *response, 84 NSError *error))completionHandler { 85 NSParameterAssert(message); 86 NSParameterAssert(roomId.length); 87 NSParameterAssert(clientId.length); 88 89 NSData *data = [message JSONData]; 90 NSString *urlString = 91 [NSString stringWithFormat: 92 kARDRoomServerMessageFormat, roomId, clientId]; 93 NSURL *url = [NSURL URLWithString:urlString]; 94 RTCLog(@"C->RS POST: %@", message); 95 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 96 request.HTTPMethod = @"POST"; 97 request.HTTPBody = data; 98 [NSURLConnection sendAsyncRequest:request 99 completionHandler:^(NSURLResponse *response, 100 NSData *data, 101 NSError *error) { 102 if (error) { 103 if (completionHandler) { 104 completionHandler(nil, error); 105 } 106 return; 107 } 108 ARDMessageResponse *messageResponse = 109 [ARDMessageResponse responseFromJSONData:data]; 110 if (!messageResponse) { 111 if (completionHandler) { 112 NSError *error = [[self class] badResponseError]; 113 completionHandler(nil, error); 114 } 115 return; 116 } 117 if (completionHandler) { 118 completionHandler(messageResponse, nil); 119 } 120 }]; 121} 122 123- (void)leaveRoomWithRoomId:(NSString *)roomId 124 clientId:(NSString *)clientId 125 completionHandler:(void (^)(NSError *error))completionHandler { 126 NSParameterAssert(roomId.length); 127 NSParameterAssert(clientId.length); 128 129 NSString *urlString = 130 [NSString stringWithFormat:kARDRoomServerLeaveFormat, roomId, clientId]; 131 NSURL *url = [NSURL URLWithString:urlString]; 132 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 133 request.HTTPMethod = @"POST"; 134 135 RTCLog(@"C->RS: BYE"); 136 __block NSError *error = nil; 137 138 // We want a synchronous request so that we know that we've left the room on 139 // room server before we do any further work. 140 dispatch_semaphore_t sem = dispatch_semaphore_create(0); 141 [NSURLConnection sendAsyncRequest:request 142 completionHandler:^(NSURLResponse *response, NSData *data, NSError *e) { 143 if (e) { 144 error = e; 145 } 146 dispatch_semaphore_signal(sem); 147 }]; 148 149 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 150 if (error) { 151 RTCLogError(@"Error leaving room %@ on room server: %@", roomId, error.localizedDescription); 152 if (completionHandler) { 153 completionHandler(error); 154 } 155 return; 156 } 157 RTCLog(@"Left room:%@ on room server.", roomId); 158 if (completionHandler) { 159 completionHandler(nil); 160 } 161} 162 163#pragma mark - Private 164 165+ (NSError *)badResponseError { 166 NSError *error = 167 [[NSError alloc] initWithDomain:kARDAppEngineClientErrorDomain 168 code:kARDAppEngineClientErrorBadResponse 169 userInfo:@{ 170 NSLocalizedDescriptionKey: @"Error parsing response.", 171 }]; 172 return error; 173} 174 175@end 176