Skip to content

Transport Documentation

Adam Janin edited this page May 3, 2016 · 3 revisions

Transport Example

The following is a minimal two-way chat example. In one shell, call minchat.py chat1 chat2. In another shell, call minchat.py chat2 chat1.

import sys
from nluas.Transport import Transport

myname = sys.argv[1]
remotename = sys.argv[2]

t = Transport(myname)
t.subscribe(remotename, lambda tuple: print('Got', tuple))

while True:
    t.send(remotename, input())

This code first imports the necessary package, extracts from the command line the local chat name and the name of chat you want to communicate with, and creates a Transport object. You use the name of the Transport object to communicate with it. So if there's a Transport object t1 named chat1 and it wants to send a message to a transport object t2 named chat2, it would call t1.send('chat2', 'some message').

The subscribe call is used to receive messages. It takes as arguments the name of the remote Transport you're expecting a message from, plus a function of one argument. The function gets called whenever a message from the remote Transport is sent to the local Transport. The function's single argument is a tuple of the remote message (e.g. a python string, array, or dictionary.

The loop simply repeats forever, getting a string from the user and sending it to the remote chat. Any real example should have some way of quitting cleanly.

Transport API

Constructor

Create a Transport object. Set the name of this agent to myname. Optionally set the Pyre discovery port and a prefix that gets added to all Pyre channel names. This call will also start a new thread that listens on the Pyre channels for new messages.

t = Transport(myname, port=5670, prefix='')

(Note that due to a bug in Pyre, the port currently is ignored.)

send

Send object to the agent who named itself destname. If no agent named destname is listening for messages from t.name, the call will do nothing. The object can be any python object that can be represented in JSON (e.g. lists and dicts of strings and numbers).

t.send(destname, object)

subscribe

Call callback every time an agent who named itself sourcename sends an object to t.name. The callback must take one positional argument, the object, and can optionally take a keyword argument (e.g. **kw), which will contain the name, ip address, and uuid of the sender and a time stamp (name, ip, uuid, datetime). The callback is called in the thread used to listen on the network, so it should not block or take too long to run. If you need the callback to block or run for a long time, start a new thread in the callback. There is only one callback per name; subsequent calls to subscribe with the same sourcename will raise a TransportError exception.

t.subscribe(sourcename, callback)

unsubscribe

Stop listening for messages from a Transport named sourcename.

t.unsubscribe(sourcename)

subscribe_all

Call callback every time ANY agent sends a message to t.name. The callback follows the same conventions as Transport.subscribe(). If there are both a subscribe_all(cb1) and a subscribe(sourcename, cb2) and sourcename sends an object, both cb1 and cb2 will be called. Subsequent calls to subscribe_all will raise a TransportError exception.

t.subscribe_all(callback)

unsubscribe_all

Stop listening for messages from arbitrary Transports.

t.unsubscribe_all()

get

Block waiting for a message from sourcename. Returns a python namedtuple with object (the python object sent), uuid, name, ip (uuid, name, and ip address of the sender), and datetime (a timestamp of when the message was received).

nt = t.get(sourcename)

Exceptions

Exceptions all descend from TransportError. It stores an error message string (msg) and a Transport object (transport).

TransportProtocolError is raised if unexpected or malformed messages are received by a Transport.

TransportSecurityError is raised if a message is unauthorized. Currently, this is checked only via the sender's IP address in the function Transport.is_valid_ip().

Notes on Transport

If you get a TransportSecurityError exception, it is probably because you've changed where the code is running and haven't updated Transport.is_valid_ip(). This function is used for security and may need to be updated whenever you change networks.

If you want to connect non-local networks together, you need to use a bridge. See https://github.com/icsi-berkeley/framework_code/wiki/Bridge-Documentation. This page also has information on connecting to a bridge using C++ on Windows.