Tutorial

Getting Started

Installing RSB

There are currently two ways to install RSB:

  • From source
  • Debian Packages

Debian Packages

Debian packages for several versions of Ubuntu Linux are available from the CoR-Lab package repository. Repository source line:

deb http://packages.cor-lab.de/ubuntu/ RELEASENAME testing

Usage instructions can be found in the wiki.

Running the Examples

Basic Communication

Creating an Informer and Sending Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from rsb import createInformer, Scope

if __name__ == '__main__':

    # create an informer for strings on scope "/example/informer".
    informer = createInformer(Scope("/example/informer"), dataType=str)
    
    print("Informer setup finished")
    
    # send some events using a method that directly accepts data
    for i in range(1200):
        informer.publishData("a test string")
        
    print("Sent events, exiting")

Creating a Listener and Receiving Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from rsb import createListener, Scope
import time

def handle(event):
    print("Received event: %s" % event)

if __name__ == '__main__':
    
    # create a listener on the specified scope. The listener will dispatch all
    # received events asynchronously to all registered listeners
    listener = createListener(Scope("/example/informer"))
    
    # add a handler to handle received events. In python, handlers are callable
    # objects with the event as the single argument
    listener.addHandler(handle)
    
    print("Listener setup finished")
    
    # wait endlessly for received events
    while True:
        time.sleep(100)

RPC Communication

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from rsb import Scope, createRemoteServer;

if __name__ == "__main__":

    # Create a RemoteServer object for the remote server at scope
    # /example/server. Method calls should complete within five
    # seconds.
    server = createRemoteServer(Scope('/example/server'))

    # Call the method 'methodOne' on the remote server passing it a
    # string argument. The server's reply is returned from the call as
    # for a regular function call.
    print 'server replied to synchronous call: "%s"' % server.echo('bla')

    # Call the method 'methodOne' again, this time asynchronously.
    future = server.echo.async('bla')
    # do other things
    print 'server replied to asynchronous call: "%s"' % future.get(timeout = 10)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from time import sleep

from rsb import Scope, createServer

if __name__ == '__main__':

    # Create a LocalServer object that exposes its methods under the
    # scope /example/server.
    server = createServer(Scope('/example/server'))

    # Add a method to the server.
    server.addMethod('echo', lambda x: x, str, str)

    # It is also possible to create a LocalServer with a given set of
    # methods. This construction avoids adding the methods
    # individually.
    server = createServer(Scope('/example/server'),
                          methods = [ ('echo2', lambda x: x, str, str) ])

    # Finally, a LocalServer can be created by exposing some or all
    # methods of an ordinary Python object.
    class MyObject:
        def echo3(self, arg):
            return arg

    server = createServer(Scope('/example/server'),
                          object = MyObject(),
                          expose = [ ('echo3', str, str) ])

    # Note: the code above creates three servers, each of which
    # provides one method on the scope /example/server

    # Wait for method calls by clients.
    sleep(100)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
;; Note: depending on your RSB configuration, this example may require
;; a running Spread daemon for successful execution.

;; Create a `remote-server' instance that calls methods of the remote
;; server at "/example/clientserver".
;; The remote server will use all transports which are enabled in the
;; global RSB configuration with their respective configured options.
(defvar *my-remote-server* (rsb.patterns:make-remote-server "/example/clientserver"))

;; Methods can be called without further preparation. Note that the
;; initial call of a method may take more time than subsequent methods
;; due to lazy initialization strategies.
(rsb.patterns:call *my-remote-server* "echo" "bla")

;; The remote server will remain connected to the bus until it is
;; garbage collected or explicitly detached using the `detach'
;; function.
(rsb:detach *my-remote-server*)

;; For managing the lifetime of `remote-server' instances (e.g. for
;; short-lived clients), the `with-remote-server' macro can used. It
;; will take care of disposing of the `remote-server' instance after
;; it has been used, also in case of non-local exist.
(rsb.patterns:with-remote-server (my-remote-server "/example/clientserver")

  (rsb.patterns:call my-remote-server "echo" "bla")

  ;; The default behavior of returning the reply payload can be
  ;; changed using the :return keyword parameter.
  (rsb.patterns:call my-remote-server "echo" "bla"
		     :return :event)

  ;; Non-blocking calls can be made using the :block? keyword
  ;; parameter. In that case, an object implementing the future
  ;; protocol is returned to represent the result of the computation.
  (let ((future (rsb.patterns:call my-remote-server "echo" "bla"
				   :block? nil)))
    (rsb.patterns:future-result future))

  ;; These behaviors can be combined:
  (let ((future (rsb.patterns:call my-remote-server "echo" "bla"
				   :block? nil
				   :return :event)))
    (rsb.patterns:future-result future))

  ;; Another way of calling methods makes use of the fact that
  ;; `remote-method' instances are funcallable:
  (map 'list (rsb.patterns:server-method my-remote-server "echo")
       '("a" "b" "c"))

  ;; This variant provides all the different behaviors of the `call'
  ;; variant:
  (funcall (rsb.patterns:server-method my-remote-server "echo")
	   "bla"
	   :return :event
	   :block? nil))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
;; Note: depending on your RSB configuration, this example may require
;; a running Spread daemon for successful execution.

;; Create a `local-server' instance that offers its methods under the
;; scope "/example/clientserver".
;; The local server will use all transports which are enabled in the
;; global RSB configuration with their respective configured options.
(defvar *my-local-server* (rsb.patterns:make-local-server "/example/clientserver"))

;; The new server instance initially does not have any methods. There
;; are several ways to add methods.
(setf (rsb.patterns:server-method *my-local-server* "echo")
      #'(lambda (arg)
	  arg))

;; The local server and its methods will remain connected to the bus
;; until they are garbage collected or explicitly detached using the
;; `detach' function.
(rsb:detach *my-local-server*)

;; For managing the lifetime of `local-server' instances (e.g. for
;; short-lived clients), the `with-local-server' macro can used. It
;; will take care of disposing of the `remote-server' instance after
;; it has been used, also in case of non-local exist.
(rsb.patterns:with-local-server (my-server "/example/clientserver")

  (setf (rsb.patterns:server-method my-server "echo")
	#'(lambda (arg)
	    arg))

  ;; Methods can be managed similarly. After the `with-methods' form,
  ;; the methods are removed.
  (rsb.patterns:with-methods (my-server)
      (("echo2" (arg string)
          arg))))

Extension Points

Writing Converters

Writing Filters

Writing Connectors

Writing Event Processing Strategies