|
| 1 | +.. doctest-skip-all |
| 2 | +
|
| 3 | +.. _vo-samp-example_clients: |
| 4 | + |
| 5 | + |
| 6 | +Communication between Integrated Clients Objects |
| 7 | +************************************************ |
| 8 | + |
| 9 | +As shown in :doc:`example_table_image`, the `pyvo.samp.SAMPIntegratedClient` class can be |
| 10 | +used to communicate with other SAMP-enabled tools such as `TOPCAT <https://www.star.bristol.ac.uk/mbt/topcat>`_, |
| 11 | +`SAO DS9 <http://ds9.si.edu/>`_, or `Aladin Desktop <https://aladin.unistra.fr>`_. |
| 12 | + |
| 13 | +In this section, we look at how we can set up two `pyvo.samp.SAMPIntegratedClient` |
| 14 | +instances and communicate between them. |
| 15 | + |
| 16 | +First, start up a SAMP hub as described in :doc:`example_hub`. |
| 17 | + |
| 18 | +Next, we create two clients and connect them to the hub:: |
| 19 | + |
| 20 | + >>> from pyvo import samp |
| 21 | + >>> client1 = samp.SAMPIntegratedClient(name="Client 1", description="Test Client 1", |
| 22 | + ... metadata = {"client1.version":"0.01"}) |
| 23 | + >>> client2 = samp.SAMPIntegratedClient(name="Client 2", description="Test Client 2", |
| 24 | + ... metadata = {"client2.version":"0.25"}) |
| 25 | + >>> client1.connect() |
| 26 | + >>> client2.connect() |
| 27 | + |
| 28 | +We now define functions to call when receiving a notification, call or |
| 29 | +response:: |
| 30 | + |
| 31 | + >>> def test_receive_notification(private_key, sender_id, mtype, params, extra): |
| 32 | + ... print("Notification:", private_key, sender_id, mtype, params, extra) |
| 33 | + |
| 34 | + >>> def test_receive_call(private_key, sender_id, msg_id, mtype, params, extra): |
| 35 | + ... print("Call:", private_key, sender_id, msg_id, mtype, params, extra) |
| 36 | + ... client1.ereply(msg_id, samp.SAMP_STATUS_OK, result = {"txt": "printed"}) |
| 37 | + |
| 38 | + >>> def test_receive_response(private_key, sender_id, msg_id, response): |
| 39 | + ... print("Response:", private_key, sender_id, msg_id, response) |
| 40 | + |
| 41 | +We subscribe client 1 to ``"samp.app.*"`` and bind it to the |
| 42 | +related functions:: |
| 43 | + |
| 44 | + >>> client1.bind_receive_notification("samp.app.*", test_receive_notification) |
| 45 | + >>> client1.bind_receive_call("samp.app.*", test_receive_call) |
| 46 | + |
| 47 | +We now bind message tags received by client 2 to suitable functions:: |
| 48 | + |
| 49 | + >>> client2.bind_receive_response("my-dummy-print", test_receive_response) |
| 50 | + >>> client2.bind_receive_response("my-dummy-print-specific", test_receive_response) |
| 51 | + |
| 52 | +We are now ready to test out the clients and callback functions. Client 2 |
| 53 | +notifies all clients using the "samp.app.echo" message type via the hub:: |
| 54 | + |
| 55 | + >>> client2.enotify_all("samp.app.echo", txt="Hello world!") |
| 56 | + ['cli#2'] |
| 57 | + Notification: 0d7f4500225981c104a197c7666a8e4e cli#2 samp.app.echo {'txt': |
| 58 | + 'Hello world!'} {'host': 'antigone.lambrate.inaf.it', 'user': 'unknown'} |
| 59 | + |
| 60 | +We can also find a dictionary that specifies which clients would currently |
| 61 | +receive ``samp.app.echo`` messages:: |
| 62 | + |
| 63 | + >>> print(client2.get_subscribed_clients("samp.app.echo")) |
| 64 | + {'cli#2': {}} |
| 65 | + |
| 66 | +Client 2 calls all clients with the ``"samp.app.echo"`` message type using |
| 67 | +``"my-dummy-print"`` as a message-tag:: |
| 68 | + |
| 69 | + >>> print(client2.call_all("my-dummy-print", |
| 70 | + ... {"samp.mtype": "samp.app.echo", |
| 71 | + ... "samp.params": {"txt": "Hello world!"}})) |
| 72 | + {'cli#1': 'msg#1;;cli#hub;;cli#2;;my-dummy-print'} |
| 73 | + Call: 8c8eb53178cb95e168ab17ec4eac2353 cli#2 |
| 74 | + msg#1;;cli#hub;;cli#2;;my-dummy-print samp.app.echo {'txt': 'Hello world!'} |
| 75 | + {'host': 'antigone.lambrate.inaf.it', 'user': 'unknown'} |
| 76 | + Response: d0a28636321948ccff45edaf40888c54 cli#1 my-dummy-print |
| 77 | + {'samp.status': 'samp.ok', 'samp.result': {'txt': 'printed'}} |
| 78 | + |
| 79 | +Client 2 then calls client 1 using the ``"samp.app.echo"`` message type, |
| 80 | +tagging the message as ``"my-dummy-print-specific"``:: |
| 81 | + |
| 82 | + >>> try: |
| 83 | + ... print(client2.call(client1.get_public_id(), |
| 84 | + ... "my-dummy-print-specific", |
| 85 | + ... {"samp.mtype": "samp.app.echo", |
| 86 | + ... "samp.params": {"txt": "Hello client 1!"}})) |
| 87 | + ... except samp.SAMPProxyError as e: |
| 88 | + ... print("Error ({0}): {1}".format(e.faultCode, e.faultString)) |
| 89 | + msg#2;;cli#hub;;cli#2;;my-dummy-print-specific |
| 90 | + Call: 8c8eb53178cb95e168ab17ec4eac2353 cli#2 |
| 91 | + msg#2;;cli#hub;;cli#2;;my-dummy-print-specific samp.app.echo {'txt': 'Hello |
| 92 | + Cli 1!'} {'host': 'antigone.lambrate.inaf.it', 'user': 'unknown'} |
| 93 | + Response: d0a28636321948ccff45edaf40888c54 cli#1 my-dummy-print-specific |
| 94 | + {'samp.status': 'samp.ok', 'samp.result': {'txt': 'printed'}} |
| 95 | + |
| 96 | +We can now define a function called to test synchronous calls:: |
| 97 | + |
| 98 | + >>> def test_receive_sync_call(private_key, sender_id, msg_id, mtype, params, extra): |
| 99 | + ... import time |
| 100 | + ... print("SYNC Call:", sender_id, msg_id, mtype, params, extra) |
| 101 | + ... time.sleep(2) |
| 102 | + ... client1.reply(msg_id, {"samp.status": samp.SAMP_STATUS_OK, |
| 103 | + ... "samp.result": {"txt": "printed sync"}}) |
| 104 | + |
| 105 | +We now bind the ``samp.test`` message type to ``test_receive_sync_call``:: |
| 106 | + |
| 107 | + >>> client1.bind_receive_call("samp.test", test_receive_sync_call) |
| 108 | + >>> try: |
| 109 | + ... # Sync call |
| 110 | + ... print(client2.call_and_wait(client1.get_public_id(), |
| 111 | + ... {"samp.mtype": "samp.test", |
| 112 | + ... "samp.params": {"txt": "Hello SYNCRO client 1!"}}, |
| 113 | + ... "10")) |
| 114 | + ... except samp.SAMPProxyError as e: |
| 115 | + ... # If timeout expires than a SAMPProxyError is returned |
| 116 | + ... print("Error ({0}): {1}".format(e.faultCode, e.faultString)) |
| 117 | + SYNC Call: cli#2 msg#3;;cli#hub;;cli#2;;sampy::sync::call samp.test {'txt': |
| 118 | + 'Hello SYNCRO Cli 1!'} {'host': 'antigone.lambrate.inaf.it', 'user': |
| 119 | + 'unknown'} |
| 120 | + {'samp.status': 'samp.ok', 'samp.result': {'txt': 'printed sync'}} |
| 121 | + |
| 122 | +Finally, we disconnect the clients from the hub at the end:: |
| 123 | + |
| 124 | + >>> client1.disconnect() |
| 125 | + >>> client2.disconnect() |
0 commit comments