mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 06:31:27 -07:00
Revise README for improved clarity and details
Updated README.md for clarity and accuracy regarding service architecture and configuration instructions.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
RecFlare is an implementation of RecNet — the Rec Room backend — built on
|
RecFlare is an implementation of RecNet — the Rec Room backend — built on
|
||||||
Cloudflare Workers. It implements the network services the Rec Room client talks
|
Cloudflare Workers. It implements the network services the Rec Room client talks
|
||||||
to — accounts, auth, rooms, matchmaking, economy, chat, notifications, and more —
|
to — accounts, auth, rooms, matchmaking, economy, chat, notifications, and more —
|
||||||
each as an independent Worker on its own subdomain.
|
each as an independent Worker on their own subdomains, just how RecNet was.
|
||||||
|
|
||||||
> **Disclaimer:** This is an unofficial, fan-made project for preservation and
|
> **Disclaimer:** This is an unofficial, fan-made project for preservation and
|
||||||
> experimentation. It is not affiliated with, endorsed by, or connected to Rec
|
> experimentation. It is not affiliated with, endorsed by, or connected to Rec
|
||||||
@@ -14,7 +14,7 @@ each as an independent Worker on its own subdomain.
|
|||||||
There are already so many multiplayer clones, why?
|
There are already so many multiplayer clones, why?
|
||||||
|
|
||||||
1. None of them are fully open source (some had leaks of old code).
|
1. None of them are fully open source (some had leaks of old code).
|
||||||
2. None of them run on microservice architecture.
|
2. None of them run on microservice architecture, most on a single server.
|
||||||
3. None of them had unit tests.
|
3. None of them had unit tests.
|
||||||
4. "Upgrading the server" is not sustainable plan for growth.
|
4. "Upgrading the server" is not sustainable plan for growth.
|
||||||
5. This was fun (sort of).
|
5. This was fun (sort of).
|
||||||
@@ -35,7 +35,11 @@ RecFlare is compatible with the
|
|||||||
Room with manifest `7859140924515540835`. Other client or game versions may expect
|
Room with manifest `7859140924515540835`. Other client or game versions may expect
|
||||||
different endpoints and response shapes and are not supported.
|
different endpoints and response shapes and are not supported.
|
||||||
|
|
||||||
See the project page for information on how to mod the game to connect to this server.
|
Generally speaking any client that effectively rewrites the nameserver can be used
|
||||||
|
with this server.
|
||||||
|
|
||||||
|
See the above project page for information on how to mod the game to connect to this
|
||||||
|
server.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
@@ -105,40 +109,54 @@ apex/`ns` host and isn't listed within it. Each implemented worker has its own
|
|||||||
|
|
||||||
## Why Cloudflare?
|
## Why Cloudflare?
|
||||||
|
|
||||||
- **It's free to run a lot of services.** Cloudflare Workers' free tier is keyed
|
- **Makes it easy to mirror RecNet**
|
||||||
to usage, not to the number of Workers — so whether you deploy 1 service or all
|
Rec Room's backend is (was) a set of independent microservices, not one big monolith.
|
||||||
36, the baseline cost is the same. You only start paying once usage crosses the
|
Modeling each service as its own isolated Worker keeps RecFlare's structure close to
|
||||||
free-tier limits.
|
the real thing — services scale,
|
||||||
- **It mirrors RecNet's architecture.** Rec Room's backend is a set of
|
|
||||||
independent microservices, not one monolith. Modeling each service as its own
|
|
||||||
Worker keeps RecFlare's structure close to the real thing — services scale,
|
|
||||||
fail, and deploy independently — instead of collapsing everything into a single
|
fail, and deploy independently — instead of collapsing everything into a single
|
||||||
giant server.
|
giant server.
|
||||||
|
- **It's free/cheap to run a lot of service.**
|
||||||
|
Cloudflare Workers' free tier is keyed
|
||||||
|
to usage, not to the number of Workers — so whether you deploy 1 service or all
|
||||||
|
36, the baseline cost is the same. You only start paying once usage crosses the
|
||||||
|
free-tier limits. Additionally for development or maybe a private instance, the cost
|
||||||
|
is near zero when not in use.
|
||||||
|
- **Bundled Cloud CDN/Storage/SQL**
|
||||||
|
Cloudflare offers several cloud services we can rely on so the microservices can remain
|
||||||
|
stateless (effectively read-only). They are also scalable by default so we don't need to worry
|
||||||
|
about adding more disk space or upgrading services. If we start outgrowing the limits of these,
|
||||||
|
well, we'll cross that bridge when we get to it.
|
||||||
|
- D1 (a SQLite-compatible distributed database)
|
||||||
|
- R2 (service like S3 for mass file hosting)
|
||||||
|
- KV (service to distributed offer key/value stores)
|
||||||
|
- Durable Objects (for a notifications hub)
|
||||||
|
|
||||||
## Do I have to use Cloudflare?
|
## Do I have to use Cloudflare?
|
||||||
|
|
||||||
No. The services are plain [Hono](https://hono.dev) apps, so the request-handling
|
Short answer, no. The services are plain [Hono](https://hono.dev) apps, so the request-handling
|
||||||
code isn't tied to Cloudflare and can be deployed to other hosting providers —
|
code isn't tied to Cloudflare and can be deployed to other hosting providers —
|
||||||
AWS (Lambda), Vercel, Netlify, Fly.io, a plain Node/Bun server, and so on.
|
AWS (Lambda), Vercel, Netlify, Fly.io, a plain Node/Bun server, and so on.
|
||||||
|
|
||||||
**However**
|
Long answer: the catch is everything _around_ the code. RecFlare leans on Cloudflare for the
|
||||||
|
deployment (Wrangler) and infrastructure layer — custom-domain routing per service, plus the
|
||||||
The catch is everything _around_ the code. RecFlare leans on Cloudflare for the
|
|
||||||
deployment and infrastructure layer — custom-domain routing per service, plus the
|
|
||||||
storage bindings (D1, KV, R2, Durable Objects) the workers use. On another
|
storage bindings (D1, KV, R2, Durable Objects) the workers use. On another
|
||||||
provider you'll need to provide equivalents (per-service routing, databases,
|
provider you'll need to provide equivalents (per-service routing, databases,
|
||||||
object storage, a pub/sub or WebSocket layer) and wire up the deployment yourself.
|
object storage, a pub/sub or WebSocket layer) and wire up the deployment yourself.
|
||||||
|
|
||||||
|
So for example if you wanted to run on Vercel, you'd have to swap out KV for Redis, which are very similar
|
||||||
|
services but would require small code changes.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- node (modern)
|
- node (modern)
|
||||||
- pnpm
|
- pnpm
|
||||||
- bun
|
- bun
|
||||||
- jq
|
- jq/awk/sed
|
||||||
- A Cloudflare account with a zone (domain) you control, for deploying
|
- A Cloudflare account with a zone (domain) you control, for deploying.
|
||||||
|
|
||||||
Cloudflare's free plan is good enough for testing (100k requests/day) but the
|
Cloudflare's free plan is good enough for testing (100k worker requests/day) but the
|
||||||
Rec Room client is pretty chatty. Frequent testing may exhaust that quota.
|
Rec Room client is pretty chatty. Frequent testing may exhaust that quota. The $5/month
|
||||||
|
Worker plan includes 10M/month.
|
||||||
|
|
||||||
See https://developers.cloudflare.com/workers/platform/pricing/#workers
|
See https://developers.cloudflare.com/workers/platform/pricing/#workers
|
||||||
|
|
||||||
@@ -152,97 +170,60 @@ just install
|
|||||||
|
|
||||||
**Configure your custom domain:**
|
**Configure your custom domain:**
|
||||||
|
|
||||||
Create a new .env file:
|
Create a new .env file from the template:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# edit .env and set RECFLARE_DOMAIN to your domain
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, export it:
|
Edit `.env` and set `RECFLARE_DOMAIN` to your domain (or declare it with `export RECFLARE_DOMAIN=rec.example.com`)
|
||||||
|
|
||||||
```bash
|
(Optional) - per-app subdomain overrides come from
|
||||||
export RECFLARE_DOMAIN=rec.example.com
|
`RECFLARE_SUBDOMAINS` (a JSON object, e.g. `'{"playersettings":"settings"}'`). This would be used
|
||||||
```
|
if you wanted to merge two services together.
|
||||||
|
|
||||||
`just deploy` resolves the base domain at deploy time and passes it to wrangler —
|
|
||||||
each worker is attached to its custom domain via `--domain <subdomain>.<domain>`,
|
|
||||||
and the base domain is injected as the `DOMAIN` var so the `ns` service-discovery
|
|
||||||
document and the api share-link base URL are built at runtime. Nothing in version
|
|
||||||
control is rewritten; committed `wrangler.jsonc` files have no routes.
|
|
||||||
|
|
||||||
Per-app subdomain overrides come from
|
|
||||||
`RECFLARE_SUBDOMAINS` (a JSON object, e.g. `'{"playersettings":"settings"}'`).
|
|
||||||
|
|
||||||
**Create the storage resources:**
|
**Create the storage resources:**
|
||||||
|
|
||||||
The workers bind Cloudflare storage primitives — one shared D1 database, two KV
|
The workers bind Cloudflare storage primitive. Create them once against your
|
||||||
namespaces, two R2 buckets, and a Durable Object. Create them once against your
|
Cloudflare account, then record the IDs in `.env`. The committed `wrangler.jsonc`
|
||||||
Cloudflare account, then record the ids in `.env`. The committed `wrangler.jsonc`
|
files carry `"local"` placeholders; the real IDs are spliced in at deploy time, so
|
||||||
files carry `"local"` placeholders; the real ids are spliced in at deploy time, so
|
|
||||||
nothing in version control needs editing. Authenticate wrangler first
|
nothing in version control needs editing. Authenticate wrangler first
|
||||||
(`wrangler login`).
|
(`wrangler login`).
|
||||||
|
|
||||||
_D1 — one shared `recflare` database_ (bound by `api`, `accounts`, `auth`, `match`,
|
|
||||||
`rooms`):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wrangler d1 create recflare
|
wrangler d1 create recflare
|
||||||
# copy the printed database_id into .env:
|
|
||||||
# RECFLARE_D1=<database_id>
|
|
||||||
```
|
|
||||||
|
|
||||||
Then apply the schema. The `rooms` and `auth` workers own the migrations under
|
|
||||||
their `apps/<worker>/migrations/` directories. `just migrate` applies them to the
|
|
||||||
remote database (splicing `RECFLARE_D1` into the `"local"` placeholder the same way
|
|
||||||
`just deploy` does, so you don't edit any config):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
just migrate # migrate every worker that owns migrations
|
|
||||||
just migrate -F rooms # or scope to one worker
|
|
||||||
just migrate -- --local # target the local dev db instead of remote
|
|
||||||
```
|
|
||||||
|
|
||||||
This runs non-interactively (it sets `CI`), so wrangler's "database may be
|
|
||||||
unavailable during the migration" confirmation is auto-accepted — turbo can't
|
|
||||||
forward your answer to the task anyway. A backup is still captured.
|
|
||||||
|
|
||||||
_KV — two namespaces_ (`RECFLARE_MATCH_PRESENCE` for `match`/`auth`,
|
|
||||||
`RECFLARE_PLAYER_SETTINGS` for `playersettings`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wrangler kv namespace create RECFLARE_MATCH_PRESENCE
|
wrangler kv namespace create RECFLARE_MATCH_PRESENCE
|
||||||
wrangler kv namespace create RECFLARE_PLAYER_SETTINGS
|
wrangler kv namespace create RECFLARE_PLAYER_SETTINGS
|
||||||
```
|
```
|
||||||
|
|
||||||
Record both ids in `.env` as a single JSON object keyed by binding name (note the
|
Take the IDs output from the commands and put them into `.env`. (or with CI: `RECFLARE_KV='{"RECFLARE_MATCH_PRESENCE":"<id>","RECFLARE_PLAYER_SETTINGS":"<id>"}'`)
|
||||||
surrounding single quotes — without them the shell strips the inner quotes):
|
|
||||||
|
Then apply the schema. `just migrate` will set up the database and populate it with data. This runs non-interactively, so be careful!
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
RECFLARE_KV='{"RECFLARE_MATCH_PRESENCE":"<id>","RECFLARE_PLAYER_SETTINGS":"<id>"}'
|
just migrate # migrate every worker that owns migrations
|
||||||
|
just migrate -F rooms # or scope to one worker
|
||||||
```
|
```
|
||||||
|
|
||||||
_R2 — two buckets_ (`recflare-cdn` for `cdn`, `recflare-img` for `api`/`img`):
|
### R2 and Durable Objects
|
||||||
|
|
||||||
|
You only have to create the buckets:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wrangler r2 bucket create recflare-cdn
|
wrangler r2 bucket create recflare-cdn
|
||||||
wrangler r2 bucket create recflare-img
|
wrangler r2 bucket create recflare-img
|
||||||
```
|
```
|
||||||
|
|
||||||
R2 buckets are referenced by name in the committed `wrangler.jsonc`, so there is
|
### Durable Objects
|
||||||
nothing to add to `.env`. See [`apps/img/README.md`](apps/img/README.md) for
|
|
||||||
seeding the default avatar/profile images.
|
|
||||||
|
|
||||||
_Durable Objects — no manual setup_. The `notify` worker's `RECFLARE_NOTIFICATIONS_HUB`
|
Nothing manual to do here. The object is created manually.
|
||||||
binding (class `NotificationsHub`) is provisioned automatically from the migration
|
|
||||||
declared in its `wrangler.jsonc` on first deploy — there is no id to create or set.
|
|
||||||
|
|
||||||
**Run the development microservices:**
|
**Run the development microservices:**
|
||||||
|
|
||||||
> **Note:** This runs, but the name-server document still advertises the deployed
|
> **Note:** This runs, but the name-server document still advertises the deployed
|
||||||
> hosts, not your local instances — so service discovery won't resolve locally.
|
> hosts, not your local instances — so service discovery won't resolve locally.
|
||||||
> You can still call each service directly; each Wrangler instance runs on its own
|
> You can still call each service directly; each Wrangler instance runs on its own
|
||||||
> port.
|
> port. Maybe we can get this working somehow. @todo
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
just dev
|
just dev
|
||||||
@@ -250,17 +231,20 @@ just dev
|
|||||||
|
|
||||||
**Deploy all workers:**
|
**Deploy all workers:**
|
||||||
|
|
||||||
```bash
|
This will deploy all workers to respective endpoints (*.example.com)
|
||||||
just deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
Deploying requires `wrangler` to be authenticated against your Cloudflare
|
Deploying requires `wrangler` to be authenticated against your Cloudflare
|
||||||
account (`wrangler login`, or `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID`
|
account (`wrangler login`, or `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID`
|
||||||
in the environment). It also requires the storage resources to exist and their
|
in the environment).
|
||||||
ids to be set in `.env` — see **Create the storage resources** above. At deploy
|
|
||||||
time the deploy script splices `RECFLARE_D1` and `RECFLARE_KV` into the `"local"`
|
It requires the storage to be set up above, otherwise, deployments may fail.
|
||||||
placeholders in each worker's `wrangler.jsonc`; a missing id fails the deploy with
|
|
||||||
a message naming the binding.
|
You can always re-run it as often as you wish.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just deploy # for all services
|
||||||
|
just deploy -F rooms # for a single microservice
|
||||||
|
```
|
||||||
|
|
||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
@@ -308,7 +292,11 @@ See "Run the development microservices" above. It may be possible later as Wrang
|
|||||||
|
|
||||||
### Can I use this to make my own server?
|
### Can I use this to make my own server?
|
||||||
|
|
||||||
Yes, that's the point.
|
Yes, that's the point. Just set your custom domain and deploy it.
|
||||||
|
|
||||||
|
### Is there an admin panel?
|
||||||
|
|
||||||
|
Not yet. But there could be.
|
||||||
|
|
||||||
### Can I copy this project and modify it?
|
### Can I copy this project and modify it?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user