Git Product home page Git Product logo

libp2p-websocket's Introduction

LIBP2P-WEBSOCKET

Relay p2p connections between browsers transcoding between sockets and websockets

This runs a simple websocket server and listens for websocket connections using a simple protocol:

NOTE: THIS IS A WORK IN PROGRESS

LICENSE AND COPYRIGHT

Copyright (c) 2020, William R. Burdick Jr., Roy Riggs, and TEAM CTHLUHU. All rights reserved. Use of this source code is governed by an MIT-style license that can be found in the LICENSE file.

Running

./libp2p-websocket -browser chat.html will start the relay and pop the chat example in a browser

In development, you can use -files to point to the live html/js/css files you are editing. If you are in the src directory. For example, you should be able to use this command to pop out a development version of chat:

libp2p-websocket -files html -files examples -browse chat.html

Usage:

Usage of libp2p-websocket:
  -addr string
        host address to listen on
  -browse string
        Browse a URL
  -files value
        add the contents of a directory to serve from /
  -key string
        specify peer key
  -listen value
        Adds a multiaddress to the listen list
  -nopeers
        clear the bootstrap peer list
  -peer value
        Adds a peer multiaddress to the bootstrap list
  -port int
        port to listen on (default 8888)

libp2p-websocket runs a websocket server on /libp2p

This allows a browser to control the relay using a very simple binary protocol. When a connection closes, it cleans up all of its child connections. The client and server exchange these command messages, with the first byte of each message identifying the command.

CLIENT-TO-SERVER MESSAGES

  Start:       [0][KEY: str] -- start peer with optional peer key
  Listen:      [1][FRAMES: 1][PROTOCOL: rest] -- request a listener for a protocol (frames optional)
  Stop:        [2][PROTOCOL: rest] -- stop listening to PROTOCOL
  Close:       [3][ID: 8]                     -- close a stream
  Data:        [4][ID: 8][data: rest]         -- write data to stream
  Connect:     [5][FRAMES: 1][PROTOCOL: STR][RELAY: STR][PEERID: rest] -- connect to another peer (frames optional)

Including peer addresses with the peerid

The connect message allows a peer ID or a peer ID plus its addresses. This allows connection to peers without relying on discovery techniques. Users can exchange addresses over other channels, like chat programs.

A peer ID plus its addresses are encoded as

/addrs/BASE85JSON where BASE85JSON is a JSON object encoded in base85. The JSON object is like this:

{
    "peerID": PEERID,
    "addrs": [MULTIADDR,...]
}

SERVER-TO-CLIENT MESSAGES

  Hello:                   [0][STARTED: 1] -- hello message indicates whether the peer needs starting
  Identify:                [1][PUBLIC: 1][PEERID: str][ADDRESSES: str][KEY: rest] -- successful initialization
  Listener Connection:     [2][ID: 8][PEERID: str][PROTOCOL: rest] -- new listener connection with id ID
  Connection Closed:       [3][ID: 8][REASON: rest]            -- connection ID closed
  Data:                    [4][ID: 8][data: rest]              -- receive data from stream with id ID
  Listen Refused:          [5][PROTOCOL: rest]                 -- could not listen on PROTOCOL
  Listener Closed:         [6][PROTOCOL: rest]                 -- could not listen on PROTOCOL
  Peer Connection:         [7][ID: 8][PEERID: str][PROTOCOL: rest] -- connected to a peer with id ID
  Peer Connection Refused: [8][PEERID: str][PROTOCOL: str][ERROR: rest] -- connection to peer PEERID refused
  Protocol Error:          [9][MSG: rest]                      -- error in the protocol
  Listening:               [10][PROTOCOL: rest]                -- confirmation that listening has started

Building

Prerequisites

go: you need go if you want to build the go part (which includes updating the default HTML files)

esc: go get -u github.com/mjibson/esc -- make sure this is on your path (it should go into $GOHOME/bin).

Building the default webdir

The src/build file is (probably?) a posix shell script that uses esc to generate files.go by combining examples/* and html/* into a directory and creating a virtual file system out of which the HTTP server serves files.

build-and-run

Go compiles so fast that, while I'm developing, I build the entire project everytime I run it:

cd src
./build && go build libp2p-websocket.go protocol.go files.go && ./libp2p-websocket -browse chat.html

This creates an updated files.go, compiles the project, and then runs the chat example.

libp2p-websocket's People

Contributors

furroy avatar zot avatar

Watchers

 avatar  avatar  avatar  avatar

libp2p-websocket's Issues

Signal/Relay peers

Todo:

  • see if running an autonat service on textcraft can make nat detection faster
  • high level signalling
    • add request token system
  • high level relaying
  • invite-only sessions

NAT problems

Private-natted peers are a problem. There are two cases:

  1. public-natted peer connects to private-natted host
    • Callback: public peer needs to request a callback from private host
    • Signalling: private host needs to "hear" the request
  2. private-natted peer connects to private-natted host (the double NAT problem)
    • Relay: private peer needs to relay messages to the host through a public peer
  3. NAT detection: a peer needs to know whether it's private

libp2p's autorelay is supposed to solve these problems implicitly but I haven't been able to get it to work. I also tried regular relay, which I also haven't been able to get to work.

libp2p's autonat project does NAT detection but it takes 30 seconds for my machine to detect that it's private. Maybe we could run a NAT detection response service on Textcraft to speed this up?

Failing autorelay, I tried using the DHT for signalling by having the private host monitor the DHT for "advertisements" of callback requests from public peers. I might be doing something wrong but it's taking more than a minute for the host to "hear" a request. This is in addition to the 30 seconds it takes for NAT detection. So that has to be faster.

So here's my approach for working around most of these problems:

The easy case: connections to public hosts

  1. A public host generates a session token
  2. The host user shares the token with other people over a messenger
  3. Other people paste the session token in their GUI to connect to the host

The hard case: connections to private hosts

  1. A private host user generates a request token and sends it to a public peer user over a messenger
  2. The public peer user pastes it in their GUI and tells the private host user over a messenger to connect
  3. The private host user connects to the public peer and generates a session token
  4. The private host user shares the session token with other users over a messenger
  5. Other users paste the session token in the GUI to connect
  6. Each public peer connection generates a new session token that can relay through it

The magic session token here makes peers connect to the public peer instead of the private host. The public peer acts as a signal/relay peer (both signalling and relay). The session token specifies which public peer to use.

When a public peer connects, the signalling peer sends a callback request to the private host, which connects to the new public peer, causing the new peer to become another signaling/relay peer.

When a private peer connects, the signal/relay peer it connects through relays all messages to the private host.

The caveat

This means that in order to be a host, a private-natted peer needs at least one public-natted peer to connect and be a signal/relay peer. I think this is OK because a ton of routers support UPnP so public peers should be fairly common among a user base. The best solution for private-only sessions that I can think of is to allow public peers that are not connected to signal/relay for other sessions.

To get a list of public peers, we could actually use the DHT, which is slow, by caching the result and updating new info as it comes in. A host could reuse session ids and peers that connect through relay peers could pick their relay randomly.

Invite-only sessions

  • A host peer has a list of peers that are allowed to connect
  • Each peer already has its own key pair it can use to sign data
  • Instead of a public session token, the host generates a unique session token for each invite
  • The invited peer signs each message it sends and includes a nonce
  • Messages could be encrypted with the host's public key or with a shared secret

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.