This application demonstrates the use of Fastly Fanout in a simple web chat app that uses EventStream.
A live instance of this demo can be found at fanout-chat-demo.edgecompute.app.
To enable realtime updates, Fastly Fanout is positioned as a GRIP (Generic Realtime Intermediary Protocol) proxy. Responses for streaming requests are held open by Fanout. Then, as updates become ready, the backend application publishes these updates through Fanout to all connected clients. For details on this mechanism, see Real-time Updates below.
The project comprises two main parts:
-
A web application. The backend for this web application is written in Python. It uses the Django framework and uses SQLite to maintain a small database. The frontend for this web application is a standard HTML application that uses jQuery. The files that compose the frontend are served by the backend as static files.
-
An edge application. A Fastly Compute application that passes traffic through to the web application, and activates the Fanout feature for relevant requests.
The live instance's backend runs on Glitch, and the project can be viewed here: https://glitch.com/~fanout-chat-demo.
The live instance's edge application is at fanout-chat-demo.edgecompute.app. It is configured with the above Glitch application as the backend, and the service has the Fanout feature enabled.
Though the project is designed with Glitch and Fastly in mind, it's possible to run it locally for development.
You will need:
- Python - 3.7 or newer
- Pushpin - This open source GRIP proxy implementation can take the place of Fanout during development.
Preparation:
-
Configure Pushpin using
localhost:3000by modifying theroutesfile. For example, on a default macOS installation, set the contents of/opt/homebrew/etc/pushpin/routes:* localhost:3000 -
Setup virtualenv, install Python dependencies, create empty environment config, and set up the database.
virtualenv --python=python3 venv . venv/bin/activate pip install -r requirements.txt touch .env python manage.py migrate
To start the application:
python manage.py runserver 3000Now, browse to your application at http://localhost:7999/.
To run in production, you will need a Fastly Compute service with Fanout enabled.
You will also need to run the server application on an origin server that is visible from the internet.
This application is written with Glitch in mind.
NOTE: If you are using Glitch, consider boosting your app so that it doesn't go to sleep.
-
Create a new project on Glitch and import this GitHub repository. Note the public URL of your project, which typically has the domain name
https://<project-name>.glitch.me. -
Set up the environment. In the Glitch interface, modify
.envand set the following values:-
GRIP_URL:https://api.fastly.com/service/<service-id>?verify-iss=fastly:<service-id>&key=<api-token>Replace
<service-id>with your Fastly service ID, and<api-token>with an API token for your service that hasglobalscope. -
GRIP_VERIFY_KEY:base64:LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFQ0tvNUExZWJ5RmNubVZWOFNFNU9uKzhHODFKeQpCalN2Y3J4NFZMZXRXQ2p1REFtcHBUbzN4TS96ejc2M0NPVENnSGZwLzZsUGRDeVlqanFjK0dNN3N3PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t(*)(*) This is a base64-encoded version of the public key published at Validating GRIP requests on the Fastly Developer Hub.
-
DJANGO_SECRET_KEY: Django uses a secret key to provide cryptographic signing. Set a unique, unpredictable value.See SECRET_KEY in the Django documentation for more details.
-
-
Glitch will find the
glitch.jsonfile and automatically install the dependencies and start your application. -
Set up the edge application on your Fastly account, and set your Glitch application as a backend for it using the name
origin. See the edge application's README.md file for details. -
Browse to your application at the public URL of your Edge application.
This application is written with Glitch in mind, but you can alternatively use any Python server that is visible from the internet.
-
Clone this repository to a new directory on your Python server.
-
Switch to the directory, install dependencies, create the environment file, and set up the database:
pip3 install -r requirements.txt touch .env python3 manage.py migrate -
Set the following environment variables. Modify
.envand set the following values:-
GRIP_URL:https://api.fastly.com/service/<service-id>?verify-iss=fastly:<service-id>&key=<api-token>Replace
<service-id>with your Fastly service ID, and<api-token>with an API token for your service that hasglobalscope. -
GRIP_VERIFY_KEY:base64:LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFQ0tvNUExZWJ5RmNubVZWOFNFNU9uKzhHODFKeQpCalN2Y3J4NFZMZXRXQ2p1REFtcHBUbzN4TS96ejc2M0NPVENnSGZwLzZsUGRDeVlqanFjK0dNN3N3PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t(*)(*) This is a base64-encoded version of the public key published at Validating GRIP requests on the Fastly Developer Hub.
-
DJANGO_SECRET_KEY: Django uses a secret key to provide cryptographic signing. Set a unique, unpredictable value.See SECRET_KEY in the Django documentation for more details.
-
-
Start your application:
python manage.py runserver -
Set up the edge application on your Fastly account, and set your Python application as a backend for it using the name
origin. See the edge application's README.md file for details. -
Browse to your application at the public URL of your Edge application.
It's also possible to run in production using your own instance of Pushpin. The details are beyond the scope of this document, but here are some pointers:
- Configure Pushpin to proxy to your instance of the server application
- Then set your
GRIP_URLto point to your Pushpin instance
For more details, see Pushpin Configuration.
This program can be configured using two environment variables:
GRIP_URL- a URL used to publish messages through a GRIP proxy. The default value ishttp://127.0.0.1:5561/, a value that can be used in development to publish to Pushpin.GRIP_VERIFY_KEY- (optional) a string that can be used to configure theverify-keycomponent ofGRIP_URL. See Configuration of js-serve-grip for details.
GET /rooms/{room-id}/messages/Params: (None)
Returns: JSON object, with fields:
messages: list of the most recent messages, in time descending orderlast-event-id: last event ID (use this when listening for events)
POST /rooms/{room-id}/messages/Params:
from={string}: the name of the user sending the messagetext={string}: the content of the message
Returns: JSON object of message
GET /rooms/{room-id}/events/Params:
lastEventId: event ID to start reading from (optional)
Returns: SSE stream
The /rooms/{room-id}/events/ endpoint uses django-eventstream to
use GRIP to serve updated data to clients.
If you encounter any non-security-related bug or unexpected behavior, please file an issue using the bug report template.
Please see our SECURITY.md for guidance on reporting security-related issues.
MIT.