Open rhoot opened 11 months ago
We're talking about the client API? You can use client.write
outside of the readLoop. So you client.write
whenever you have to (outputs) and you answer messages in you handle
(inputs).
No, I've so far only looked at the server.
To give a better idea, the specific problem I'm trying to solve is where input can take a long time to produce the response for, but that should progressively return outputs as they become available. Ideally when there's no remaining output it can go back to blocking reads.
Essentially I'd want something like this in pseudo-code:
while (true) {
const use_blocking_read = !hasRemainingWork();
enqueueInputs(use_blocking_read);
if (hasRemainingWork()) {
processOutput();
}
}
But I could also imagine wanting an entirely pub/sub sort of service that parses the URL to determine what output you're interested in and then only produces output with no input. It would be useful for live metrics.
One option would be to let the app handler optionally define its own readLoop
and use that if it's defined. But there's currently details in readLoop that most implementations probably woudn't care to replicate (e.g. properly handling a close message).
The handle
callback does block the readloop, so you can block it by not returning:
pub fn handle(self: *Handler, message: Message) !void {
buildSlowResponse(message)
}
Could get fancier and use a condition variable to stop handle
from returning until the full response is sent (maybe from another thread, if that's how it's working).
That would also prevent incoming messages though, including messages to abort the previous one.
I was able to get things working without re-implementing the message handling entirely by doing this (you can ignore the whitespace differences; I ran diff
with -w
to reduce the diff size).
So before calling readMessage
it polls to see if there's any data to be read if a timeout was provided. handleNextMessage
allows implementing the readLoop
without all the message handling. So now I can do this:
pub fn readLoop(self: *Handler, conn: *websocket.Conn, reader: *websocket.Reader) !void {
while (!conn.closed) {
self.got_input = false;
const us_timeout: i32 = if (self.has_pending_output) 0 else -1;
try conn.handleNextMessage(Handler, self, reader, us_timeout);
if (self.got_input) {
continue;
}
// process stuff
}
}
pub fn handle(self: *Handler, message: websocket.Message) !void {
self.got_input = true;
// handle the message
}
I could make a PR if you think it'd be worth getting into the library? I'm not sure if there's some edge case it doesn't handle though. In particular after adding the errors (to cause the try
in readLoop
to fail and break out of the loop). The tests are passing at least.
I was hoping to use this as a simple way to handle some simple communication, but the problem is I need to be able to generate outputs without just responding to input (but still accept inputs). Unless I've missed something, that seems to not be possible with the current API?
It would be nice if I could somehow either hook into the
Conn
'sreadLoop
, or write my own loop that periodically calls into theConn
to receive incoming data.