forked from chadrik/msgflo-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
msgflo.py
executable file
·143 lines (113 loc) · 4.07 KB
/
msgflo.py
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python
import sys, os, json
sys.path.append(os.path.abspath("."))
import logging
import gevent
import gevent.event
from haigha.connection import Connection as haigha_Connection
from haigha.message import Message as haigha_Message
def addDefaultQueue(p, role):
defaultQueue = '%s.%s' % (role, p['id'].upper())
p.setdefault('queue', defaultQueue)
return p
def normalizeDefinition(d, role):
# Apply defaults
d.setdefault('id', role)
d.setdefault('icon', 'file-word-o')
d.setdefault('label', "")
inports = d.setdefault('inports', [
{ 'id': 'in', 'type': 'any' }
])
outports = d.setdefault('outports', [
{ 'id': 'out', 'type': 'any' }
])
inports = [addDefaultQueue(p, role) for p in inports]
outports = [addDefaultQueue(p, role) for p in outports]
return d
class Participant:
def __init__(self, d, role):
self.definition = normalizeDefinition(d, role)
def send(self, outport, outdata):
if not self._runtime:
return
self._runtime._send(outport, outdata)
def process(self, inport, inmsg):
raise NotImplementedError('IParticipant.process()')
def ack(self, msg):
self._runtime._channel.basic.ack(msg.delivery_info["delivery_tag"])
def nack(self, msg):
self._runtime._channel.basic.nack(msg.delivery_info["delivery_tag"])
def sendParticipantDefinition(channel, d):
msg = haigha_Message(json.dumps(d))
channel.basic.publish(msg, '', 'fbp')
print 'sent discovery message', msg
return
def setupQueue(part, channel, direction, port):
queue = port['queue']
def handleInput(msg):
print "Received message: %s" % (msg,)
sys.stdout.flush()
msg.data = json.loads(msg.body.decode("utf-8"))
part.process(port, msg)
return
if 'in' in direction:
channel.queue.declare(queue)
channel.basic.consume(queue=queue, consumer=handleInput, no_ack=False)
print 'subscribed to', queue
sys.stdout.flush()
else:
channel.exchange.declare(queue, 'fanout')
print 'created outqueue', queue
sys.stdout.flush()
class GeventEngine(object):
def __init__(self, participant, done_cb):
self._done_cb = done_cb
self.participant = participant
self.participant._runtime = self
# Connect to AMQP broker with default connection and authentication
# settings (assumes broker is on localhost)
self._conn = haigha_Connection(transport='gevent',
close_cb=self._connection_closed_cb,
logger=logging.getLogger())
# Start message pump
self._message_pump_greenlet = gevent.spawn(self._message_pump_greenthread)
# Create message channel
self._channel = self._conn.channel()
self._channel.add_close_listener(self._channel_closed_cb)
sendParticipantDefinition(self._channel, self.participant.definition)
# Create and configure message exchange and queue
for p in self.participant.definition['inports']:
setupQueue(self.participant, self._channel, 'in', p)
for p in self.participant.definition['outports']:
setupQueue(self.participant, self._channel, 'out', p)
def _send(self, outport, data):
ports = self.participant.definition['outports']
print "Publishing message: %s, %s, %s" % (data,outport,ports)
sys.stdout.flush()
serialized = json.dumps(data)
msg = haigha_Message(serialized)
port = [p for p in ports if outport == p['id']][0]
self._channel.basic.publish(msg, port['queue'], '')
return
def _message_pump_greenthread(self):
try:
while self._conn is not None:
# Pump
self._conn.read_frames()
# Yield to other greenlets so they don't starve
gevent.sleep()
finally:
self._done_cb()
return
def _channel_closed_cb(self, ch):
print "AMQP channel closed; close-info: %s" % (
self._channel.close_info,)
self._channel = None
# Initiate graceful closing of the AMQP broker connection
self._conn.close()
return
def _connection_closed_cb(self):
print "AMQP broker connection closed; close-info: %s" % (
self._conn.close_info,)
self._conn = None
return