diff --git a/README.md b/README.md index ce5ceb7..38aa2b1 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,45 @@ def handler(payload, root): gcn.listen(handler=handler) ``` +## Threading + +You can run the listener in a separate thread or process and pass the packets back in a `Queue`, +allowing the main program to continue operating while waiting for an event. +Here is an example: + +```python +#!/usr/bin/env python +import gcn +import threading +import queue + +# Set up communications: +messagequeue = queue.Queue() +# Create a listen handler to enqueue the (payload, root) tuple +handler = gcn.handlers.queuehandlerfor(messagequeue) + +# Create and start the thread. +thread = threading.Thread(target=gcn.listen, + kwargs=dict(handler=handler)) +thread.start() + +# Wait for messages to come in, but do other things if they don't. +nothingcount=0 +while True: + try: + # Use block=False if you want to timeout immediately + payload,root = messagequeue.get(timeout=10) + print(root.attrib['ivorn']) + nothingcount = 0 + except queue.Empty: + # Do idle stuff here. + print("Nothing...") + nothingcount += 1 + if nothingcount > 10: + print("Quitting due to inactivity") + break +``` + [1]: http://gcn.gsfc.nasa.gov [2]: http://www.ivoa.net/documents/VOEvent diff --git a/gcn/handlers.py b/gcn/handlers.py index ee71ac7..04b352c 100755 --- a/gcn/handlers.py +++ b/gcn/handlers.py @@ -22,7 +22,7 @@ from urllib.parse import quote_plus __all__ = ('get_notice_type', 'include_notice_types', 'exclude_notice_types', - 'archive') + 'archive', 'queuehandlerfor') def get_notice_type(root): @@ -85,3 +85,19 @@ def archive(payload, root): with open(filename, 'wb') as f: f.write(payload) logging.getLogger('gcn.handlers.archive').info("archived %s", ivorn) + + +def _queuehandler(payload, root, *, queue): + """ Place (payload, root) on queue for threaded operation. + This can be used in the following manner: + gcn.listen(handler=functools.partial(partialize_queue, queue=a_queue)) + """ + queue.put((payload, root)) + + +def queuehandlerfor(queue): + """Create a handler that places (payload, root) on the given queue + This can be used in the following manner: + gcn.listen(handler = queuehandlerfor(queue)) + """ + return functools.partial(_queuehandler, queue=queue) diff --git a/gcn/tests/test_handlers.py b/gcn/tests/test_handlers.py index 51a16d7..844d943 100644 --- a/gcn/tests/test_handlers.py +++ b/gcn/tests/test_handlers.py @@ -7,7 +7,7 @@ from . import data from .. import handlers from .. import notice_types - +import queue payloads = [resources.read_binary(data, 'gbm_flt_pos.xml'), resources.read_binary(data, 'kill_socket.xml')] @@ -53,3 +53,24 @@ def test_archive(tmpdir): assert (tmpdir / filename).exists() finally: os.chdir(old_dir) + + +def test_queuehandler(): + queue_ = queue.Queue() + queuehandlerfor = handlers.queuehandlerfor(queue_) + assert queue_.empty() + + for payload in payloads: + queuehandlerfor(payload, fromstring(payload)) + qpayload, qtree = queue_.get() + assert qpayload == payload + + assert queue_.empty() + + for payload in payloads: + queuehandlerfor(payload, fromstring(payload)) + for payload in payloads: + qpayload, qtree = queue_.get() + assert qpayload == payload + + assert queue_.empty() diff --git a/setup.cfg b/setup.cfg index 8e573bd..65c9431 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,6 +28,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Topic :: Internet Topic :: Scientific/Engineering :: Astronomy project_urls =