-
Notifications
You must be signed in to change notification settings - Fork 2
Flask server and UI
python3 server.py
python3 Shepherd.py
python3 YDL.py
Shepherd and YDL aren't strictly necessary if you just want to test html/css/js changes. The Flask stuff is run by server.py
.
Great question! Flask is a Python web framework; basically a server with some spicy bits. We mostly use it to serve html pages from a Python server, and have those pages communicate with our Python code using Flask-SocketIO. Here are the official docs:
- https://flask-socketio.readthedocs.io/en/latest/
- https://socket.io/docs/
- https://flask.palletsprojects.com/en/2.0.x/tutorial/index.html (good tutorial)
Our Flask server, server.py
, will serve pages from the shepherd/templates
folder; these templates may pull in resources from the shepherd/static
folder.
First, make sure to add the new page to the UI_PAGES
dictionary in Utils.py
. Otherwise server.py
won't know that the page exists.
If you want to extend the base template (comes with a navbar and logging for websocket messages), start with this:
{% extends 'base.html' %}
{% block head_content %}
<title>Example Title</title>
<style>
/* you can delete this element, or add page-specific style rules*/
</style>
<script>
// this function is called when the page is loaded, from base.html
// socket: the main socketio websocket
// send: a function that sends a header through the socket, and also logs it
function main_js_content(socket, send) {
//add socket listeners and javascript stuff here
}
</script>
{% endblock %}
{% block html_content %}
<!-- add html content here -->
{% endblock %}
Note that if you want to include this page in the navbar, you should add it to the navbar in base.html
.
If you do not want to extend the base template, but you still want to send messages to Shepherd, make sure to send messages with the following format:
socket.emit("ui-to-server", getCookie("password"), shepherd_header, json_string)
where json_string is optional.
In Shepherd.py
, messages typically should be sent with ydl_send
to the UI target. For example:
ydl_send(YDL_TARGETS.UI, UI_HEADER.CHEESE, {"cheese_type": "mozzarella"})
This will be forwarded through YDL to server.py, which will forward it through a websocket to all currently open UI pages. It can then be read by javascript code like:
socket.on('cheese', function (data) { // note that 'cheese' has to match UI_HEADER.CHEESE
data = JSON.parse(data);
let cheese_type = data.cheese_type;
...
});
In the other direction, javascript code should typically use the send()
function provided by base.html
. For example:
send('pizza', JSON.stringify({"toppings": "extra cheese"}));
This will be forwarded through a websocket to server.py, which will forward it through YDL to Shepherd.py
. Note that the header "pizza" must be included in Utils.py
as SHEPHERD_HEADER.PIZZA
or something similar. Then, if SHEPHERD_HEADER.PIZZA
is included in the function mappings, it can be handled like:
def receive_pizza(args):
toppings = args["toppings"]
...
Summary:
Here are the steps that need to be done to add a message from Shepherd -> frontend:
- add the header to
Utils.py
, underUI_HEADER
- add
socket.on
listener to frontend - add
ydl_send
call toShepherd.py
Here are the steps that need to be done to add a message from frontend -> Shepherd:
- add the header to
Utils.py
, underSHEPHERD_HEADER
- add the header to the relevant mapping(s) in
Shepherd.py
(i.e. EVERYWHERE_FUNCTIONS dictionary) - add listening function to
Shepherd.py
- add
send
call to frontend.
The password protection exists so that "sensitive" pages (like the match controls) can be served from the same server as pages that students are free to access.
The current implementation is that the password stored in a cookie with the name "password"; attempting to access a sensitive page without the cookie set will cause server.py
to serve password.html
instead. server.py
should also reject any websocket messages that don't include the correct password.
The password should never be written in plain text anywhere in the Shepherd repo; pass it by word-of-mouth, or by Slack. If you want to change the password, change the hash string in server.py
.