Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sockets handled by a single adapter class #4

Open
LivInTheLookingGlass opened this issue May 21, 2017 · 2 comments
Open

Make sockets handled by a single adapter class #4

LivInTheLookingGlass opened this issue May 21, 2017 · 2 comments

Comments

@LivInTheLookingGlass
Copy link
Contributor

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
Copy link
Contributor Author

LivInTheLookingGlass commented May 21, 2017

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
Copy link
Contributor Author

@bslater1337, does this seem reasonable to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant