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 "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://apprtc.appspot.com";
23static NSString * const kARDRoomServerJoinFormat =
24    @"https://apprtc.appspot.com/join/%@";
25static NSString * const kARDRoomServerJoinFormatLoopback =
26    @"https://apprtc.appspot.com/join/%@?debug=loopback";
27static NSString * const kARDRoomServerMessageFormat =
28    @"https://apprtc.appspot.com/message/%@/%@";
29static NSString * const kARDRoomServerLeaveFormat =
30    @"https://apprtc.appspot.com/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  __weak ARDAppEngineClient *weakSelf = self;
59  [NSURLConnection sendAsyncRequest:request
60                  completionHandler:^(NSURLResponse *response,
61                                      NSData *data,
62                                      NSError *error) {
63    ARDAppEngineClient *strongSelf = weakSelf;
64    if (error) {
65      if (completionHandler) {
66        completionHandler(nil, error);
67      }
68      return;
69    }
70    ARDJoinResponse *joinResponse =
71        [ARDJoinResponse responseFromJSONData:data];
72    if (!joinResponse) {
73      if (completionHandler) {
74        NSError *error = [[self class] badResponseError];
75        completionHandler(nil, error);
76      }
77      return;
78    }
79    if (completionHandler) {
80      completionHandler(joinResponse, nil);
81    }
82  }];
83}
84
85- (void)sendMessage:(ARDSignalingMessage *)message
86            forRoomId:(NSString *)roomId
87             clientId:(NSString *)clientId
88    completionHandler:(void (^)(ARDMessageResponse *response,
89                                NSError *error))completionHandler {
90  NSParameterAssert(message);
91  NSParameterAssert(roomId.length);
92  NSParameterAssert(clientId.length);
93
94  NSData *data = [message JSONData];
95  NSString *urlString =
96      [NSString stringWithFormat:
97          kARDRoomServerMessageFormat, roomId, clientId];
98  NSURL *url = [NSURL URLWithString:urlString];
99  RTCLog(@"C->RS POST: %@", message);
100  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
101  request.HTTPMethod = @"POST";
102  request.HTTPBody = data;
103  __weak ARDAppEngineClient *weakSelf = self;
104  [NSURLConnection sendAsyncRequest:request
105                  completionHandler:^(NSURLResponse *response,
106                                      NSData *data,
107                                      NSError *error) {
108    ARDAppEngineClient *strongSelf = weakSelf;
109    if (error) {
110      if (completionHandler) {
111        completionHandler(nil, error);
112      }
113      return;
114    }
115    ARDMessageResponse *messageResponse =
116        [ARDMessageResponse responseFromJSONData:data];
117    if (!messageResponse) {
118      if (completionHandler) {
119        NSError *error = [[self class] badResponseError];
120        completionHandler(nil, error);
121      }
122      return;
123    }
124    if (completionHandler) {
125      completionHandler(messageResponse, nil);
126    }
127  }];
128}
129
130- (void)leaveRoomWithRoomId:(NSString *)roomId
131                   clientId:(NSString *)clientId
132          completionHandler:(void (^)(NSError *error))completionHandler {
133  NSParameterAssert(roomId.length);
134  NSParameterAssert(clientId.length);
135
136  NSString *urlString =
137      [NSString stringWithFormat:kARDRoomServerLeaveFormat, roomId, clientId];
138  NSURL *url = [NSURL URLWithString:urlString];
139  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
140  request.HTTPMethod = @"POST";
141  NSURLResponse *response = nil;
142  NSError *error = nil;
143  // We want a synchronous request so that we know that we've left the room on
144  // room server before we do any further work.
145  RTCLog(@"C->RS: BYE");
146  [NSURLConnection sendSynchronousRequest:request
147                        returningResponse:&response
148                                    error:&error];
149  if (error) {
150    RTCLogError(@"Error leaving room %@ on room server: %@",
151          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