Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
HerbCaudill committed Dec 14, 2023
1 parent 0fbc452 commit 8a72877
Showing 1 changed file with 68 additions and 78 deletions.
146 changes: 68 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Deploy to:
[AWS](#deploying-to-aws-elastic-beanstalk) |
[Google](#deploying-to-google-cloud) |
[Azure](#deploying-to-azure) |
[local server](#installing-and-running-locally)
[local server](#server)

## Why

Expand All @@ -26,30 +26,31 @@ that want to communicate need a way to find each other. This is a problem of **d

## What

This service offers a solution to each of these two problems.
This little server offers a solution to each of these two problems.

### 1. Introduction
### 1. Discovery

Alice can provide one or more document documentIds that she's interested in. (A document documentId is a unique ID
for a topic or channel — it could be a GUID, or just a string like `ambitious-mongoose`.)
Alice can provide a `documentId` (or several) that she's interested in. (A `documentId`
is a unique ID for a topic or channel — it could be a GUID, or just a unique string like
`ambitious-mongoose`.)

[![diagram](./images/relay-introduction.png)](https://raw.githubusercontent.com/local-first-web/relay/master/images/relay-introduction.png)

If Bob is interested in the same documentId or documentIds, each will receive an `Introduction` message with the
other's peerId. They can then use that information to connect.
If Bob is interested in the same `documentId`, each will receive an `Introduction`
message with the other's peerId. They can then use that information to connect.

### 2. Connection

Alice can request to connect with Bob on a given document documentId. If we get matching connection
Alice can request to connect with Bob on a given documentId. If we get matching connection
requests from Alice and Bob, we pipe their sockets together.

[![diagram](./images/relay-connection.png)](https://raw.githubusercontent.com/local-first-web/relay/master/images/relay-connection.png)

## How

### Running locally
### Server

From this monorepo, you can run this server as follows:
From this repo, you can run this server as follows:

```bash
pnpm
Expand All @@ -69,122 +70,114 @@ You can visit that URL with a web browser to confirm that it's working; you shou

<img src='./images/screenshot.png' width='300' align='center' />

### Deploying to the cloud
#### Running server from another package

The recommended way to stand one of these up is to use the [relay-deployable] repo, which is
optimized for deployment.
From another codebase, you can import the server and run it as follows:

See instructions for deploying to:
[Glitch](http://github.com/local-first-web/relay-deployable#deploying-to-glitch) |
[Heroku](http://github.com/local-first-web/relay-deployable#deploying-to-heroku) |
[AWS](http://github.com/local-first-web/relay-deployable#deploying-to-aws-elastic-beanstalk) |
[Google](http://github.com/local-first-web/relay-deployable#deploying-to-google-cloud) |
[Azure](http://github.com/local-first-web/relay-deployable#deploying-to-azure) |
[local server](http://github.com/local-first-web/relay-deployable#installing-and-running-locally)
```ts
import { Server } from "@localfirst/relay/Server.js"

const DEFAULT_PORT = 8080
const port = Number(process.env.PORT) || DEFAULT_PORT

### Usage
const server = new Server({ port })

server.listen()
```

This library includes a lightweight client library designed to be
used with this server.
### Client

> You don't strictly need to use this client - you could interact directly with the server the way we
> do in the [server tests] - but it automates the business of accepting invitations when they're
> received.
This library includes a lightweight client designed to be used with this server.

The client keeps track of all peers that the server connects you to, and for each peer it keeps
track of each documentId (aka discoveryKey, aka channel) that you're working with that peer on.

```ts
import { Client } from "@localfirst/relay"
import { Client } from "@localfirst/relay/Client.js"

client = new Client({ peerId: "alice", url: "myrelay.somedomain.com" })
.join("ambitious-mongoose")
.on("peer.connect", ({ documentId, peerId, socket }) => {
.on("peer-connect", ({ documentId, peerId, socket }) => {
// `socket` is a WebSocket

// send a message
socket.write("Hello! 🎉")

// listen for messages
socket.on("data", message => {
socket.addEventListener("data", event => {
const message = event.data
console.log(`message from ${peerId} about ${documentId}`, message)
})
})
```

### Security
## Security

This server makes no security guarantees. Alice and Bob should probably:
This server makes no security guarantees. Alice and Bob should probably:

1. **Authenticate** each other, to ensure that "Alice" is actually Alice and "Bob" is actually Bob.
2. **Encrypt** all communications with each other.
1. **Authenticate** each other, to ensure that "Alice" is actually Alice and "Bob" is actually Bob.
2. **Encrypt** all communications with each other.

The [@localfirst/auth] library can be used with this relay service. It provides peer-to-peer
authentication and end-to-end encryption, and allows you to treat this relay (and the rest of the
network) as untrusted.

## Server API

> The following documentation might be of interest to anyone working on the @localfirst/relay `Client`, or replacing it
> with a new client. You don't need to know any of this to interact with this server if you're using the included client.
> The following documentation might be of interest to anyone working on the @localfirst/relay
> `Client`, or replacing it with a new client. You don't need to know any of this to interact with
> this server if you're using the included client.
This server has two WebSocket endpoints: `introduction` and `connection`.
This server has two WebSocket endpoints: `/introduction` and `/connection`.

### Introduction endpoint: `/introduction/:localId`
In the following examples, Alice is the local peer and Bob is a remote peer. We're using `alice` and `bob` as their `peerId`s; in practice, typically these would be GUIDs that uniquely identify their devices.

- I connect to this endpoint, e.g. `wss://myrelay.somedomain.com/introduction/alice`.
#### `/introduction/:localPeerId`

- `:localId` is my unique client identifier.
- `:localPeerId` is the local peer's unique `peerId`.

- Once a WebSocket connection has been made, I send an introduction request containing one or more
document IDs I'm interested in joining:
Alice connects to this endpoint, e.g. `wss://myrelay.somedomain.com/introduction/alice`.

```ts
{
type: 'Join',
documentIds: ['ambitious-mongoose', 'frivolous-platypus'], // documents I have or am interested in
}
```
Once a WebSocket connection has been made, Alice sends an introduction request containing one or more `documentId`s that she has or is interested in:

- If another peer is connected to the same server and interested in one or more of the same
documents IDs, the server sends me an introduction message:
```ts
{
type: 'Join',
documentIds: ['ambitious-mongoose', 'frivolous-platypus'], // documents Alice has or is interested in
}
```

```ts
{
type: 'Introduction',
peerId: 'bob', // the peer's peerId
documentIds: ['ambitious-mongoose'] // documents we're both interested in
}
```
If Bob is connected to the same server and interested in one or more of the same documents IDs, the
server sends Alice an introduction message:

```ts
{
type: 'Introduction',
peerId: 'bob', // Bob's peerId
documentIds: ['ambitious-mongoose'] // documents we're both interested in
}
```

- I can now use this information to request a connection to this peer via the `connection` endpoint:
Alice can now use this information to request a connection to this peer via the `connection` endpoint:

### Connection endpoint: `/connection/:localId/:remoteId/:documentId`
#### `/connection/:localPeerId/:remotePeerId/:documentId`

Once I've been given a peer's ID, I make a new connection to this endpoint, e.g.
Once Alice has Bob's `peerId`, she makes a new connection to this endpoint, e.g.
`wss://myrelay.somedomain.com/connection/alice/bob/ambitious-mongoose`.

- `:localId` is my unique client identifier.
- `:remoteId` is the peer's unique client identifier.
- `:localPeerId` is the local peer's unique `peerId`.
- `:remotePeerId` is the remote peer's unique `peerId`.
- `:documentId` is the document ID.

If and when the peer makes a reciprocal connection, e.g.
`wss://myrelay.somedomain.com/connection/bob/alice/ambitious-mongoose`, the server pipes their sockets
together and leaves them to talk.
If and when Bob makes a reciprocal connection by connecting to
`wss://myrelay.somedomain.com/connection/bob/alice/ambitious-mongoose`, the server pipes their
sockets together and leaves them to talk.

The client and server don't communicate with each other via the `connection` endpoint; it's purely a
relay between two peers.

## Deployment

Jump to instructions for:
[Glitch](#deploying-to-glitch) |
[Heroku](#deploying-to-heroku) |
[AWS](#deploying-to-aws-elastic-beanstalk) |
[Google](#deploying-to-google-cloud) |
[Azure](#deploying-to-azure) |
[local server](#installing-and-running-locally)

### Deploying to Glitch

You can deploy this relay to [Glitch](https://glitch.com) by clicking this button:
Expand All @@ -193,8 +186,6 @@ You can deploy this relay to [Glitch](https://glitch.com) by clicking this butto

Alternatively, you can remix the [**local-first-relay**](https://glitch.com/edit/#!/local-first-relay) project.

![image](./glitch-screenshot.png)

### Deploying to Heroku

This server can be deployed to [Heroku](https://heroku.com). By design, it should only ever run with a single dyno. You can deploy it by clicking on this button:
Expand All @@ -211,7 +202,7 @@ heroku open

### Deploying to AWS Elastic Beanstalk

To install using the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html).
Install using the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html):

```bash
eb init
Expand All @@ -221,7 +212,7 @@ eb open

### Deploying to Google Cloud

To install using the [Google Cloud SDK](https://cloud.google.com/sdk/docs/):
Install using the [Google Cloud SDK](https://cloud.google.com/sdk/docs/):

```bash
gcloud projects create my-local-first-relay --set-as-default
Expand All @@ -232,7 +223,7 @@ gcloud app browse

### Deploying to Azure

To install using the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) installed:
Install using the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest):

```bash
az group create --name my-local-first-relay --location eastus
Expand Down Expand Up @@ -265,5 +256,4 @@ Formerly known as 🐟 Cevitxe Signal Server. (Cevitxe is now [@localfirst/state
[@localfirst/state]: https://github.com/local-first-web/state
[@localfirst/auth]: https://github.com/local-first-web/auth
[@localfirst/relay-client]: ./packages/client/
[relay-deployable]: https://github.com/local-first-web/relay-deployable
[server tests]: ./packages/relay/src/Server.test.ts

0 comments on commit 8a72877

Please sign in to comment.