Repository: qpid-proton Updated Branches: refs/heads/master 28385a4fc -> 02d82cdfc
added tornado integration example Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/02d82cdf Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/02d82cdf Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/02d82cdf Branch: refs/heads/master Commit: 02d82cdfcf61bb1cb05a9ae6b0c00414480e8be8 Parents: 2c96b7d Author: Rafael Schloming <[email protected]> Authored: Thu Feb 5 10:08:16 2015 -0500 Committer: Rafael Schloming <[email protected]> Committed: Thu Feb 5 12:57:35 2015 -0500 ---------------------------------------------------------------------- examples/reactor/py/README.md | 3 + examples/reactor/py/tornado-hello-world.py | 41 +++++++++++ examples/reactor/py/tornado-send.py | 82 ++++++++++++++++++++++ examples/reactor/py/tornado_app.py | 93 +++++++++++++++++++++++++ 4 files changed, 219 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02d82cdf/examples/reactor/py/README.md ---------------------------------------------------------------------- diff --git a/examples/reactor/py/README.md b/examples/reactor/py/README.md index e843d09..b08fdbd 100644 --- a/examples/reactor/py/README.md +++ b/examples/reactor/py/README.md @@ -29,3 +29,6 @@ transliterate into C in a fairly straightforward way. - send.py - recv.py + + - tornado-hello-world.py + - tornado-send.py http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02d82cdf/examples/reactor/py/tornado-hello-world.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/tornado-hello-world.py b/examples/reactor/py/tornado-hello-world.py new file mode 100755 index 0000000..fa8ca83 --- /dev/null +++ b/examples/reactor/py/tornado-hello-world.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import tornado.ioloop +from tornado_app import TornadoApp + +# The proton reactor provides a general purpose event processing +# library for writing reactive programs. A reactive program is defined +# by a set of event handlers. An event handler is just any class or +# object that defines the "on_<event>" methods that it cares to +# handle. + +class Program: + + # The reactor init event is produced by the reactor itself when it + # starts. + def on_reactor_init(self, event): + print "Hello, World!" + +# The TornadoApp integrates a Reactor into tornado's ioloop. +TornadoApp(Program()) + +# Now the tornado main loop will behave like the reactor's main loop. +tornado.ioloop.IOLoop.instance().start() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02d82cdf/examples/reactor/py/tornado-send.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/tornado-send.py b/examples/reactor/py/tornado-send.py new file mode 100755 index 0000000..54b8618 --- /dev/null +++ b/examples/reactor/py/tornado-send.py @@ -0,0 +1,82 @@ +#!/usr/bin/python +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys, tornado.ioloop +from tornado_app import TornadoApp +from proton import Message +from proton.handlers import CHandshaker + +class Send: + + def __init__(self, host, message): + self.host = host + self.message = message + # Use the handlers property to add some default handshaking + # behaviour. + self.handlers = [CHandshaker()] + + def on_connection_init(self, event): + conn = event.connection + conn.hostname = self.host + + # Every session or link could have their own handler(s) if we + # wanted simply by setting the "handler" slot on the + # given session or link. + ssn = conn.session() + + # If a link doesn't have an event handler, the events go to + # its parent session. If the session doesn't have a handler + # the events go to its parent connection. If the connection + # doesn't have a handler, the events go to the reactor. + snd = ssn.sender("sender") + conn.open() + ssn.open() + snd.open() + + def on_link_flow(self, event): + snd = event.sender + if snd.credit > 0: + dlv = snd.send(self.message) + dlv.settle() + snd.close() + snd.session.close() + snd.connection.close() + +class Program: + + def __init__(self, hostname, content): + self.hostname = hostname + self.content = content + + def on_reactor_init(self, event): + # You can use the connection method to create AMQP connections. + + # This connection's handler is the Send object. All the events + # for this connection will go to the Send object instead of + # going to the reactor. If you were to omit the Send object, + # all the events would go to the reactor. + event.reactor.connection(Send(self.hostname, Message(self.content))) + +args = sys.argv[1:] +hostname = args.pop() if args else "localhost" +content = args.pop() if args else "Hello World!" + +TornadoApp(Program(hostname, content)) +tornado.ioloop.IOLoop.instance().start() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/02d82cdf/examples/reactor/py/tornado_app.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/tornado_app.py b/examples/reactor/py/tornado_app.py new file mode 100644 index 0000000..34c659a --- /dev/null +++ b/examples/reactor/py/tornado_app.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import tornado.ioloop +from proton.reactors import Reactor +from proton.handlers import IOHandler + +class TornadoApp: + + def __init__(self, *args): + self.reactor = Reactor(*args) + self.reactor.global_handler = self + self.io = IOHandler() + self.loop = tornado.ioloop.IOLoop.instance() + self.count = 0 + self.reactor.start() + self.reactor.process() + + def on_reactor_quiesced(self, event): + event.reactor.yield_() + + def on_unhandled(self, name, event): + event.dispatch(self.io) + + def _events(self, sel): + events = self.loop.ERROR + if sel.reading: + events |= self.loop.READ + if sel.writing: + events |= self.loop.WRITE + return events + + def _schedule(self, sel): + if sel.deadline: + self.loop.add_timeout(sel.deadline, lambda: self.expired(sel)) + + def _expired(self, sel): + sel.expired() + + def _process(self): + self.reactor.process() + if not self.reactor.quiesced: + self.loop.add_callback(self._process) + + def _callback(self, sel, events): + if self.loop.READ & events: + sel.readable() + if self.loop.WRITE & events: + sel.writable() + self._process() + + def on_selectable_init(self, event): + sel = event.context + if sel.fileno() >= 0: + self.loop.add_handler(sel.fileno(), lambda fd, events: self._callback(sel, events), self._events(sel)) + self._schedule(sel) + self.count += 1 + + def on_selectable_updated(self, event): + sel = event.context + if sel.fileno() > 0: + self.loop.update_handler(sel.fileno(), self._events(sel)) + self._schedule(sel) + + def on_selectable_final(self, event): + sel = event.context + if sel.fileno() > 0: + self.loop.remove_handler(sel.fileno()) + sel.release() + self.count -= 1 + if self.count == 0: + self.loop.add_callback(self._stop) + + def _stop(self): + self.reactor.stop() + self.loop.stop() --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
