Skip to content

Commit 4d472cc

Browse files
committed
Add support for Flutter Web.
1 parent b0ff355 commit 4d472cc

File tree

5 files changed

+183
-52
lines changed

5 files changed

+183
-52
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
--------------------------------------------
33
[0.2.0] - 2019.12.18
44

5+
* Add support for Flutter Web.
6+
7+
[0.2.0] - 2019.12.18
8+
59
* Update
610

711
[0.1.0] - 2019.03.22
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import 'dart:io';
2+
import 'dart:math';
3+
import 'dart:convert';
4+
import 'dart:async';
5+
import '../logger.dart';
6+
7+
typedef void OnMessageCallback(dynamic msg);
8+
typedef void OnCloseCallback(int code, String reason);
9+
typedef void OnOpenCallback();
10+
11+
class WebSocketImpl {
12+
String _url;
13+
var _socket;
14+
final logger = Logger('Logger::Dart::WebSocket');
15+
OnOpenCallback onOpen;
16+
OnMessageCallback onMessage;
17+
OnCloseCallback onClose;
18+
WebSocketImpl(this._url);
19+
20+
connect({Object protocols, Object headers}) async {
21+
logger.debug('connect $_url, $headers, $protocols');
22+
try {
23+
_socket =
24+
await WebSocket.connect(_url, protocols: protocols, headers: headers);
25+
26+
/// Allow self-signed certificate, for test only.
27+
/// var parsed_url = Grammar.parse(this._url, 'absoluteURI');
28+
/// _socket = await _connectForBadCertificate(parsed_url.scheme, parsed_url.host, parsed_url.port);
29+
30+
this?.onOpen();
31+
_socket.listen((data) {
32+
this?.onMessage(data);
33+
}, onDone: () {
34+
this?.onClose(_socket.closeCode, _socket.closeReason);
35+
});
36+
} catch (e) {
37+
this.onClose(_socket.closeCode, _socket.closeReason);
38+
}
39+
}
40+
41+
send(data) {
42+
if (_socket != null) {
43+
_socket.add(data);
44+
logger.debug('send: $data');
45+
}
46+
}
47+
48+
close() {
49+
_socket.close();
50+
}
51+
52+
isConnecting() {
53+
return _socket != null && _socket.readyState == WebSocket.connecting;
54+
}
55+
56+
/// For test only.
57+
Future<WebSocket> _connectForBadCertificate(
58+
String scheme, String host, int port) async {
59+
try {
60+
Random r = new Random();
61+
String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));
62+
SecurityContext securityContext = new SecurityContext();
63+
HttpClient client = HttpClient(context: securityContext);
64+
client.badCertificateCallback =
65+
(X509Certificate cert, String host, int port) {
66+
logger.warn('Allow self-signed certificate => $host:$port. ');
67+
return true;
68+
};
69+
70+
HttpClientRequest request = await client.getUrl(Uri.parse(
71+
(scheme == 'wss' ? 'https' : 'http') +
72+
'://$host:$port/ws')); // form the correct url here
73+
74+
request.headers.add('Connection', 'Upgrade');
75+
request.headers.add('Upgrade', 'websocket');
76+
request.headers.add('Sec-WebSocket-Protocol', 'protoo');
77+
request.headers.add(
78+
'Sec-WebSocket-Version', '13'); // insert the correct version here
79+
request.headers.add('Sec-WebSocket-Key', key.toLowerCase());
80+
81+
HttpClientResponse response = await request.close();
82+
var socket = await response.detachSocket();
83+
var webSocket = WebSocket.fromUpgradedSocket(
84+
socket,
85+
protocol: 'protoo',
86+
serverSide: false,
87+
);
88+
89+
return webSocket;
90+
} catch (e) {
91+
logger.error('error $e');
92+
throw e;
93+
}
94+
}
95+
}

lib/src/transports/websocket_transport.dart

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'dart:convert';
22
import 'dart:io';
33
import 'dart:math';
44
import 'package:events2/events2.dart';
5+
import 'websocket_dart_impl.dart'
6+
if (dart.library.js) 'websocket_web_impl.dart';
57
import '../logger.dart';
68

79
const APP_NAME = 'protoo-client';
@@ -17,7 +19,7 @@ const WS_SUBPROTOCOL = 'protoo';
1719

