clog
clog copied to clipboard
Callbacks implementation
Hi,
I'm creating this pull request not so much for you to merge, but for discuss it, or discuss other options. I think I may be stretching the limits of CLOG a bit, and so I need something like this. Or I'm wrong, and there's an alternative way of doing what I need with current CLOG already.
The issue is with the integration of some javascript components, where I need to execute some arbitrary javascript on the client, following some particular JS api, and at the same time bind some function server side. So, I cannot use set-event family functions, I need to follow an api. And also I need to access arbitrary data sent from client side (and the data may be had to be extracted right from the client side event).
So I came up with this implementation of callbacks. Callback functions are defined via defcallback and then invoked from javascript via call-callback (call-callback actually generates the javascript needed to call the callback function).
For example, this is how I'm using it for a graph component I'm trying to integrate:
Define a callback function. args is an arbitrary json object sent from the client:
(clog-callbacks:defcallback graph-double-click (args)
(let* ((node-id (car (access:access args :nodes)))
(obj (nth node-id *objects*)))
(show obj)))
Generate js code following a js component api that calls the server-side callback and sends arbitrary js arguments to it:
(defun graph-set-on-double-click (graph stream)
"Handle double click events for GRAPH."
(format stream "~a.on('doubleClick', function (params) {
params.event = '[original event]';
~a
})"
(js-handle graph)
(clog-callbacks:call-callback 'graph-double-click "JSON.stringify(params)")))
Unfortunately the implementation needs to touch clog-connection::handle-message.
But let's discuss if possible.
Thank you.
Instead of defining a callback and then calling it, it is possible to do it at once just passing a lambda expression, and so the callback has access to the context in which it was created, something that is very needed, like this:
(defun graph-set-on-double-click (graph stream)
"Handle double click events for GRAPH."
(let ((callback-call (clog-callbacks:call-callback
(lambda (args)
(let* ((node-id (car (access:access args :nodes))))
(show (find node-id (graph-nodes graph) :key #'car))))
"JSON.stringify(params)"))
(js-handle (js-handle graph)))
(write-string
(interpol
"${js-handle}.on('doubleClick', function (params) {
params.event = '[original event]';
${callback-call}
})")
stream)))
One thought: if handle-message were extensible (replace the COND with a table dispatching that matches on the prefix message character). Like #\E for event. I could add #\C for callbacks to that table. And then I could plug this in without modifying Clog.
I keep getting a bit delayed and flying for next 3 days. I will take a good look and give input soon.