Chat Example

A rework in Flask of the server chat script, previously implemented in PHP.

  1. 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.
  2. The app is a Python package, in the directory msgcollect.
    1. __init__.py The initialization file is what is actually loaded when the package is, and loads other code as needed.
      1. Main thing is the app factory, a method that creates an app and sets options in one central place.
      2. Since our “views” are actually loaded by Javascript, the the factory makes a simple use of the CORS module. (See here, and below.)
      3. The two main views (and a test view) are loaded by methods from the init.
    2. Db.py
      1. This is not a view, but provides utilities for the database.
      2. The g object is sort of a per-request holding place. Keeps parallel requests from colliding.
      3. 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.
    3. 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.
    4. Poll.py
      1. 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.)
      2. The mk_poll function is called by the __init__ to set up, and the work is done by gen_poll.
      3. The view is called with a URL ending /poll?head=nnn. The head value defaults to 1.
      4. The call requests all messages starting with head, but the script limits to the ten newest.
      5. The head value is extracted from the Flask request object, and converted to integer. If a non-int is sent, this will crash.
      6. 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.
      7. Then back to SQL to get the messages to return. These are built into a Python hash and returned.
      8. When the Flask view returns a structure (instead of a string) it automatically converts to JSON, and changes the HTTP content type.
      9. The db.execute is part of the Python sqlite3 package.
        1. The db is the handle created in the db.py file.
        2. Execute returns an “iterator”, which serves to deliver the the results. The fetchone() method returns one row; there are other methods
        3. 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.
        4. Notice the Python for loop that runs through the rows to generate the return value.
    5. Add.py
      1. A view which accepts new messages to be stored on the server. Layout similar to poll.py
      2. The done method is a utility for error return.
        1. A view needs to return a Response object, and Flask returns other things to one.
        2. This one makes an explicit Response object in order to set the return type and code.
      3. It accepts URLs of the form /add?MSG=msg&NAME=name. It extracts each data value from the request object.
      4. Returns an error if there is name. (Probably should also check for empty string.)
      5. Use SQL to insert into the database.
        1. The ? in the INSERT are replaced with the data values in order. This automatically takes care of escaping the data for SQL.
        2. The cursor has a method rowcount to tell the number of rows inserted.
        3. Also cleans up old messages, but failure here is not considered an error.
  3. Origins
    1. Browsers implement a Same Origin Policy for security reasons.
    2. 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.
    3. 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.
    4. 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.