firesocket
v1.0.17
Published
A drop-in replacement for WebSocket using Firebase Realtime Database
Downloads
10
Maintainers
Readme
FireSocket
A drop-in replacement for WebSocket using Firebase Realtime Database.
Examples
An example showing dynamically switching between FireSocket and WebSocket is in example/.
A full example is running at https://firesocketexample.appspot.com/.
Code changes
Before with WebSocket
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", () => ...
Using FireSocket
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", () => ...
Firebase setup
- 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 [email protected]
- set
$env:GOOGLE_APPLICATION_CREDENTIALS=".test-creds.json"
App setup
- 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
Roadmap to release 1.0
- Basic parity with ws functionality
- ~~message~~
- ~~send~~
- ~~readyState~~
- open waits until server connects
- ~~close~~
- ~~A/B testing source compatibility between FireSocket and WebSocket~~
- ~~Server admin authentication, supporting example server app and cli~~
- ~~Database read/write limitations on user/server~~
- Server lib for wiping some/all message state
- ~~Client authentication~~
- ~~web~~
- ~~cli~~
- ~~Example express server setup with HTTP serving the script file~~
- ~~npm limit files for pack release~~
- ~~bot to update dependencies~~
- ~~generate .d.ts prepack or something~~
- set up CI/CD that builds/tests/publishes to npm
- ~~running tests in Cloud Build~~
- ~~Set up using separate project~~
- ~~Link from here to README in spec doc~~
- ~~npm badge~~
- build badges
- ~~Github status checks on build success~~
- ~~https://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
Future improvements
- [ ] Authentication is pluggable, so app can swap in email/SMS/OAuth sign-in
- [ ] Generate type declarations instead of relying on cast to WebSocket
Testing
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.
Motivation for client-server communication
WebSocket
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
Firebase Database
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
Database Schema
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