mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -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
|
||||
Cloudflare Workers. It implements the network services the Rec Room client talks
|
||||
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
|
||||
> 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?
|
||||
|
||||
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.
|
||||
4. "Upgrading the server" is not sustainable plan for growth.
|
||||
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
|
||||
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
|
||||
|
||||
@@ -105,40 +109,54 @@ apex/`ns` host and isn't listed within it. Each implemented worker has its own
|
||||
|
||||
## Why Cloudflare?
|
||||
|
||||
- **It's free to run a lot of services.** 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.
|
||||
- **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,
|
||||
- **Makes it easy to mirror RecNet**
|
||||
Rec Room's backend is (was) a set of independent microservices, not one big monolith.
|
||||
Modeling each service as its own isolated Worker keeps RecFlare's structure close to
|
||||
the real thing — services scale,
|
||||
fail, and deploy independently — instead of collapsing everything into a single
|
||||
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?
|
||||
|
||||
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 —
|
||||
AWS (Lambda), Vercel, Netlify, Fly.io, a plain Node/Bun server, and so on.
|
||||
|
||||
**However**
|
||||
|
||||
The catch is everything _around_ the code. RecFlare leans on Cloudflare for the
|
||||
deployment and infrastructure layer — custom-domain routing per service, plus the
|
||||
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
|
||||
storage bindings (D1, KV, R2, Durable Objects) the workers use. On another
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
- node (modern)
|
||||
- pnpm
|
||||
- bun
|
||||
- jq
|
||||
- A Cloudflare account with a zone (domain) you control, for deploying
|
||||
- jq/awk/sed
|
||||
- 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
|
||||
Rec Room client is pretty chatty. Frequent testing may exhaust that quota.
|
||||
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. The $5/month
|
||||
Worker plan includes 10M/month.
|
||||
|
||||
See https://developers.cloudflare.com/workers/platform/pricing/#workers
|
||||
|
||||
@@ -152,97 +170,60 @@ just install
|
||||
|
||||
**Configure your custom domain:**
|
||||
|
||||
Create a new .env file:
|
||||
Create a new .env file from the template:
|
||||
|
||||
```bash
|
||||
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
|
||||
export RECFLARE_DOMAIN=rec.example.com
|
||||
```
|
||||
|
||||
`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"}'`).
|
||||
(Optional) - per-app subdomain overrides come from
|
||||
`RECFLARE_SUBDOMAINS` (a JSON object, e.g. `'{"playersettings":"settings"}'`). This would be used
|
||||
if you wanted to merge two services together.
|
||||
|
||||
**Create the storage resources:**
|
||||
|
||||
The workers bind Cloudflare storage primitives — one shared D1 database, two KV
|
||||
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`
|
||||
files carry `"local"` placeholders; the real ids are spliced in at deploy time, so
|
||||
The workers bind Cloudflare storage primitive. Create them once against your
|
||||
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
|
||||
nothing in version control needs editing. Authenticate wrangler first
|
||||
(`wrangler login`).
|
||||
|
||||
_D1 — one shared `recflare` database_ (bound by `api`, `accounts`, `auth`, `match`,
|
||||
`rooms`):
|
||||
|
||||
```bash
|
||||
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_PLAYER_SETTINGS
|
||||
```
|
||||
|
||||
Record both ids in `.env` as a single JSON object keyed by binding name (note the
|
||||
surrounding single quotes — without them the shell strips the inner quotes):
|
||||
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>"}'`)
|
||||
|
||||
Then apply the schema. `just migrate` will set up the database and populate it with data. This runs non-interactively, so be careful!
|
||||
|
||||
```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
|
||||
wrangler r2 bucket create recflare-cdn
|
||||
wrangler r2 bucket create recflare-img
|
||||
```
|
||||
|
||||
R2 buckets are referenced by name in the committed `wrangler.jsonc`, so there is
|
||||
nothing to add to `.env`. See [`apps/img/README.md`](apps/img/README.md) for
|
||||
seeding the default avatar/profile images.
|
||||
### Durable Objects
|
||||
|
||||
_Durable Objects — no manual setup_. The `notify` worker's `RECFLARE_NOTIFICATIONS_HUB`
|
||||
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.
|
||||
Nothing manual to do here. The object is created manually.
|
||||
|
||||
**Run the development microservices:**
|
||||
|
||||
> **Note:** This runs, but the name-server document still advertises the deployed
|
||||
> 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
|
||||
> port.
|
||||
> port. Maybe we can get this working somehow. @todo
|
||||
|
||||
```bash
|
||||
just dev
|
||||
@@ -250,17 +231,20 @@ just dev
|
||||
|
||||
**Deploy all workers:**
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
This will deploy all workers to respective endpoints (*.example.com)
|
||||
|
||||
Deploying requires `wrangler` to be authenticated against your Cloudflare
|
||||
account (`wrangler login`, or `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID`
|
||||
in the environment). It also requires the storage resources to exist and their
|
||||
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"`
|
||||
placeholders in each worker's `wrangler.jsonc`; a missing id fails the deploy with
|
||||
a message naming the binding.
|
||||
in the environment).
|
||||
|
||||
It requires the storage to be set up above, otherwise, deployments may fail.
|
||||
|
||||
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
|
||||
|
||||
@@ -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?
|
||||
|
||||
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?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user