[ ] Need to be improved farther in the future: using config files for our settings (e.g. the serial port) instead of hard-coding them into attr.ib classes. We'll need this when we shift to connecting over UART wires rather than USB
[ ] Delete io._serial.find_port, it's not needed
[ ] io.trio._channel: needs code comments explaining why this class exists
[ ] io.trio._serial: needs code comments about receive_some's use of max_bytes, and why we need lowlevel.wait_readable
[ ] io.trio.rotaryencoder: how much of the internal state can we refactor out to make it easier to understand? Can we unify the quad_rise callbacks? Can we unify the quad_fall callbacks?
[ ] io.trio.rotaryencoder: close method should clear all the callbacks, or deactivate the pigpio thread, or clean up after the open() method call (but it seems like we're never calling the close methods in ventserver.application)
[ ] io.trio.fileio: rootdir should be set from environment variable so that we can save states to the USB drive in deployment; _connected should just be a boolean, not a trio.Event; maybe we should just always append the ".pb" extension to the filename; and the file extension should be an attr.ib on the class
[ ] io.trio.fileio: instead of calling os.mkdir, we should call the trio equivalent; remove "# type: ignore" comments; need to research performance and fault-tolerance properties of opening a bunch of files and keeping them open, vs. opening and closing each file each time we want to write to it, and then update the I/O endpoint interface and usage accordingly
[ ] io.trio.fileio: close all the I/O endpoints once we're done, e.g. at the end of the main() function
[ ] io.trio.fileio: reduce the File I/O Endpoint to just a File Writer I/O Endpoint, since we only need to write files during the main loop. At the start of the program we can just use trio's open_file method to read the contents of files to load as protobufs into memory
[ ] io.trio.websocket: should we increase the message queue size so that the backend can keep doing work even if the frontend freezes temporarily?
[ ] io.trio.websocket: Instead of SingleConnectionService having a server as a member object, we should just use the Server directly and give it a SingleConnectionPolicy or SingleConnectionStrategy object; the server delegates its behavior to the Connection policy/strategy object/function, just like how right now it's delegating its behavior to the request_handler attr.ib. Similarly, SingleConnectionService should delegate the connection handling to a Connection behavior object/function
[ ] io.trio.websocket: Driver blocks open() until a connection is received; should integration._trio block other work until the websocket Driver finishes the open() method?
[ ] io.trio.websocket: have a attr.ib flag on the Driver which specifies a timeout for sending a websocket message; add a timeout in the Driver.send method to cancel the message send operation and log a warning after a timeout (e.g. because the frontend is temporarily frozen); then we don't have to worry about backpressure from the frontend onto the backend's work, since the application protocol is already robust to dropped messages
[ ] io.trio.fileio should also have a timeout cancellation on file writing operations (where failure is logged as an error) to avoid causing backpressure on backend processing
[ ] Need plenty of code comments on everything related to buffers and backpressure! Explain our strategy, which is: if the other end of a connection is stuck, then we drop the data instead of propagating backpressure. This allows us to avoid unbounded buffer growth, and our communication protocol is already designed for connections where messages can be dropped