Commit graph

149 commits

Author SHA1 Message Date
Nathaniel Nicandro
f6a3690c59 Add some debug statements 2017-12-27 00:12:39 -06:00
Nathaniel Nicandro
d28dc7a3af Add a sentinel to the client's ioloop 2017-12-27 00:00:59 -06:00
Nathaniel Nicandro
5b2afb3ea0 [WIP] Kernel manager 2017-12-22 00:50:56 -06:00
Nathaniel Nicandro
b82665f889 Collect messages from kernel before sending to parent process
Instead of directly sending every received message to the parent emacs process
at the moment we receive it. The messages are stored in a queue. Only when we
do not receive a message from the kernel for two polling periods or when the
queue is full will the messages be sent to the parent process. When the
messages are sent, they are first sorted by their timestamp and prioritized
based on channel.
2017-12-21 18:20:35 -06:00
Nathaniel Nicandro
e0b5da2580 Just silently drop messages received that were not requested by us 2017-12-21 18:13:49 -06:00
Nathaniel Nicandro
5f5a742d3d Slots for a jupyter-kernel-client are always bound 2017-12-21 18:12:25 -06:00
Nathaniel Nicandro
df193db165 Remove message-callbacks 2017-12-19 21:54:11 -06:00
Nathaniel Nicandro
1848cc256a Properly cleanup ioloop subprocess
Also wrap loops that wait for subprocess output with timeouts
2017-12-19 18:47:57 -06:00
Nathaniel Nicandro
94636454c0 Use accept-process-output when waiting 2017-12-19 18:16:58 -06:00
Nathaniel Nicandro
cd158b2de6 Fix indentation 2017-12-19 18:13:42 -06:00
Nathaniel Nicandro
0f84618914 Introduce jupyter-request and jupyter-callback types
`jupyter-request` encapsulates a request ID, request callbacks, and a flag
variable which tells you if the kernel has sent an idle message for this
request.

`jupyter-callback` encapsulates a callback function and a flag variable
determining if the callback has run at least once. The `callbacks` field of a
`jupyter-request` is an alist mapping reply types to `jupyter-callback`
objects.

Whenever a message is sent to the kernel a new `jupyter-request` object is
created and returned from one of the `jupyter-request-*` methods. This object
holds all the required information to track a message that the kernel is
handling. When a message is received from the kernel, the client checks its
`requests` hash table for the `jupyter-request` object associated with the
message and runs any callbacks for the message and updates the flag variables
of the request and callback if necessary.

The request is considered complete and removed from the `requests` hash table
when an idle message has been received for the request and all callbacks have
run at least once. Note that this is almost surely does not handle all cases
since there may be situations where you would like a callback to run multiple
times while an idle message has already been sent.
2017-12-19 18:13:16 -06:00
Nathaniel Nicandro
3b7b6efaaa Take into account the status field of an is_complete_reply 2017-12-19 11:55:07 -06:00
Nathaniel Nicandro
a52ab008ed Properly handle shutdown messages 2017-12-19 11:54:10 -06:00
Nathaniel Nicandro
09aa179636 Implement starting/stopping channels in ioloop subprocess 2017-12-19 11:50:50 -06:00
Nathaniel Nicandro
29cd9912f0 Fix typo 2017-12-17 02:58:11 -06:00
Nathaniel Nicandro
c04998677c Implement callback which fires for all messages associated with a request
If `t` is passed as the `MSG-TYPE` argument of `jupyter-add-receive-callback`,
then it signifies that the associated callback will run for every message that
is received in response to a request.
2017-12-17 02:53:31 -06:00
Nathaniel Nicandro
1e246ee480 [WIP] Move all socket communication to a subprocess
With this new implementation, all communication between the kernel and the
client happens in a subprocess. When the client would like to send a message,
the parent emacs process generates the required plist and sends it to the
subprocess for encoding and sending to the kernel. When a message is received,
the subprocess decodes it and prints it to the pipe for the parent emacs
process to read.

This implementation also introduces the use of futures to avoid having to wait
for subprocess output when sending a message to the kernel. Every
`jupyter-request-*` function now returns a primitive future object which is
just a cons cell with the `car` equal to `:jupyter-future`. When the `cdr` of
the future is non-nil, then it is the message ID of the sent request. This acts
as a check to ensure that the message ID is available from the future object,
if the `cdr` is nil the ID is not available, but if the `cdr` is non-nil then
it is the message ID. The convenience function `jupyter-ensure-id` ensures that
the message ID is available and returns the ID.

The future acts as a stand in for the message ID of the encoded request which
will be retrieved from the subprocess once the message has been encoded and
sent to the kernel. This future object is meant to be passed to
`jupyter-add-receive-callback` and other related functions the same way as an
actual message id.
2017-12-17 02:53:15 -06:00
Nathaniel Nicandro
f5afa2ef07 Minor style and documentation changes 2017-12-16 19:02:11 -06:00
Nathaniel Nicandro
80de6579fa Stick to using timers instead of a polling subprocess
I believe I was misunderstanding the use of `zmq-poll` on the file descriptors
in a subprocess. It seems that polling the file descriptors doesn't seem to
work.

Currently I am sticking to running periodic timers in emacs itself to process
messages. This may slow down emacs when connecting to lots of clients that are
receiving and sending lots of messages.

