Have ideas to improve npm?Join in the discussion! »

    anysocket

    0.3.2 • Public • Published

    AnySocket

    An abstract networking layer over multiple transports, agnostic of client/server with support for E2EE (with forward secrecy)

    Dependency Status devDependency Status NPM version Downloads HitCount

    Important

    This is a work in progress and API is subject to change.

    WIP Documentation

    Features

    • Client / Server agnostic
    • Support for request/reply
    • E2EE between peers with forward secrecy
    • RPC support
    • P2P using a proxy server (with support for direct E2EE between peers)
    • Binary support (see: AnySocket.Packer)
    • Browser support - 30kb footprint (see: /dist/anysocket.bundle.js)
    • Multiple transports *(implemented atm: ws)
    • All peers have a UUIDv4 associated
    • Disconnect detection using a heartbeat
    • Not Battle Tested ...yet

    Info: Binary RPC arguments and responses are auto packed/unpacked (AnySocket.Packer.pack/AnySocket.Packer.unpack).

    Benchmark

    nodejs - browser

    Running PLAIN TEXT benchmark: 5518.838ms  (test duration)
    Latency: 0.86 ms
    Running E2EE benchmark: 5986.633ms        (test duration)
    Latency: 1.06 ms
    

    nodejs - nodejs

    Running PLAIN TEXT benchmark: 5010.484ms  (test duration)
    Latency: 0.67 ms
    Running E2EE benchmark: 5003.755ms        (test duration)
    Latency: 0.92 ms
    

    You can run the benchmarks from: /examples/benchmark

    Installation

    npm install --save anysocket

    or

    <script src="/dist/anysocket.bundle.js"></script>

    How to use

    The following example starts a websocket server on port 3000.

    const AnySocket = require("anysocket");
    const server = new AnySocket();
    const PORT = 3000;
    server.listen("ws", PORT)
        .then(() => {
            console.log("Listening on port:", PORT);
        })
        .catch((err) => {
            console.error("Failed to start server:", err);
        });
    server.on("connected", (peer) => {
        console.log("Connected", peer.id);    
        peer.send({
            hello: "world"
        });
    });
    server.on("message", (packet) => {
        console.log("From:", packet.peer.id, "Message:", packet.msg);
    });
    server.on("disconnected", (peer, reason) => {
        console.log("Disconnected", peer.id, "Reason:", reason);
    });

    The following example connects to a websocket on port 3000

    const AnySocket = require("anysocket");
    const client = new AnySocket();
    const PORT = 3000;
    client.connect("ws", "127.0.0.1", PORT)
        .then(() => {
            // note: you cannot send messages from here, you need to wait for the "connected" event
            console.log("Connected to server");
        })
        .catch((err) => {
            console.error("Failed to connect to server:", err);
        });
    
    // after negotiating the AUTH packet, it will trigger the connect event
    client.on("connected", (peer) => {
        console.log("Connected", peer.id);    
        peer.send({
            hello: "world"
        });
    });
    client.on("message", (packet) => {
        console.log("From:", packet.peer.id, "Message:", packet.msg);
    });
    client.on("disconnected", (peer, reason) => {
        console.log("Disconnected", peer.id, "Reason:", reason);
    });

    More in the examples folder.

    Api

    Documentation

    AnySocket()

    Creates a new AnySocket instance


    AnySocket.id

    Unique identifier (UUIDv4) that will be used for all connections originating this instance (client/server)


    AnySocket.server(scheme, options)

    Alias for AnySocket.listen()


    AnySocket.listen(scheme, options)

    Attaches a new server transport based on the selected *scheme

    Arguments:

    • scheme - one of the implemented transports
    • options - one of the options below
      • port - port number
      • json
    {
        ip: "0.0.0.0", // listening ip
        port: 3000, // listening port
        replyTimeout: 30 * 1000, // reply timeout
        heartbeatInterval: 5 * 1000 // heartbeat interval
    }
    

    Returns a Promise that resolves/rejects when the server has started listening or when it throws an error


    AnySocket.connect(scheme, ip, port, [options])

    Connects to AnySocket Server

    Arguments:

    • scheme - one of the implemented transports
    • ip - server ip
    • port - server port
    • options - options json
    {
        replyTimeout: 30 * 1000, // reply timeout
        heartbeatInterval: 5 * 1000 // heartbeat interval
    }
    

    Returns a Promise that resolves/rejects when a connection has been established note: you cannot take actions (ex: send) until the connected event has been triggered


    AnySocket.stop()

    Stops all servers and disconnects all peers

    Returns a Promise that resolves/rejects when finished


    AnySocket.broadcast(message, [awaitReply])

    Broadcasts a message to all connected peers

    Arguments:

    • message - a JSON stringifiable object
    • awaitReply - set to true if a reply is expected (optional) - default: false

    Returns a Promise that resolves with a AnyPacket if waiting for a reply or rejects on error

    note: it doesn't resolve if awaitReply is not set


    AnySocket.setRPC(rpc)

    This sets the RPC functions on the AnySocket object so they can be called using AnyPeer.rpc RPC object can be nested indefinitely, but the "this" object will always be the called method's parent

    Each RPC function can return a value, object, Buffer/TypedArray or a Promise (awaits the promise to be resolved)

    Binary info:

    • If a RPC receives an argument as a Buffer/TypedArray it will be auto unpacked
    • If a RPC returns a Buffer/TypedArray it will be auto packed

    Arguments:

    • rpc - object or class with RPC functions

    Any throwed error / reject will be sent back to the client in the form:

    {
        error: "error message",
        code: 500
    }

    AnySocket.canProxy(peerID, otherPeerID)

    Checks if peerID can be proxied through otherPeerID. Defaults to: false

    note: You need to override this function in order to allow proxying

    Returns true/false


    AnySocket.hasPeer(id)

    note: returns true for proxies

    Returns true/false if AnySocket has a peer with the id


    AnySocket.hasDirectPeer(id)

    note: returns false for proxies

    Returns true/false if AnySocket has a direct peer (no proxy) with the id


    AnySocket.proxy(peerID, throughPeerID)

    Send a proxy request for peerID via throughPeerID as relay

    note: A proxied peer uses the same flow as a new connection

    Returns a Promise that resolves with a AnyPeer or rejects if proxy fails


    AnySocket event connected

    Emitted when the link has been established and it's ready for sending/receiving messages

    Arguments:


    AnySocket event message

    Emitted when a message is received

    Arguments:


    AnySocket event e2e

    Emitted when the link has been end-to-end encrypted and it's ready to be used

    Arguments:


    AnySocket event disconnected

    Emitted when a peer has disconnected

    Arguments:

    • peer - AnyPeer instance
    • reason - a string detailing the disconnect reason

    AnyPacket()

    Constructor should not be used directly


    AnyPacket.seq

    An incremental unique identifier per packet per peer (used internally)


    AnyPacket.peer

    An AnyPeer instance


    AnyPacket.msg

    An object that contains data sent/received from a peer


    AnyPacket.reply(message)

    Sends a reply to the current packet

    Arguments:

    • message - a JSON stringifiable object

    note: you can only reply to a normal message, you cannot reply to a reply packet. It fails silently


    AnySocket.Packer.pack(bytes)

    Packs the bytes

    Arguments:

    • bytes - Buffer/TypedArray

    Returns a string representation of the bytes


    AnySocket.Packer.unpack(bytes)

    Unpacks the bytes

    Arguments:

    • bytes - String representation of a Buffer/TypedArray

    Returns a Buffer/TypedArray


    AnyPeer()

    Constructor should not be used directly


    AnyPeer.id

    Unique peer identifier (UUIDv4) - Peer AnySocket.id


    AnyPeer.connectionID

    Unique connection identifier (UUIDv4), used internally before getting a AnyPeer.id


    AnyPeer.rpc(...args)

    This is a special Proxy Object that can indefinitely nested and have any number of arguments

    Example: peer.rpc.hello.world.user("LynxAegon")

    • This will try to run a RPC on the peer and the RPC object should look like this:
    AnySocket.setRPC({
        hello: {
            world: {
                user: (name) => {
                    return new Promise((resolve, reject) => {
                        resolve("Hello World, " + name);
                    });
                }
            }
        }
    })

    Returns a Promise that will resolve if success or reject in case of error


    AnyPeer.e2e()

    Enables E2E encryption using ECDH for exchange and then switches to AES-256-CBC with forward secrecy.

    Each message is encrypted with a different key derrived from the master key


    AnyPeer.send(message, [awaitReply, [timeout]])

    Sends a message to the peer

    Arguments:

    • message - a JSON stringifiable object
    • awaitReply - set to true if a reply is expected (optional) - default: false
    • timeout - set a custom reply packet timeout in milliseconds (optional)

    Returns a Promise that resolves with a AnyPacket if waiting for a reply or rejects on error

    note: it doesn't resolve if awaitReply is not set

    note: you can only reply to a normal message, you cannot reply to a reply packet. It fails silently


    AnyPeer.disconnect(reason)

    Disconnects the peer

    Arguments:

    • reason - a string that explains why the peer was disconnected

    AnyPeer.isProxy()

    Returns true if the AnyPeer instance is a proxy (see: AnySocket.proxy)


    AnyPeer.isE2EEnabled()

    Returns true if the connection has been end-to-end encrypted (see: AnyPeer.e2e)


    AnyPeer event message

    Emitted when a message is received

    Arguments:


    AnyPeer event e2e

    Emitted when the link has been end-to-end encrypted and it's ready to be used

    Arguments:


    AnyPeer event disconnected

    Emitted when the peer has disconnected

    Arguments:

    • peer - AnyPeer instance
    • reason - a string detailing the disconnect reason

    Upcoming Features

    • Mesh Network
    • Multiple transports: wss, tcp, http, udp*, ipc
    • Client reconnection
    • Custom AUTH method

    * this will require a change in the protocol, as the protocol assumes the packets are sent using a reliable, ordered connection

    License

    MIT

    Install

    npm i anysocket

    DownloadsWeekly Downloads

    19

    Version

    0.3.2

    License

    MIT

    Unpacked Size

    151 kB

    Total Files

    49

    Last publish

    Collaborators

    • avatar