A drop-in replacement for WebSocket using Firebase Realtime Database.
An example showing dynamically switching between FireSocket and WebSocket is in example/.
A full example is running at https://firesocketexample.appspot.com/.
server:
const express = require("express");
const ws = require("ws");
const app = express();
const wss = new ws.Server({server});
wss.on("connection", ws => ...
client:
const ws = new WebSocket(window.location.href.replace("http", "ws"));
ws.addEventListener("open", () => ...
server:
const firesocket = require("firesocket");
const express = require("express");
const app = express();
const wss = firesocket.Server.createFromCreds(databaseUrl, {app, firebaseConfig});
wss.on("connection", ws => ...
client:
const ws = new FireSocket(); // Args are ignored
ws.addEventListener("open", () => ...
- Run
npm install firesocket
- Install
firebase
cli - Set up Realtime Database security rules
- Run
firebase login
- Run
firebase init
- Create new project or use existing project created in Console
- Select Database
- For security rules, use the path
node_modules/firesocket/database.rules.json
- Don't delete the existing file
- Run
firebase deploy --only database
- Run
- Set up Authentication
- https://console.firebase.google.com/u/0/project/_/authentication
- Enable Anonymous, and/or another provider to allow for resumption of socket connection
- Set up Admin Authentication using a Service Account
- Open IAM Service accounts
- Permissing needed is "Firebase Realtime Database Admin":
roles/firebasedatabase.admin
- If running in GCP, add admin policy to your default service account
- OR
- Create new service account, name i.e. "server", give admin policy
- For non-GCP servers or local testing, create service account credentials and store it securely
gcloud iam service-accounts keys create .test-creds.json --iam-account example@example.com
- set
$env:GOOGLE_APPLICATION_CREDENTIALS=".test-creds.json"
- On the web server, change
WebSocket
toFireSocket
require("firesocket")
- (TODO split up browser part) If clients are browser-based, use
firesocket.Server.createFromCreds
factory to create Server. - The returned
FireSocket.Server
object is API-compatible withWebSocket.Server
- Download the Firebase client public JSON config for web app
- The web server is expected to serve this JSON at
/firebase-config.json
- (TODO API) the
firesocket.Server
helper will add this to your express server
- The web server is expected to serve this JSON at
- Add the script
/firesocket.js
before your web app's logic- Replace
WebSocket
withFireSocket
(constructor args are ignored) - The
FireSocket
object is API-compatible withWebSocket
- (TODO API) the
firesocket.Server
helper will serve this script
- Replace
- Basic parity with ws functionality
messagesendreadyState- open waits until server connects
close
A/B testing source compatibility between FireSocket and WebSocketServer admin authentication, supporting example server app and cliDatabase read/write limitations on user/server- Server lib for wiping some/all message state
Client authenticationwebcli
Example express server setup with HTTP serving the script filenpm limit files for pack releasebot to update dependenciesgenerate .d.ts prepack or something- set up CI/CD that builds/tests/publishes to npm
running tests in Cloud BuildSet up using separate projectLink from here to README in spec docnpm badge- build badges
Github status checks on build successhttps://medium.com/@Philmod/npm-release-automation-adb970e49066
- firebase disconnect messages using onDisconnect
- Get vs code typing for firesocket.Server working
- Any TODOs left in README
- Any TODOs left in code, maybe won't fix
- Authentication is pluggable, so app can swap in email/SMS/OAuth sign-in
- Generate type declarations instead of relying on cast to WebSocket
Run npm test
to run all tests. This includes unit tests, and mock tests using the firebase emulator and a local WebSocket server. See spec/ for more information.
The example/ can be useful for manually debugging changes.
The default client-server communication, and by far the fastest. It's pretty simple for a web game to just update state and issue questions based on player events.
Downsides:
- Cheap hosting servers don't allow many simultaneous connections, if any
- Messages are not persisted, so a server reboot will wipe out any app state
Using Firebase Realtime Database, it is possible to emulate WebSocket messages.
This fixes both limitations:
- Firebase is free for 100 connections users, with pay-as-you-go up to 200k.
- When the server restarts it can event-source state from the database
Realtime Database was picked over Firestore because the average round trip latency of 600ms is fast enough to barely be noticed by users, while Firestore is noticeably slower at 1500ms. medium.com
Guide: Info on Data Model, Auth, Queues
Each game is composed of messages from server to client, and v/v.
Each firebase client listens for child_added
on their message queue.
Here, user* is a userID from Firebase Authentication
user:
userWQ3mVT:
0: Message: Connected to Game
1: Choice: New Game, Refresh
2: Message: Cards
3: Choice: Play Copper, Buy Copper
user7f8pR:
0: Message: Connected to Game
1: Choice: New Game, Refresh, alice's game
server:
userWQ3mVT:
0: Name: alice
1: Choice: New Game
2: Start: Militia, Moat, ...
user7f8pR:
0: Name: bob
1: Choice: Refresh