A rework in Flask of the server chat script, previously
implemented in PHP.
- The main page is HTML, mostly Javascript. It is
unchanged except the URLs for the server script.
[PageSource].
Note: Make sure your browser doesn't shift to https, where it will probably
not load the script.
- The app is a Python package, in the directory msgcollect.
- __init__.py The
initialization file is what is actually
loaded when the package is, and loads other code as needed.
- Main thing is the app factory, a method that creates an app
and sets options in one central place.
- Since our “views” are actually loaded by Javascript, the
the factory makes a simple use of the CORS module.
(See here, and below.)
- The two main views (and a test view) are loaded by
methods from the init.
- Db.py
- This is not a view, but provides utilities for the database.
- The g object is sort of a per-request holding place.
Keeps parallel requests from colliding.
- It also provides the init-db command to the flask command.
This is not called by a web page, but used by the developer to
set up or reset the database.
- Schema.sql is not a view, and not
even Python code. This the SQL that defines the table that supports
the app. Any SQL can be here, so it need not be a single table as in
this simple example.
- Poll.py
- This is a “view” which returns the messages
recently sent to, and stored by, the server script. (The name
view obviously comes from the idea that you're generating HTML to
display, which we aren't.)
- The mk_poll function is called by the __init__ to
set up, and the work is done by gen_poll.
- The view is called with a URL ending /poll?head=nnn.
The head value defaults to 1.
- The call requests all messages starting with head, but the script
limits to the ten newest.
- The head value is extracted from the Flask request object, and
converted to integer. If a non-int is sent, this will crash.
- It then uses SQL to find largest message number, then computes
lower bound to return, which is the largest of 1, the request, and
ten less than the exiting max.
- Then back to SQL to get the messages to return. These are built into
a Python hash and returned.
- When the Flask view returns a structure (instead of a string) it
automatically converts to JSON, and changes the HTTP content type.
- The db.execute is part of the Python sqlite3 package.
- The db is the handle created in the db.py file.
- Execute returns an “iterator”, which serves to deliver the
the results. The fetchone() method returns one row;
there are other methods
- The row is returned as a Python tuple. Even if there is no
data, you will get a row with None in the first position.
- Notice the Python for loop that runs through the rows to
generate the return value.
- Add.py
- A view which accepts new messages
to be stored on the server. Layout similar to poll.py
- The done method is a utility for error return.
- A view needs to return a Response object, and Flask
returns other things to one.
- This one makes an explicit Response object in order
to set the return type and code.
- It accepts URLs of the form /add?MSG=msg&NAME=name. It
extracts each data value from the request object.
- Returns an error if there is name. (Probably should also check
for empty string.)
- Use SQL to insert into the database.
- The ? in the INSERT are replaced with the data values in order.
This automatically takes care of escaping the data for SQL.
- The cursor has a method rowcount to tell the number
of rows inserted.
- Also cleans up old messages, but failure here is not
considered an error.
- Origins
- Browsers implement a
Same Origin Policy for
security reasons.
- For this app, a static HTML page posted at a different host
is not allowed to submit requests to the Flask app located
on sandbox-v01.mc.edu.
- This policy is intended to protect resources on
sandbox-v01.mc.edu from hacking by the page source.
Which seems odd, since it's the Javascript that seems the
potential threat.
A good general rule not needed here.
- That is why I used the CORS module in the Flask project.
In this simple use, it adds Access-Control-Allow-Origin: *
to each view. That allows any browser to use the service.