What I would like to move towards is having a subprocess which connects to the
required endpoints and listens for incoming messages. When a message arrives,
it decodes it and sends it back to the parent emacs process. When I would like
to send a message, I just send the raw plist to the subprocess and it encodes
and sends it through the socket. So the subprocess will take care of
encoding/decoding messages and sending/receiving messages on sockets. Whereas
the parent emacs process will send/receive plists.
2017-12-16 18:54:40 -06:00
Nathaniel Nicandro
4f1e466754 Remove unnecessary lexical-let 2017-12-15 22:40:31 -06:00
Nathaniel Nicandro
76de6a8b4a Ensure kernel connection file is finished writing before reading from it 2017-12-15 22:37:59 -06:00
Nathaniel Nicandro
ab2931beb6 Remove comment
The problem appears to be that I was not waiting until the kernel was finished
handshaking with the `jupyter console` application. Kernels are currently
started using the `jupyter console` command which was causing messages not to
be received by `jupyter-kernel-client`
2017-12-15 22:34:17 -06:00
Nathaniel Nicandro
f599ea7486 Some re-organization of code 2017-12-15 22:33:56 -06:00
Nathaniel Nicandro
1f3e9fad67 Don't type check in private functions 2017-12-15 22:33:18 -06:00
Nathaniel Nicandro
72095237f8 Remove callbacks from callback table when status is idle
The jupyter v5.0 protocol specifies that for every request that is handled, a status: idle message will be sent when the request is complete. When receiving this idle message is when callbacks are removed from the table.
2017-12-15 22:26:21 -06:00
Nathaniel Nicandro
98875e2ba4 jupyter--process-message -> jupyter--handle-message
Also more documentation for what it means to handle a message.
2017-12-15 22:24:00 -06:00
Nathaniel Nicandro
0e550f8ceb Code re-organization 2017-12-15 18:21:54 -06:00
Nathaniel Nicandro
903133b7f8 Rename jupyter--ioloop-callback to jupyter--queue-message 2017-12-15 18:19:45 -06:00
Nathaniel Nicandro
d35029ac35 Generalize waiting for message replies 2017-12-15 18:18:41 -06:00
Nathaniel Nicandro
ad53e098f6 Move jupyter--received-message-types to jupyter-messages.el
Also fix naming issue, previously `recieved` when it should have been `received`.
2017-12-15 18:16:53 -06:00
Nathaniel Nicandro
b4f0c94906 Also start the control channel 2017-12-15 18:14:43 -06:00
Nathaniel Nicandro
70712b9229 More documentation 2017-12-15 18:14:28 -06:00
Nathaniel Nicandro
1146c1b6c4 Don't do type checking for internal functions 2017-12-15 18:12:26 -06:00
Nathaniel Nicandro
8f949059b7 Remove debugging code 2017-12-14 14:14:00 -06:00
Nathaniel Nicandro
7eeef3f6c0 Better commentary 2017-12-14 14:11:42 -06:00
Nathaniel Nicandro
973024906c jupyter-send-* -> jupyter-request-*
I think it makes more sense to prefix with `request` instead of send`. Since
`jupyter-send-execute` seems ambiguous unless you say something like
`jupyter-send-execute-request`. But if you say `jupyter-request-execute` it has
essentially the same meaning as `jupyter-send-execute-request` with the extra
word. It also works better for functions like `jupyter-request-kernel-info` as
opposed to `jupyter-send-kernel-info` which seems to imply that you are sending
the kernel info.
2017-12-14 14:07:21 -06:00
Nathaniel Nicandro
ec43c2666c Remove debugging statement 2017-12-14 14:05:01 -06:00
Nathaniel Nicandro
5bdd4592dc Reply message dispatchers are private 2017-12-14 14:03:58 -06:00
Nathaniel Nicandro
3a3e742f8a Silence byte compiler 2017-12-14 13:58:46 -06:00
Nathaniel Nicandro
fe13c02e42 Default message handlers don't do anything 2017-12-14 13:58:46 -06:00
Nathaniel Nicandro
e59086cad6 Also check control channel 2017-12-14 13:58:45 -06:00
Nathaniel Nicandro
aa6bb20f3a Update commentary 2017-12-14 13:58:38 -06:00
Nathaniel Nicandro
9e422743ec Add some protection against misspelled received message types when adding callbacks 2017-12-14 13:53:52 -06:00
Nathaniel Nicandro
5093759aa9 Handle all possible message types
- All messages sent are prefixed like `jupyter-send-*`. So that an
  `execute_request` maps to `jupyter-send-execute`.

- All received message handlers are prefixed with `jupyter-handle-*`. So that
  an `execute_reply` message would be mapped to `jupyter-handle-execute`. Also
  for IOPub messages, the handlers are also prefixed with
  `jupyter-handle-<iopub message type>` so that a `stream` message would map to
  `jupyter-handle-stream`.
2017-12-14 13:53:52 -06:00
Nathaniel Nicandro
78fca10b67 Handle control messages 2017-12-14 13:53:52 -06:00
Nathaniel Nicandro
bab7305cc8 Mark functions as private 2017-12-14 13:53:48 -06:00
Nathaniel Nicandro
05f3fd0032 Don't query when killing kernels created in jupyter-kernel-client-using-kernel 2017-12-14 13:23:40 -06:00
Nathaniel Nicandro
c3ce229961 Correctly append to callback list 2017-12-14 13:23:04 -06:00
Nathaniel Nicandro
76cf1c5eb7 Semi working prototype 2017-12-13 11:27:13 -06:00