Python Gateway

Introduction

This Python package provides a Gateway class to interact with the fjåge agents. The fjåge agents reside in one or more containers that provide agent management, directory and messaging services. Various containers may run on the same node or on different nodes in a network. This Python Gateway class allows the external Python scripts to interact with fjåge agents using an interface implemented in Python. The Python APIs use the package fjagepy.

The first step is to install the fjagepy package using:

pip install fjagepy

Import all the necessary symbols from fjagepy package:

from fjagepy import Gateway, AgentID, Message, MessageClass, GenericMessage, Performative

or just:

from fjagepy import *

Import message classes

Since the Java/Groovy message classes are not directly available in Python, we use the MessageClass utility to dynamically create specified message classes. An example of such is shown:

ShellExecReq = MessageClass('org.arl.fjage.shell.ShellExecReq')

The ShellExecReq class can now be used to instantiate new objects like:

msg = ShellExecReq()

The fully qualified class name as a string must be provided as an argument to this method. The fully qualified class names that are already supported by fjåge are documented here.

Open a connection

If a fjage server is running, we can create a connection using Gateway class:

gw = Gateway(hostname, port)

where hostname and port is the IP address and the port number of the device on which the fjåge server is running. The gw object is created which can be used to call the methods of Gateway class.

Send and receive messages

We have seen earlier that the agents interact with each other using messages. The python gateway can similarly send and receive messages to the agents running on containers running on diffeent machines. An example of request and response message are as shown below:

Request message:

msg = Message()
msg.recipient = abc
gw.send(msg)

where abc is the AgentID of the agent you are trying to send the message to.

Another alternative to send a message is following:

msg = Message(recipient = abc)
rsp = gw.request(msg, timeout)

In the above code snippet, a request method is used to send a message and receive the response back. Different responses that can be received are documented here.

msg is an instance of Message class and in the ablove example, the intended recipient is set to the AgentID abc. The constructed message msg is sent to the agents running on master container using gw.send(msg).

A simple example of executing a shell command from remote connection opened using Gateway class is as shown below:

gw = Gateway(hostname, port)
ShellExecReq = MessageClass('org.arl.fjage.shell.ShellExecReq')
shell = gw.agentForService('org.arl.fjage.shell.Services.SHELL')
req = ShellExecReq(recipient=shell, cmd = 'ps')
rsp = gw.request(req, 1000)
print(rsp)
gw.close()

In the code above, we first open a connection to the fjåge server. Next, we import the ShellExecReq message that we will require later. We want to send this message to an agent which supports the SHELL service (honoring the ShellExecReq messages). The agentForService method of the Gateway class allows us to look up that agent. Next, we construct the ShellExecReq message to request execution of a shell command (in this case ps). The request method then sends the message and waits for a response, which we then print and close the connection.

Generic messages

As the use case of GenericMessage is already explained before, we will illustrate it’s use using the Python gateway API:

gw = Gateway(hostname, port)
shell = gw.agentForService('org.arl.fjage.shell.Services.SHELL')
gmsg = GenericMessage(recipient=shell, text='hello', data=np.random.randint(0,9,(100)))
gw.send(gmsg)

The shell agent running on the server side will receive this generic message sent through gateway:

rgmsg = receive(GenericMessage, 1000)
println rgmsg.text
println rgmsg.data

Publish and subscribe

We know that there are times when we may want to publish a message without explicitly knowing who the recipients are. All agents subscribing to the topic that we publish on would then receive the published message. For example:

gw.topic('abc')

returns an object representing the named topic. A user can subscribe to this topic using:

gw.subscribe(gw.topic('abc'))

But if we are interested in receiving all the messages sent from a particular agent whose AgentID we know (for example shell), then:

shell = gw.agentForService('org.arl.fjage.shell.Services.SHELL')
gw.subscribe(shell)

will allow to receive the published messages by shell agent.

Close a connection:

In order to close the connection to the fjåge server, we can call the close method provided by the Gateway class:

gw.close()