p2p-today / js2p

The Javascript implementation of the p2p.today networking framework (re-org in progress)
GNU Lesser General Public License v3.0
2 stars 0 forks source link

Make sockets handled by a single adapter class #4

Open LivInTheLookingGlass opened 7 years ago

LivInTheLookingGlass commented 7 years ago

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.

LivInTheLookingGlass commented 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);
        }
    }
}
LivInTheLookingGlass commented 7 years ago

@bslater1337, does this seem reasonable to you?