Skip to content

Commit

Permalink
add io_websocket transport for switching the implementation of dart.l…
Browse files Browse the repository at this point in the history
…ibrary.html and dart.library.io on #4 Flutter Port
  • Loading branch information
jumperchen committed Jan 21, 2019
1 parent d26a257 commit 88a2a09
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 156 deletions.
19 changes: 13 additions & 6 deletions lib/src/engine/socket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ import 'dart:convert';
*
* Copyright (C) 2017 Potix Corporation. All Rights Reserved.
*/
import 'dart:html';
//import 'dart:html';

import 'package:logging/logging.dart';
import 'package:socket_io_common/src/util/event_emitter.dart';
import 'package:socket_io_client/src/engine/parseqs.dart';
import 'package:socket_io_common/src/engine/parser/parser.dart' as parser;
import 'package:socket_io_client/src/engine/transport/polling_transport.dart';
import 'package:socket_io_client/src/engine/transport/transports.dart';
import './transport/transport.dart';

// ignore: uri_does_not_exist
import './transport/transports_stub.dart'
// ignore: uri_does_not_exist
if (dart.library.html) './transport/transports.dart'
// ignore: uri_does_not_exist
if (dart.library.io) './transport/io_transports.dart';

final Logger _logger = new Logger('socket_io_client:engine.Socket');

Expand Down Expand Up @@ -80,7 +87,7 @@ class Socket extends EventEmitter {
opts['hostname'] = Uri.parse(opts['host']).host;
}

this.secure = opts['secure'] ?? (window.location.protocol == 'https:');
this.secure = opts['secure'] /*?? (window.location.protocol == 'https:')*/;

if (opts['hostname'] != null && !opts.containsKey('port')) {
// if no port is specified manually, use the protocol default
Expand All @@ -89,11 +96,11 @@ class Socket extends EventEmitter {

this.agent = opts['agent'] ?? false;
this.hostname =
opts['hostname'] ?? (window.location.hostname ?? 'localhost');
this.port = opts['port'] ??
opts['hostname'] /*?? (window.location.hostname ?? 'localhost')*/;
this.port = opts['port'] /*??
(window.location.port.isNotEmpty
? int.parse(window.location.port)
: (this.secure ? 443 : 80));
: (this.secure ? 443 : 80))*/;
var query = opts['query'] ?? {};
if (query is String)
this.query = decode(query);
Expand Down
19 changes: 19 additions & 0 deletions lib/src/engine/transport/io_transports.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2019 Potix Corporation. All Rights Reserved
// History: 2019-01-21 12:15
// Author: jumperchen<[email protected]>
import 'package:socket_io_client/src/engine/transport/io_websocket_transport.dart';
import 'package:socket_io_client/src/engine/transport/transport.dart';

class Transports {
static List<String> upgradesTo(String from) {
if ("polling" == from) {
return ["websocket"];
}
return [];
}

static Transport newInstance(String name, options) {
// only support websocket here.
return new IOWebSocketTransport(options);
}
}
169 changes: 169 additions & 0 deletions lib/src/engine/transport/io_websocket_transport.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright (C) 2019 Potix Corporation. All Rights Reserved
// History: 2019-01-21 12:13
// Author: jumperchen<[email protected]>

import 'dart:async';
import 'dart:io';
//import 'dart:html';
import 'package:logging/logging.dart';
import 'package:socket_io_client/src/engine/transport/transport.dart';
import 'package:socket_io_common/src/engine/parser/parser.dart';
import 'package:socket_io_client/src/engine/parseqs.dart';

class IOWebSocketTransport extends Transport {
static Logger _logger =
new Logger('socket_io_client:transport.IOWebSocketTransport');

String name = 'websocket';
var protocols;

bool supportsBinary;
Map perMessageDeflate;
WebSocket ws;

IOWebSocketTransport(Map opts) : super(opts) {
var forceBase64 = (opts != null && opts['forceBase64']);
this.supportsBinary = !forceBase64;
this.perMessageDeflate = opts['perMessageDeflate'];
this.protocols = opts['protocols'];
}

void doOpen() async {
var uri = this.uri();
var protocols = this.protocols;

try {
this.ws = await WebSocket.connect(uri, protocols: protocols);
} catch (err) {
return this.emit('error', err);
}

// if (this.ws.binaryType == null) {
// this.supportsBinary = false;
// }
//
// this.ws.binaryType = 'arraybuffer';

this.addEventListeners();
}

/**
* Adds event listeners to the socket
*
* @api private
*/
void addEventListeners() {
bool isOpen = false;
this.ws.listen((data) {
if (isOpen != true) {
onOpen();
isOpen = true;
}
onData(data);
}, onDone: () => onClose(), onError: (_) => onError('websocket error'));
}

/**
* Writes data to socket.
*
* @param {Array} array of packets.
* @api private
*/
write(List packets) {
this.writable = false;

var done = () {
emit('flush');

// fake drain
// defer to next tick to allow Socket to clear writeBuffer
Timer.run(() {
writable = true;
emit('drain');
});
};

int total = packets.length;
// encodePacket efficient as it uses WS framing
// no need for encodePayload
packets.forEach((packet) {
PacketParser.encodePacket(packet,
supportsBinary: supportsBinary, fromClient: true, callback: (data) {
// Sometimes the websocket has already been closed but the browser didn't
// have a chance of informing us about it yet, in that case send will
// throw an error
try {
// TypeError is thrown when passing the second argument on Safari
ws.add(data);
} catch (e) {
_logger.fine('websocket closed before onclose event');
}

if (--total == 0) done();
});
});
}

/**
* Closes socket.
*
* @api private
*/
doClose() {
this.ws?.close();
}

/**
* Generates uri for connection.
*
* @api private
*/
uri() {
var query = this.query ?? {};
var schema = this.secure ? 'wss' : 'ws';
var port = '';

// avoid port if default for schema
if (this.port != null &&
(('wss' == schema && this.port != 443) ||
('ws' == schema && this.port != 80))) {
port = ':${this.port}';
}

// append timestamp to URI
if (this.timestampRequests == true) {
query[this.timestampParam] =
new DateTime.now().millisecondsSinceEpoch.toRadixString(36);
}

// communicate binary support capabilities
if (this.supportsBinary == false) {
query['b64'] = 1;
}

var queryString = encode(query);

// prepend ? to query
if (queryString.isNotEmpty) {
queryString = '?$queryString';
}

var ipv6 = this.hostname.contains(':');
return schema +
'://' +
(ipv6 ? '[' + this.hostname + ']' : this.hostname) +
port +
this.path +
queryString;
}
//
// /**
// * Feature detection for WebSocket.
// *
// * @return {Boolean} whether this transport is available.
// * @api public
// */
// check() {
// return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
// }
}
2 changes: 1 addition & 1 deletion lib/src/engine/transport/polling_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import 'package:socket_io_client/src/engine/parseqs.dart';
*
* Copyright (C) 2017 Potix Corporation. All Rights Reserved.
*/
import 'package:socket_io_client/src/engine/transport/transports.dart';
import 'package:logging/logging.dart';
import 'package:socket_io_client/src/engine/transport/transport.dart';
import 'package:socket_io_common/src/engine/parser/parser.dart';

final Logger _logger = new Logger('socket_io:transport.PollingTransport');
Expand Down
Loading

0 comments on commit 88a2a09

Please sign in to comment.