aiocoap.pipe module

class aiocoap.pipe.Pipe(request, log)

Bases: object

Low-level meeting point between a request and a any responses that come back on it.

A single request message is placed in the Pipe at creation time. Any responses, as well as any exception happening in the course of processing, are passed back to the requester along the Pipe. A response can carry an indication of whether it is final; an exception always is.

This object is used both on the client side (where the Context on behalf of the application creates a Pipe and passes it to the network transports that send the request and fill in any responses) and on the server side (where the Context creates one for an incoming request and eventually lets the server implementation populate it with responses).

This currently follows a callback dispatch style. (It may be developed into something where only awaiting a response drives the proces, though).

Currently, the requester sets up the object, connects callbacks, and then passes the Pipe on to whatever creates the response.

The creator of responses is notified by the Pipe of a loss of interest in a response when there are no more callback handlers registered by registering an on_interest_end callback. As the response callbacks need to be already in place when the Pipe is passed on to the responder, the absence event callbacks is signalled by callign the callback immediately on registration.

To accurately model “loss of interest”, it is important to use the two-phase setup of first registering actual callbacks and then producing events and/or placing on_interest_end callbacks; this is not clearly expressed in type or state yet. (One possibility would be for the Pipe to carry a preparation boolean, and which prohibits event sending during preparation and is_interest=True callback creation afterwards).

This was previously named PlumbingRequest.

Stability

Sites and resources implemented by provinding a render_to_pipe() method can stably use the add_response() method of a Pipe (or something that quacks like it).

They should not rely on add_exception() but rather just raise the exception, and neither register on_event() handlers (being the sole producer of events) nor hook to on_interest_end() (instead, they can use finally clauses or async context managers to handle any cleanup when the cancellation of the render task indicates the peer’s loss of interest).

class Event(message, exception, is_last)

Bases: tuple

exception

Alias for field number 1

is_last

Alias for field number 2

message

Alias for field number 0

poke()

Ask the responder for a life sign. It is up to the responder to ignore this (eg. because the responder is the library/application and can’t be just gone), to issue a generic transport-dependent ‘ping’ to see whether the connection is still alive, or to retransmit the request if it is an observation over an unreliable channel.

In any case, no status is reported directly to the poke, but if whatever the responder does fails, it will send an appropriate error message as a response.

on_event(callback, is_interest=True)

Call callback on any event. The callback must return True to be called again after an event. Callbacks must not produce new events or deregister unrelated event handlers.

If is_interest=False, the callback will not be counted toward the active callbacks, and will receive a (None, None, is_last=True) event eventually.

To unregister the handler, call the returned closure; this can trigger on_interest_end callbacks.

on_interest_end(callback)

Register a callback that will be called exactly once – either right now if there is not even a current indicated interest, or at a last event, or when no more interests are present

add_response(response, is_last=False)
add_exception(exception)
aiocoap.pipe.run_driving_pipe(pipe, coroutine, name=None)

Create a task from a coroutine where the end of the coroutine produces a terminal event on the pipe, and lack of interest in the pipe cancels the task.

The coroutine will typically produce output into the pipe; that connection is set up by the caller like as in run_driving_pipe(pipe, render_to(pipe)).

The create task is not returned, as the only sensible operation on it would be cancellation and that’s already set up from the pipe.

aiocoap.pipe.error_to_message(old_pr, log)

Given a pipe set up by the requester, create a new pipe to pass on to a responder.

Any exceptions produced by the responder will be turned into terminal responses on the original pipe, and loss of interest is forwarded.

class aiocoap.pipe.IterablePipe(request)

Bases: object

A stand-in for a Pipe that the requesting party can use instead. It should behave just like a Pipe to the responding party, but the caller does not register on_event handlers and instead iterates asynchronously over the events.

Note that the PR can be aitered over only once, and does not support any additional hook settings once asynchronous iteration is started; this is consistent with the usage pattern of pipes.

on_interest_end(callback)
add_response(response, is_last=False)
add_exception(exception)
class Iterator(queue, on_interest_end)

Bases: object