Repository: qpid-proton Updated Branches: refs/heads/master 0028c1c31 -> 77d98a207
added reactor examples Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/77d98a20 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/77d98a20 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/77d98a20 Branch: refs/heads/master Commit: 77d98a2070237adf9da610304a00b2f1ce0d4fd4 Parents: 0028c1c Author: Rafael Schloming <[email protected]> Authored: Thu Jan 29 18:12:38 2015 -0500 Committer: Rafael Schloming <[email protected]> Committed: Thu Jan 29 18:12:38 2015 -0500 ---------------------------------------------------------------------- examples/reactor/py/README.md | 19 +++++++++ examples/reactor/py/cat.py | 56 +++++++++++++++++++++++++++ examples/reactor/py/counter.py | 49 +++++++++++++++++++++++ examples/reactor/py/delegates.py | 48 +++++++++++++++++++++++ examples/reactor/py/echo.py | 56 +++++++++++++++++++++++++++ examples/reactor/py/goodbye-world.py | 33 ++++++++++++++++ examples/reactor/py/hello-world.py | 42 ++++++++++++++++++++ examples/reactor/py/logger.py | 41 ++++++++++++++++++++ examples/reactor/py/scheduling.py | 52 +++++++++++++++++++++++++ examples/reactor/py/send.py | 64 +++++++++++++++++++++++++++++++ examples/reactor/py/unhandled.py | 34 ++++++++++++++++ 11 files changed, 494 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/README.md ---------------------------------------------------------------------- diff --git a/examples/reactor/py/README.md b/examples/reactor/py/README.md new file mode 100644 index 0000000..24f4f20 --- /dev/null +++ b/examples/reactor/py/README.md @@ -0,0 +1,19 @@ +The examples in this directory provide a basic introduction to the +proton reactor API and are best viewed in the order presented below. +This API is present in C as well and most of these examples will +transliterate into C in a fairly straightforward way. + + - hello-world.py + - goodbye-world.py + + - scheduling.py + - counter.py + + - unhandled.py + - logger.py + - delegates.py + + - echo.py + - cat.py + + - send.py http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/cat.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/cat.py b/examples/reactor/py/cat.py new file mode 100755 index 0000000..e3af19a --- /dev/null +++ b/examples/reactor/py/cat.py @@ -0,0 +1,56 @@ +#!/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, os +from proton.reactors import Reactor + +class Echo: + + def __init__(self, source): + self.source = source + + def on_selectable_init(self, event): + sel = event.context # XXX: no selectable property yet + + # We can configure a selectable with any file descriptor we want. + sel.fileno(self.source.fileno()) + # Ask to be notified when the file is readable. + sel.reading = True + event.reactor.update(sel) + + def on_selectable_readable(self, event): + sel = event.context + + # The on_selectable_readable event tells us that there is data + # to be read, or the end of stream has been reached. + data = os.read(sel.fileno(), 1024) + if data: + print data, + else: + sel.terminate() + event.reactor.update(sel) + +class Program: + + def on_reactor_init(self, event): + event.reactor.selectable(Echo(open(sys.argv[1]))) + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/counter.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/counter.py b/examples/reactor/py/counter.py new file mode 100755 index 0000000..8a2479a --- /dev/null +++ b/examples/reactor/py/counter.py @@ -0,0 +1,49 @@ +#!/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 time +from proton.reactors import Reactor + +class Counter: + + def __init__(self, limit): + self.limit = limit + self.count = 0 + + def on_timer_task(self, event): + self.count += 1 + print self.count + if self.count < self.limit: + # A recurring task can be acomplished by just scheduling + # another event. + event.reactor.schedule(0.25, self) + +class Program: + + def on_reactor_init(self, event): + self.start = time.time() + print "Hello, World!" + event.reactor.schedule(0.25, Counter(10)) + + def on_reactor_final(self, event): + print "Goodbye, World! (after %s long seconds)" % (time.time() - self.start) + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/delegates.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/delegates.py b/examples/reactor/py/delegates.py new file mode 100755 index 0000000..b81338d --- /dev/null +++ b/examples/reactor/py/delegates.py @@ -0,0 +1,48 @@ +#!/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 time +from proton.reactors import Reactor + +# Events know how to dispatch themselves to handlers. By combining +# this with on_unhandled, you can provide a kind of inheritance +# between handlers using delegation. + +class Hello: + + def on_reactor_init(self, event): + print "Hello, World!" + +class Goodbye: + + def on_reactor_final(self, event): + print "Goodbye, World!" + +class Program: + + def __init__(self, *delegates): + self.delegates = delegates + + def on_unhandled(self, name, event): + for d in self.delegates: + event.dispatch(d) + +r = Reactor(Program(Hello(), Goodbye())) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/echo.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/echo.py b/examples/reactor/py/echo.py new file mode 100755 index 0000000..ecf1c9d --- /dev/null +++ b/examples/reactor/py/echo.py @@ -0,0 +1,56 @@ +#!/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, os +from proton.reactors import Reactor + +class Echo: + + def __init__(self, source): + self.source = source + + def on_selectable_init(self, event): + sel = event.context # XXX: no selectable property yet + + # We can configure a selectable with any file descriptor we want. + sel.fileno(self.source.fileno()) + # Ask to be notified when the file is readable. + sel.reading = True + event.reactor.update(sel) + + def on_selectable_readable(self, event): + sel = event.context + + # The on_selectable_readable event tells us that there is data + # to be read, or the end of stream has been reached. + data = os.read(sel.fileno(), 1024) + if data: + print data, + else: + sel.terminate() + event.reactor.update(sel) + +class Program: + + def on_reactor_init(self, event): + event.reactor.selectable(Echo(sys.stdin)) + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/goodbye-world.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/goodbye-world.py b/examples/reactor/py/goodbye-world.py new file mode 100755 index 0000000..6037ef9 --- /dev/null +++ b/examples/reactor/py/goodbye-world.py @@ -0,0 +1,33 @@ +#!/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. +# + +from proton.reactors import Reactor + +class Program: + + def on_reactor_init(self, event): + print "Hello, World!" + + # The reactor produces an event when it is about to exit. + def on_reactor_final(self, event): + print "Goodbye, World!" + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/hello-world.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/hello-world.py b/examples/reactor/py/hello-world.py new file mode 100755 index 0000000..8c35b85 --- /dev/null +++ b/examples/reactor/py/hello-world.py @@ -0,0 +1,42 @@ +#!/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. +# + +from proton.reactors import Reactor + +# 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!" + +# When you construct a reactor, you give it a handler. +r = Reactor(Program()) + +# When you call run, the reactor will process events. The reactor init +# event is what kicks off everything else. When the reactor has no +# more events to process, it will exit. +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/logger.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/logger.py b/examples/reactor/py/logger.py new file mode 100755 index 0000000..bcc8a9f --- /dev/null +++ b/examples/reactor/py/logger.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 time +from proton.reactors import Reactor + +class Logger: + + def on_unhandled(self, name, event): + print name, event + +class Program: + + def on_reactor_init(self, event): + print "Hello, World!" + + def on_reactor_final(self, event): + print "Goodbye, World!" + +# You can pass multiple handlers to the reactor. Each handler will see +# every event. By combining this with on_unhandled, you can print out +# every event as it happens. +r = Reactor(Logger(), Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/scheduling.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/scheduling.py b/examples/reactor/py/scheduling.py new file mode 100755 index 0000000..b2a1af7 --- /dev/null +++ b/examples/reactor/py/scheduling.py @@ -0,0 +1,52 @@ +#!/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 time +from proton.reactors import Reactor + +class Program: + + def on_reactor_init(self, event): + self.start = time.time() + print "Hello, World!" + + # If we want to hang around for a bit longer, we can schedule + # a task event for some point in the future. This will cause the + # reactor to stick around until it has a chance to process the + # event. + + # The first argument is the delay. The second argument to is + # the handler for the event. We are just using self for now, + # but we could pass in another object if we wanted. + task = event.reactor.schedule(1.0, self) + + # We can ignore the task if we want to, but we can also use it + # to pass stuff to the handler. + task.something_to_say = "Yay" + + def on_timer_task(self, event): + task = event.context # xxx: don't have a task property on event yet + print task.something_to_say, "my task is complete!" + + def on_reactor_final(self, event): + print "Goodbye, World! (after %s long seconds)" % (time.time() - self.start) + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/send.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/send.py b/examples/reactor/py/send.py new file mode 100755 index 0000000..b2927a7 --- /dev/null +++ b/examples/reactor/py/send.py @@ -0,0 +1,64 @@ +#!/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 +from proton import Message +from proton.reactors import Reactor +from proton.handlers import CHandshaker + +# This is a send in terms of low level AMQP events. There are handlers +# that can streamline this significantly if you don't want to worry +# about all the details. + +class Send: + + def __init__(self, host, message): + self.host = host + self.message = message + # The default event dispatcher will automatically check for a + # handlers property and delegate the event to all children + # present. + self.handlers = [CHandshaker()] + + def on_connection_init(self, event): + conn = event.connection + conn.hostname = self.host + ssn = conn.session() + snd = ssn.sender("sender") + conn.open() + ssn.open() + snd.open() + + def on_link_flow(self, event): + snd = event.sender + if snd.credit > 0: + snd.send(self.message) + snd.close() + snd.session.close() + snd.connection.close() + +class Program: + + def on_reactor_init(self, event): + # You can use the connection method to create AMQP connections. + event.reactor.connection(Send(sys.argv[1], Message(body=sys.argv[2]))) + +r = Reactor(Program()) +r.run() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/77d98a20/examples/reactor/py/unhandled.py ---------------------------------------------------------------------- diff --git a/examples/reactor/py/unhandled.py b/examples/reactor/py/unhandled.py new file mode 100755 index 0000000..303c89d --- /dev/null +++ b/examples/reactor/py/unhandled.py @@ -0,0 +1,34 @@ +#!/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 time +from proton.reactors import Reactor + +class Program: + + # If an event occurs and an object doesn't have an on_<event> + # method, the reactor will attempt to call the on_unhandled method + # this can be useful not only for debugging, but for logging and + # for delegating/inheritance. + def on_unhandled(self, name, event): + print name, event + +r = Reactor(Program()) +r.run() --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
