Gramex 1.90 release notes

Gramex 1.90 introduces MessageHandler for live communication, WebsocketHandler arguments, lighter gramex init, and gramex features formatting.

MessageHandler for live communication

MessageHandler is a publish-subscribe queue for secure, live communication between users. It is used for chat, live commenting, and message queues via WebSockets.

MessageHandler example

The configuration is similar to FormHandler databases:

url:
  messagehandler/simple:
    pattern: /$YAMLURL/simple
    handler: MessageHandler
    kwargs:
      url: sqlite:///$YAMLPATH/messages.db
      table: simple
      columns:
        body: TEXT

This opens a WebSocket connection to /messages. You can send messages to it using:

var url = location.href.replace(/^http/, "ws").replace(/\/[^/]*$/, "/messages");
var ws = new WebSocket(url);
ws.send(JSON.stringify({ _method: "POST", body: "Hello" }));

This will insert a message into the simple table with these columns:

id user timestamp body
Xjs3k user@example.org 2023-01-02T03:04:05 Hello

id, user, timestamp are always present in the table. The rest are specified by columns: in the FormHandler columns syntax.

It also broadcasts the messages to all clients, which you can listen to on the websocket.

ws.onmessage = function (response) {
  const msg = JSON.parse(response.data);
  console.log(msg);
};

When opened, the websocket sends all past message. You can limit it with MessageHandler filters.

WebsocketHandler arguments

WebsocketHandler now supports all BaseHandler attributes, including handler.args.

Earlier, handlers.args was not available in WebsocketHandler methods. This made it hard to re-use the same Websocket for different purposes.

Now, you can use handler.args to pass arguments to WebsocketHandler methods. For example:

url:
  pingbot:
    pattern: /pingbot
    handler: WebSocketHandler
    kwargs:
      on_message:
        # On every message, reply with a prefix followed by the same message
        function: handler.write(handler.args['prefix'] + message)

Lighter gramex init

gramex init is now lighter and more modern. Specifically:

Gramex features formatting

gramex feature now accepts a --format=table|json|csv argument. For example:

$ gramex features --format=table
      type         feature  count
0       MS  CaptureHandler      1
1       MS    ComicHandler      0
2       MS     FileHandler     14
3       MS    DriveHandler      0
...

$ gramex features --format=csv
type,feature,count
MS,CaptureHandler,1
MS,ComicHandler,0
MS,FileHandler,14
MS,DriveHandler,0
...

$ gramex features --format=json
[
  {"type":"MS","feature":"CaptureHandler","count":1},
  {"type":"MS","feature":"ComicHandler","count":0},
  {"type":"MS","feature":"FileHandler","count":14},
  {"type":"MS","feature":"DriveHandler","count":0},
  ...
]

Web Crypto for hashing

Earler, Gramex auth templates used the js-sha256 library to hash passwords.

But thanks to the popularity of the Web Crypto API in browsers, the default auth template uses crypto.subtle.digest("SHA-256", msg) to hash passwords. This is faster and more secure.

Backward-incompatible changes

FunctionHandler output automatically serializes data. For example, Pandas DataFrames are converted into JSON as an array of objects.

The behavior for Pandas Series was not documented, but it was returned as a list of values.

For example, this FunctionHandler:

url:
  series:
    pattern: /series
    handler: FunctionHandler
    kwargs:
      function: 'pd.Series({"x": 1, "y": 2, "z": 3}'

… would return:

[1, 2, 3]

Now, FunctionHandler returns Pandas Series as an {index: value} object. This preserves the index, which is often useful for a series. (The index remains ignored for DataFrames.)

{ "x": 1, "y": 2, "z": 3 }

Backward compatibility & security

Gramex 1.90 is backward compatible with previous releases unless the release notes say otherwise. We ensure this with automated tests.

Every Gramex release is tested for security vulnerabilities using the following tools.

  1. Bandit tests for back-end Python vulnerabilities. See Bandit results
  2. npm-audit tests for front-end JavaScript vulnerabilities. See npm-audit results
  3. Snyk for front-end and back-end vulnerabilities. See Synk results
  4. ClamAV for anti-virus scans. See ClamAV results
  5. Trivy for container scans. See Trivy results

Statistics

The Gramex code base has:

type,loc Python,22608 JavaScript,3552 Tests,15382

How to install

See the Gramex installation and upgrade instructions.