1820
class WebSocketTransport extends EventEmitter {
1921
var _url;
20-
var _ws;
22+
WebSocketImpl _ws;
2123
var _closed;
2224
JsonDecoder decoder = new JsonDecoder();
2325
JsonEncoder encoder = new JsonEncoder();
@@ -34,14 +36,13 @@ class WebSocketTransport extends EventEmitter {
3436

3537
get closed => this._closed;
3638

37-
Future<dynamic> send(message) async {
39+
send(message) {
3840
if (this._closed) {
3941
throw 'transport closed';
4042
}
4143
try {
4244
logger.debug('send message: ' + encoder.convert(message));
43-
this._ws.add(encoder.convert(message));
44-
return message;
45+
this._ws.send(encoder.convert(message));
4546
} catch (error) {
4647
logger.failure('send() | error sending message: ' + error.toString());
4748
throw error;
@@ -50,9 +51,7 @@ class WebSocketTransport extends EventEmitter {
5051

5152
void close() {
5253
logger.debug('close()');
53-
5454
if (this._closed) return;
55-
5655
// Don't wait for the WebSocket 'close' event, do it now.
5756
this._closed = true;
5857
this.emit('close');
@@ -63,59 +62,30 @@ class WebSocketTransport extends EventEmitter {
6362
}
6463
}
6564

66-
Future<WebSocket> _connectForSelfSignedCert(String url) async {
67-
try {
68-
Random r = new Random();
69-
String key = base64.encode(List<int>.generate(8, (_) => r.nextInt(255)));
70-
SecurityContext securityContext = new SecurityContext();
71-
HttpClient client = HttpClient(context: securityContext);
72-
client.badCertificateCallback =
73-
(X509Certificate cert, String host, int port) {
74-
print('Allow self-signed certificate => $host:$port. ');
75-
return true;
76-
};
77-
print(url);
78-
HttpClientRequest request = await client.getUrl(
79-
Uri.parse(url)); // form the correct url here
80-
request.headers.add('Connection', 'Upgrade');
81-
request.headers.add('Upgrade', 'websocket');
82-
request.headers.add('Sec-WebSocket-Protocol', WS_SUBPROTOCOL);
83-
request.headers.add(
84-
'Sec-WebSocket-Version', '13'); // insert the correct version here
85-
request.headers.add('Sec-WebSocket-Key', key.toLowerCase());
86-
87-
HttpClientResponse response = await request.close();
88-
Socket socket = await response.detachSocket();
89-
var webSocket = WebSocket.fromUpgradedSocket(
90-
socket,
91-
protocol: 'signaling',
92-
serverSide: false,
93-
);
94-
95-
return webSocket;
96-
}catch(e){
97-
throw e;
98-
}
99-
}
100-
10165
void connect() async {
66+
logger.debug('connecting to WebSocket ${this._url}');
10267
try {
68+
this._ws = WebSocketImpl(this._url);
69+
70+
this._ws.onOpen = () {
71+
_closed = false;
72+
this.emit('open');
73+
};
10374

104-
this._ws = await _connectForSelfSignedCert(this._url);
105-
/*
106-
this._ws = await WebSocket.connect(this._url, headers: {
107-
'Sec-WebSocket-Protocol': WS_SUBPROTOCOL,
108-
});
109-
*/
110-
this._ws.listen((data) {
75+
this._ws.onMessage = (data) {
11176
logger.debug('Recivied data: ' + data);
11277
this.emit('message', decoder.convert(data));
113-
}, onDone: () {
78+
};
79+
80+
this._ws.onClose = (closeCode, closeReason) {
11481
logger.debug('Closed by server!');
82+
this._closed = true;
11583
this.emit('close');
116-
});
117-
this.emit('open');
84+
};
85+
86+
await this._ws.connect(headers: {});
11887
} catch (e) {
88+
this._closed = true;
11989
this.emit('error', e.toString());
12090
}
12191
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'dart:html';
2+
import 'dart:js_util' as JSUtils;
3+
import '../logger.dart';
4+
5+
typedef void OnMessageCallback(dynamic msg);
6+
typedef void OnCloseCallback(int code, String reason);
7+
typedef void OnOpenCallback();
8+
9+
class WebSocketImpl {
10+
String _url;
11+
var _socket;
12+
OnOpenCallback onOpen;
13+
OnMessageCallback onMessage;
14+
OnCloseCallback onClose;
15+
final logger = Logger('Logger::HTML::WebSocket');
16+
17+
WebSocketImpl(this._url);
18+
19+
connect({Object protocols, Object headers}) async {
20+
logger.debug('connect $_url, $headers, $protocols');
21+
try {
22+
_socket = WebSocket(_url, 'protoo');
23+
_socket.onOpen.listen((e) {
24+
this?.onOpen();
25+
});
26+
27+
_socket.onMessage.listen((e) async {
28+
if (e.data is Blob) {
29+
dynamic arrayBuffer = await JSUtils.promiseToFuture(
30+
JSUtils.callMethod(e.data, 'arrayBuffer', []));
31+
String message = String.fromCharCodes(arrayBuffer.asUint8List());
32+
this?.onMessage(message);
33+
} else {
34+
this?.onMessage(e.data);
35+
}
36+
});
37+
38+
_socket.onClose.listen((e) {
39+
this?.onClose(e.code, e.reason);
40+
});
41+
} catch (e) {
42+
this?.onClose(e.code, e.reason);
43+
}
44+
}
45+
46+
send(data) {
47+
if (_socket != null && _socket.readyState == WebSocket.OPEN) {
48+
_socket.send(data);
49+
logger.debug('send: $data');
50+
} else {
51+
logger.error('WebSocket not connected, message $data not sent');
52+
}
53+
}
54+
55+
isConnecting() {
56+
return _socket != null && _socket.readyState == WebSocket.CONNECTING;
57+
}
58+
59+
close() {
60+
_socket.close();
61+
}
62+
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: protoo_client
2-
version: 0.2.0
2+
version: 0.3.0
33
description: Dart version of the protoo-client library.
44
homepage: https://github.com/cloudwebrtc/dart-protoo-client
55
environment:

0 commit comments

Comments
 (0)