blob: 395a22bbd1a49ca565938b706227651da50f9055 [file] [log] [blame]
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * 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.
tkchin@webrtc.org87776a82014-12-09 19:32:35 +00009 */
10
11#import "ARDWebSocketChannel.h"
12
tkchinc3f46a92015-07-23 12:50:55 -070013#import "RTCLogging.h"
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000014#import "SRWebSocket.h"
15
tkchinc3f46a92015-07-23 12:50:55 -070016#import "ARDUtilities.h"
17
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000018// TODO(tkchin): move these to a configuration object.
19static NSString const *kARDWSSMessageErrorKey = @"error";
20static NSString const *kARDWSSMessagePayloadKey = @"msg";
21
22@interface ARDWebSocketChannel () <SRWebSocketDelegate>
23@end
24
25@implementation ARDWebSocketChannel {
26 NSURL *_url;
27 NSURL *_restURL;
28 SRWebSocket *_socket;
29}
30
31@synthesize delegate = _delegate;
32@synthesize state = _state;
33@synthesize roomId = _roomId;
34@synthesize clientId = _clientId;
35
36- (instancetype)initWithURL:(NSURL *)url
37 restURL:(NSURL *)restURL
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000038 delegate:(id<ARDSignalingChannelDelegate>)delegate {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000039 if (self = [super init]) {
40 _url = url;
41 _restURL = restURL;
42 _delegate = delegate;
43 _socket = [[SRWebSocket alloc] initWithURL:url];
44 _socket.delegate = self;
tkchinc3f46a92015-07-23 12:50:55 -070045 RTCLog(@"Opening WebSocket.");
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000046 [_socket open];
47 }
48 return self;
49}
50
51- (void)dealloc {
52 [self disconnect];
53}
54
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000055- (void)setState:(ARDSignalingChannelState)state {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000056 if (_state == state) {
57 return;
58 }
59 _state = state;
60 [_delegate channel:self didChangeState:_state];
61}
62
63- (void)registerForRoomId:(NSString *)roomId
64 clientId:(NSString *)clientId {
65 NSParameterAssert(roomId.length);
66 NSParameterAssert(clientId.length);
67 _roomId = roomId;
68 _clientId = clientId;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000069 if (_state == kARDSignalingChannelStateOpen) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000070 [self registerWithCollider];
71 }
72}
73
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000074- (void)sendMessage:(ARDSignalingMessage *)message {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000075 NSParameterAssert(_clientId.length);
76 NSParameterAssert(_roomId.length);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +000077 NSData *data = [message JSONData];
78 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000079 NSString *payload =
80 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
81 NSDictionary *message = @{
82 @"cmd": @"send",
83 @"msg": payload,
84 };
85 NSData *messageJSONObject =
86 [NSJSONSerialization dataWithJSONObject:message
87 options:NSJSONWritingPrettyPrinted
88 error:nil];
89 NSString *messageString =
90 [[NSString alloc] initWithData:messageJSONObject
91 encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070092 RTCLog(@"C->WSS: %@", messageString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000093 [_socket send:messageString];
94 } else {
95 NSString *dataString =
96 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -070097 RTCLog(@"C->WSS POST: %@", dataString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000098 NSString *urlString =
99 [NSString stringWithFormat:@"%@/%@/%@",
100 [_restURL absoluteString], _roomId, _clientId];
101 NSURL *url = [NSURL URLWithString:urlString];
102 [NSURLConnection sendAsyncPostToURL:url
103 withData:data
104 completionHandler:nil];
105 }
106}
107
108- (void)disconnect {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000109 if (_state == kARDSignalingChannelStateClosed ||
110 _state == kARDSignalingChannelStateError) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000111 return;
112 }
113 [_socket close];
tkchinc3f46a92015-07-23 12:50:55 -0700114 RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000115 NSString *urlString =
116 [NSString stringWithFormat:@"%@/%@/%@",
117 [_restURL absoluteString], _roomId, _clientId];
118 NSURL *url = [NSURL URLWithString:urlString];
119 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
120 request.HTTPMethod = @"DELETE";
121 request.HTTPBody = nil;
122 [NSURLConnection sendAsyncRequest:request completionHandler:nil];
123}
124
125#pragma mark - SRWebSocketDelegate
126
127- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
tkchinc3f46a92015-07-23 12:50:55 -0700128 RTCLog(@"WebSocket connection opened.");
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000129 self.state = kARDSignalingChannelStateOpen;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000130 if (_roomId.length && _clientId.length) {
131 [self registerWithCollider];
132 }
133}
134
135- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
136 NSString *messageString = message;
137 NSData *messageData = [messageString dataUsingEncoding:NSUTF8StringEncoding];
138 id jsonObject = [NSJSONSerialization JSONObjectWithData:messageData
139 options:0
140 error:nil];
141 if (![jsonObject isKindOfClass:[NSDictionary class]]) {
tkchinc3f46a92015-07-23 12:50:55 -0700142 RTCLogError(@"Unexpected message: %@", jsonObject);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000143 return;
144 }
145 NSDictionary *wssMessage = jsonObject;
146 NSString *errorString = wssMessage[kARDWSSMessageErrorKey];
147 if (errorString.length) {
tkchinc3f46a92015-07-23 12:50:55 -0700148 RTCLogError(@"WSS error: %@", errorString);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000149 return;
150 }
151 NSString *payload = wssMessage[kARDWSSMessagePayloadKey];
152 ARDSignalingMessage *signalingMessage =
153 [ARDSignalingMessage messageFromJSONString:payload];
tkchinc3f46a92015-07-23 12:50:55 -0700154 RTCLog(@"WSS->C: %@", payload);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000155 [_delegate channel:self didReceiveMessage:signalingMessage];
156}
157
158- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
tkchinc3f46a92015-07-23 12:50:55 -0700159 RTCLogError(@"WebSocket error: %@", error);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000160 self.state = kARDSignalingChannelStateError;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000161}
162
163- (void)webSocket:(SRWebSocket *)webSocket
164 didCloseWithCode:(NSInteger)code
165 reason:(NSString *)reason
166 wasClean:(BOOL)wasClean {
tkchinc3f46a92015-07-23 12:50:55 -0700167 RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000168 (long)code, reason, wasClean);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000169 NSParameterAssert(_state != kARDSignalingChannelStateError);
170 self.state = kARDSignalingChannelStateClosed;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000171}
172
173#pragma mark - Private
174
175- (void)registerWithCollider {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000176 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000177 return;
178 }
179 NSParameterAssert(_roomId.length);
180 NSParameterAssert(_clientId.length);
181 NSDictionary *registerMessage = @{
182 @"cmd": @"register",
183 @"roomid" : _roomId,
184 @"clientid" : _clientId,
185 };
186 NSData *message =
187 [NSJSONSerialization dataWithJSONObject:registerMessage
188 options:NSJSONWritingPrettyPrinted
189 error:nil];
190 NSString *messageString =
191 [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 12:50:55 -0700192 RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000193 // Registration can fail if server rejects it. For example, if the room is
194 // full.
195 [_socket send:messageString];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000196 self.state = kARDSignalingChannelStateRegistered;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000197}
198
199@end