Open LivInTheLookingGlass opened 7 years ago
Here's my best current guess at what this would look like. This only handles the sockets, not the server.
class SocketAdapter {
constructor(addr, port, aProtocol) {
if (aProtocol.encryption === 'Plaintext') {
return new TCPSocketAdapter(addr, port);
}
else if (aProtocol.encryption === 'ws' || aProtocol.encryption === 'wss') {
var uri = `${aProtocol.encryption}://${addr}:${port}`;
return new WSAdapter(uri, aProtocol.encryption === 'wss');
}
else if (aProtocol.encryption === 'SSL') {
return new TLSSocketAdapter(addr, port);
}
else {
throw new Error("Unknown transport protocol");
}
}
write(data, encoding) {
this.conn.write(data, encoding);
}
on(evnt, callback) {
return this.emitter.on(evnt, callback);
}
}
class TCPSocketAdapter extends SocketAdapter {
constructor(addr, port) {
this.conn = this.emitter = new require('net').Socket();
this.conn.connect(port, addr);
}
}
class WSAdapter extends SocketAdapter {
constructor(uri, isSecure) {
if (WebSocket !== undefined) {
if (isSecure) {
throw new Error("Secure WebSockets not yet supported");
}
else {
return new BrowserWSAdapter(uri);
}
}
else {
if (isSecure) {
throw new Error("Secure WebSockets not yet supported");
}
else {
return new NodeWSAdapter(uri);
}
}
}
write(data, encoding) {
this.conn.send(new Buffer(data, encoding));
}
}
class BrowserWSAdapter extends WSAdapter {
constructor(uri) {
this.conn = new WebSocket(uri);
this.emitter = new EventEmitter();
this.conn.onconnect = ()=>{
this.emitter.emit('connect', ...arguments);
}
this.conn.onmessage = (evt)=>{
fileReader.onload = ()=>{
this.emitter.emit('data', Buffer.from(fileReader.result));
};
fileReader.readAsArrayBuffer(evt.data);
}
this.conn.onend = (evt)=>{
this.emitter.emit('end');
}
this.conn.onerror = (evt)=>{
this.emitter.emit('error', evt);
}
this.conn.onclose = (evt)=>{
this.emitter.emit('close');
}
}
}
class NodeWSAdapter extends WSAdapter {
constructor(uri) {
this.conn = this.emitter = require('nodejs-websocket').connect(url);
}
on(evnt, callback) {
if (evt === 'data') {
super.on('text', (str)=>{
callback(new Buffer(data));
});
return super.on('binary', (inStream)=>{
inStream.on("readable", ()=>{
var newData = inStream.read();
if (newData) {
callback(newData);
}
});
});
}
else {
return super.on(evnt, callback);
}
}
}
class TLSSocketAdapter extends SocketAdapter {
constructor(addr, port) {
let options = {
rejectUnauthorized: false
};
this.conn = this.emitter = require('tls').connect(port, addr, options);
}
on(evnt, callback) {
if (evt === 'connect') {
return super.on('secureConnect', callback);
}
else {
return super.on(evnt, callback);
}
}
}
@bslater1337, does this seem reasonable to you?
This would allow for a more consistent API. An example would be browser WebSockets. They do not inherit from EventEmitter. An adapter class could make it seem like they do.
This could also allow for easier support of non-streaming protocols like UDP.