pyre-gevent 0.2.3.dev3__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyre-gevent-0.2.3.dev3/pyre_gevent.egg-info → pyre-gevent-0.3.0}/PKG-INFO +5 -6
- pyre-gevent-0.3.0/pyre_gevent/__init__.py +8 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/pyre.py +1 -1
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/pyre_event.py +2 -4
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/pyre_node.py +4 -4
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/zbeacon.py +149 -79
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/zre_msg.py +3 -5
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0/pyre_gevent.egg-info}/PKG-INFO +5 -6
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent.egg-info/SOURCES.txt +6 -1
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent.egg-info/requires.txt +2 -2
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/setup.py +2 -2
- pyre-gevent-0.3.0/tests/test_network_disconnect.py +81 -0
- pyre-gevent-0.3.0/tests/test_pyre.py +178 -0
- pyre-gevent-0.3.0/tests/test_zactor.py +38 -0
- pyre-gevent-0.3.0/tests/test_zbeacon.py +82 -0
- pyre-gevent-0.3.0/tests/test_zhelper.py +32 -0
- pyre-gevent-0.2.3.dev3/pyre_gevent/__init__.py +0 -8
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/AUTHORS +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/LICENSE +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/MANIFEST.in +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/README.md +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/pyre_group.py +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/pyre_peer.py +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/zactor.py +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/zhelper.py +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent/zsocket.py +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent.egg-info/dependency_links.txt +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/pyre_gevent.egg-info/top_level.txt +0 -0
- {pyre-gevent-0.2.3.dev3 → pyre-gevent-0.3.0}/setup.cfg +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
Metadata-Version: 1
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: pyre-gevent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python ZRE implementation (green version)
|
|
5
5
|
Home-page: http://www.github.com/tangb/pyre-gevent/
|
|
6
6
|
Author: Arnaud Loonstra
|
|
7
7
|
Author-email: arnaud@sphaero.org
|
|
8
8
|
Maintainer: Tanguy Bonneau
|
|
9
9
|
Maintainer-email: tanguy.bonneau@gmail.com
|
|
10
|
-
License: UNKNOWN
|
|
11
|
-
Description: UNKNOWN
|
|
12
|
-
Platform: UNKNOWN
|
|
13
10
|
Requires: pyzmq
|
|
14
11
|
Requires: ipaddress
|
|
15
12
|
Requires: netaddr
|
|
16
|
-
Requires:
|
|
13
|
+
Requires: netifaces2
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
License-File: AUTHORS
|
|
@@ -27,7 +27,7 @@ class PyreEvent(object):
|
|
|
27
27
|
if self.type == "ENTER":
|
|
28
28
|
self.headers = json.loads(incoming.pop(0).decode('utf-8'))
|
|
29
29
|
self.peer_addr = incoming.pop(0).decode('utf-8')
|
|
30
|
-
elif self.type
|
|
30
|
+
elif self.type in ["JOIN", "LEAVE"]:
|
|
31
31
|
self.group = incoming.pop(0).decode('utf-8')
|
|
32
32
|
elif self.type == "WHISPER":
|
|
33
33
|
self.msg = incoming
|
|
@@ -44,9 +44,7 @@ class PyreEvent(object):
|
|
|
44
44
|
Returns:
|
|
45
45
|
str: Header value
|
|
46
46
|
"""
|
|
47
|
-
if self.headers and name in self.headers
|
|
48
|
-
return self.headers[name]
|
|
49
|
-
return None
|
|
47
|
+
return self.headers[name] if self.headers and name in self.headers else None
|
|
50
48
|
|
|
51
49
|
@property
|
|
52
50
|
def peer_uuid(self):
|
|
@@ -301,7 +301,8 @@ class PyreNode(object):
|
|
|
301
301
|
logger.warning("Unkown Node API command: {0}".format(command))
|
|
302
302
|
|
|
303
303
|
def purge_peer(self, peer, endpoint):
|
|
304
|
-
if
|
|
304
|
+
if peer.get_endpoint() == endpoint:
|
|
305
|
+
self.remove_peer(peer)
|
|
305
306
|
peer.disconnect()
|
|
306
307
|
logger.debug("Purge peer: {0}{1}".format(peer,endpoint))
|
|
307
308
|
|
|
@@ -410,7 +411,7 @@ class PyreNode(object):
|
|
|
410
411
|
|
|
411
412
|
# Ignore command if peer isn't ready
|
|
412
413
|
if not peer or not peer.get_ready():
|
|
413
|
-
logger.
|
|
414
|
+
logger.debug("Peer {0} isn't ready".format(peer))
|
|
414
415
|
return
|
|
415
416
|
|
|
416
417
|
if peer.messages_lost(zmsg):
|
|
@@ -530,8 +531,7 @@ class PyreNode(object):
|
|
|
530
531
|
reap_at = time.time() + REAP_INTERVAL
|
|
531
532
|
while not self._terminated:
|
|
532
533
|
timeout = reap_at - time.time()
|
|
533
|
-
|
|
534
|
-
timeout = 0
|
|
534
|
+
timeout = max(timeout, 0)
|
|
535
535
|
items = dict(self.poller.poll(timeout * 1000))
|
|
536
536
|
|
|
537
537
|
if self._pipe in items and items[self._pipe] == zmq.POLLIN:
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
# ======================================================================
|
|
3
2
|
# zbeacon - LAN discovery and presence
|
|
4
3
|
#
|
|
@@ -38,26 +37,30 @@ import netaddr
|
|
|
38
37
|
logger = logging.getLogger(__name__)
|
|
39
38
|
|
|
40
39
|
INTERVAL_DFLT = 1.0
|
|
41
|
-
BEACON_MAX = 255
|
|
42
|
-
MULTICAST_GRP =
|
|
40
|
+
BEACON_MAX = 255 # Max size of beacon data
|
|
41
|
+
MULTICAST_GRP = "225.25.25.25"
|
|
42
|
+
ENETDOWN = 50 # socket error, network is down
|
|
43
|
+
ENETUNREACH = 51 # socket error, network unreachable
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
class ZBeacon(object):
|
|
46
47
|
|
|
47
48
|
def __init__(self, ctx, pipe, *args, **kwargs):
|
|
48
|
-
self.ctx = ctx
|
|
49
|
-
self.pipe = pipe
|
|
50
|
-
self.udpsock = socket.socket(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
self.
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
57
|
-
|
|
58
|
-
self.
|
|
59
|
-
|
|
60
|
-
self.
|
|
49
|
+
self.ctx = ctx # ZMQ context
|
|
50
|
+
self.pipe = pipe # Actor command pipe
|
|
51
|
+
self.udpsock = socket.socket(
|
|
52
|
+
socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP
|
|
53
|
+
)
|
|
54
|
+
# UDP socket for send/recv
|
|
55
|
+
self.port_nbr = 0 # UDP port number we work on
|
|
56
|
+
self.interval = INTERVAL_DFLT # Beacon broadcast interval
|
|
57
|
+
self.ping_at = 0 # Next broadcast time
|
|
58
|
+
self.transmit = None # Beacon transmit data
|
|
59
|
+
self.filter = b"" # Beacon filter data
|
|
60
|
+
|
|
61
|
+
self.terminated = False # Did caller ask us to quit?
|
|
62
|
+
self.verbose = False # Verbose logging enabled?
|
|
63
|
+
self.hostname = "" # Saved host name
|
|
61
64
|
|
|
62
65
|
self.address = None
|
|
63
66
|
self.mac = None
|
|
@@ -71,23 +74,25 @@ class ZBeacon(object):
|
|
|
71
74
|
self.udpsock.close()
|
|
72
75
|
|
|
73
76
|
def prepare_udp(self, interface_name=None):
|
|
74
|
-
|
|
77
|
+
try:
|
|
78
|
+
self._prepare_socket(interface_name)
|
|
79
|
+
except ValueError:
|
|
80
|
+
logger.exception("Error preparing socket:")
|
|
81
|
+
return
|
|
75
82
|
try:
|
|
76
83
|
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
77
84
|
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
78
85
|
|
|
79
86
|
# On some platforms we have to ask to reuse the port
|
|
80
87
|
try:
|
|
81
|
-
self.udpsock.setsockopt(socket.SOL_SOCKET,
|
|
82
|
-
socket.SO_REUSEPORT, 1)
|
|
88
|
+
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
|
83
89
|
|
|
84
90
|
except AttributeError:
|
|
85
91
|
pass
|
|
86
92
|
|
|
87
93
|
if self.broadcast_address.is_multicast:
|
|
88
94
|
# TTL
|
|
89
|
-
self.udpsock.setsockopt(socket.IPPROTO_IP,
|
|
90
|
-
socket.IP_MULTICAST_TTL, 2)
|
|
95
|
+
self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
|
|
91
96
|
|
|
92
97
|
# TODO: This should only be used if we do not have inproc method!
|
|
93
98
|
self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
|
|
@@ -115,48 +120,63 @@ class ZBeacon(object):
|
|
|
115
120
|
self.udpsock.bind(("", self.port_nbr))
|
|
116
121
|
|
|
117
122
|
group = socket.inet_aton("{0}".format(self.broadcast_address))
|
|
118
|
-
mreq = struct.pack(
|
|
123
|
+
mreq = struct.pack("4sl", group, socket.INADDR_ANY)
|
|
119
124
|
|
|
120
|
-
self.udpsock.setsockopt(socket.SOL_IP,
|
|
121
|
-
socket.IP_ADD_MEMBERSHIP, mreq)
|
|
125
|
+
self.udpsock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
|
122
126
|
|
|
123
127
|
else:
|
|
124
128
|
# Platform specifics
|
|
125
129
|
if platform.startswith("linux"):
|
|
126
130
|
# on linux we bind to the broadcast address and send to
|
|
127
131
|
# the broadcast address
|
|
128
|
-
self.udpsock.bind((str(self.broadcast_address),
|
|
129
|
-
self.port_nbr))
|
|
132
|
+
self.udpsock.bind((str(self.broadcast_address), self.port_nbr))
|
|
130
133
|
else:
|
|
131
134
|
self.udpsock.bind(("", self.port_nbr))
|
|
132
135
|
|
|
133
|
-
logger.debug(
|
|
136
|
+
logger.debug(
|
|
137
|
+
"Set up a broadcast beacon to {0}:{1}".format(
|
|
138
|
+
self.broadcast_address, self.port_nbr
|
|
139
|
+
)
|
|
140
|
+
)
|
|
134
141
|
except socket.error:
|
|
135
|
-
logger.exception(
|
|
142
|
+
logger.exception(
|
|
143
|
+
"Initializing of {0} raised an exception".format(
|
|
144
|
+
self.__class__.__name__
|
|
145
|
+
)
|
|
146
|
+
)
|
|
136
147
|
|
|
137
148
|
def _prepare_socket(self, interface_name=None):
|
|
138
149
|
netinf = zhelper.get_ifaddrs()
|
|
139
150
|
logger.debug("Available interfaces: {0}".format(netinf))
|
|
140
151
|
|
|
141
|
-
#get default gateway interface
|
|
152
|
+
# get default gateway interface
|
|
142
153
|
default_interface_names = []
|
|
143
154
|
netifaces_default_interface_names = []
|
|
144
155
|
gateways = netifaces.gateways()
|
|
145
156
|
logger.debug("Gateways: {0}".format(gateways))
|
|
146
157
|
if netifaces.AF_INET in gateways:
|
|
147
158
|
for address, interface, is_default in gateways[netifaces.AF_INET]:
|
|
148
|
-
#fix for windows (netifaces.gateway() returns adapter name instead of interface name)
|
|
159
|
+
# fix for windows (netifaces.gateway() returns adapter name instead of interface name)
|
|
149
160
|
if platform.startswith("win"):
|
|
150
161
|
netifaces_default_interface_names.append(interface)
|
|
151
162
|
for iface in netinf:
|
|
152
163
|
for name, data in iface.items():
|
|
153
|
-
if
|
|
164
|
+
if (
|
|
165
|
+
netifaces.AF_INET in data
|
|
166
|
+
and data[netifaces.AF_INET]["adapter"] == interface
|
|
167
|
+
):
|
|
154
168
|
default_interface_names.append(name)
|
|
155
169
|
else:
|
|
156
170
|
default_interface_names.append(interface)
|
|
157
|
-
|
|
158
|
-
logger.debug(
|
|
159
|
-
|
|
171
|
+
|
|
172
|
+
logger.debug(
|
|
173
|
+
"Default interface names '{0}'".format(list(default_interface_names))
|
|
174
|
+
)
|
|
175
|
+
logger.debug(
|
|
176
|
+
"Netifaces default interface names '{0}'".format(
|
|
177
|
+
list(netifaces_default_interface_names)
|
|
178
|
+
)
|
|
179
|
+
)
|
|
160
180
|
|
|
161
181
|
for iface in netinf:
|
|
162
182
|
# Loop over the interfaces and their settings to try to find the broadcast address.
|
|
@@ -166,39 +186,53 @@ class ZBeacon(object):
|
|
|
166
186
|
if interface_name and interface_name != name:
|
|
167
187
|
continue
|
|
168
188
|
|
|
169
|
-
#Interface of default route found, skip other ones
|
|
170
|
-
#This trick allows to skip invalid interfaces like docker ones.
|
|
171
|
-
if
|
|
172
|
-
|
|
189
|
+
# Interface of default route found, skip other ones
|
|
190
|
+
# This trick allows to skip invalid interfaces like docker ones.
|
|
191
|
+
if (
|
|
192
|
+
len(default_interface_names) > 0
|
|
193
|
+
and name not in default_interface_names
|
|
194
|
+
):
|
|
195
|
+
logger.debug(
|
|
196
|
+
"Interface '{0}' is not interface of default route".format(name)
|
|
197
|
+
)
|
|
173
198
|
continue
|
|
174
199
|
|
|
175
|
-
logger.debug(
|
|
200
|
+
logger.debug("Checking out interface '{0}'.".format(name))
|
|
176
201
|
|
|
177
|
-
#Get addr and netmask infos
|
|
202
|
+
# Get addr and netmask infos
|
|
178
203
|
data_2 = data.get(netifaces.AF_INET)
|
|
179
204
|
if not data_2:
|
|
180
|
-
logger.debug(
|
|
205
|
+
logger.debug("No data_2 found for interface '{0}'.".format(name))
|
|
181
206
|
continue
|
|
182
207
|
|
|
183
|
-
#get mac address infos
|
|
184
|
-
data_17 = data.get(netifaces.
|
|
208
|
+
# get mac address infos
|
|
209
|
+
data_17 = data.get(netifaces.AF_PACKET)
|
|
185
210
|
if not data_17 and platform.startswith("win"):
|
|
186
|
-
#last chance to get mac address on windows platform
|
|
187
|
-
for
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
211
|
+
# last chance to get mac address on windows platform
|
|
212
|
+
for (
|
|
213
|
+
netifaces_default_interface_name
|
|
214
|
+
) in netifaces_default_interface_names:
|
|
215
|
+
ifaddresses = netifaces.ifaddresses(
|
|
216
|
+
netifaces_default_interface_name
|
|
217
|
+
)
|
|
218
|
+
if (
|
|
219
|
+
netifaces.AF_PACKET in ifaddresses
|
|
220
|
+
and len(ifaddresses[netifaces.AF_PACKET]) > 0
|
|
221
|
+
):
|
|
222
|
+
data_17 = ifaddresses[netifaces.AF_PACKET][0]
|
|
191
223
|
break
|
|
192
224
|
if not data_17:
|
|
193
|
-
logger.debug(
|
|
225
|
+
logger.debug("No data_17 found for interface '{0}'.".format(name))
|
|
194
226
|
continue
|
|
195
227
|
|
|
196
228
|
address_str = data_2.get("addr")
|
|
197
229
|
netmask_str = data_2.get("netmask")
|
|
198
|
-
mac_str = data_17.get("addr")
|
|
230
|
+
mac_str = data_17.get("addr")
|
|
199
231
|
|
|
200
232
|
if not address_str or not netmask_str:
|
|
201
|
-
logger.debug(
|
|
233
|
+
logger.debug(
|
|
234
|
+
"Address or netmask not found for interface '{0}'.".format(name)
|
|
235
|
+
)
|
|
202
236
|
continue
|
|
203
237
|
|
|
204
238
|
if isinstance(address_str, bytes):
|
|
@@ -210,10 +244,24 @@ class ZBeacon(object):
|
|
|
210
244
|
if isinstance(mac_str, bytes):
|
|
211
245
|
mac_str = mac_str.decode("utf8")
|
|
212
246
|
|
|
213
|
-
#keep only private interface
|
|
247
|
+
# keep only private interface
|
|
214
248
|
ip_address = netaddr.IPAddress(address_str)
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
# handle netaddr breaking changes
|
|
250
|
+
if netaddr.__version__.startswith("0."):
|
|
251
|
+
# is_private does not exist anymore on new IpAddress lib version
|
|
252
|
+
# pylint: disable=no-member
|
|
253
|
+
ip_is_private = ip_address.is_private()
|
|
254
|
+
else:
|
|
255
|
+
ip_is_private = (
|
|
256
|
+
ip_address.is_ipv4_private_use()
|
|
257
|
+
or ip_address.is_ipv6_unique_local()
|
|
258
|
+
)
|
|
259
|
+
if ip_address and not ip_is_private():
|
|
260
|
+
logger.debug(
|
|
261
|
+
"Interface '{0}' refers to public ip address, drop it.".format(
|
|
262
|
+
name
|
|
263
|
+
)
|
|
264
|
+
)
|
|
217
265
|
continue
|
|
218
266
|
|
|
219
267
|
interface_string = "{0}/{1}".format(address_str, netmask_str)
|
|
@@ -221,11 +269,11 @@ class ZBeacon(object):
|
|
|
221
269
|
interface = ipaddress.ip_interface(u(interface_string))
|
|
222
270
|
|
|
223
271
|
if interface.is_loopback:
|
|
224
|
-
logger.debug(
|
|
272
|
+
logger.debug("Interface {0} is a loopback device.".format(name))
|
|
225
273
|
continue
|
|
226
274
|
|
|
227
275
|
if interface.is_link_local:
|
|
228
|
-
logger.debug(
|
|
276
|
+
logger.debug("Interface {0} is a link-local device.".format(name))
|
|
229
277
|
continue
|
|
230
278
|
|
|
231
279
|
self.address = interface.ip
|
|
@@ -236,17 +284,17 @@ class ZBeacon(object):
|
|
|
236
284
|
|
|
237
285
|
if self.address:
|
|
238
286
|
break
|
|
239
|
-
|
|
287
|
+
|
|
240
288
|
if self.address:
|
|
241
289
|
break
|
|
242
290
|
|
|
243
291
|
logger.debug("Finished scanning interfaces.")
|
|
244
292
|
|
|
245
293
|
if not self.address:
|
|
246
|
-
self.network_address = ipaddress.IPv4Address(u(
|
|
294
|
+
self.network_address = ipaddress.IPv4Address(u("127.0.0.1"))
|
|
247
295
|
self.broadcast_address = ipaddress.IPv4Address(u(MULTICAST_GRP))
|
|
248
|
-
self.interface_name =
|
|
249
|
-
self.address = u(
|
|
296
|
+
self.interface_name = "loopback"
|
|
297
|
+
self.address = u("127.0.0.1")
|
|
250
298
|
self.mac = None
|
|
251
299
|
|
|
252
300
|
logger.debug("Address: {0}".format(self.address))
|
|
@@ -263,9 +311,9 @@ class ZBeacon(object):
|
|
|
263
311
|
def handle_pipe(self):
|
|
264
312
|
# Get just the commands off the pipe
|
|
265
313
|
request = self.pipe.recv_multipart()
|
|
266
|
-
command = request.pop(0).decode(
|
|
314
|
+
command = request.pop(0).decode("UTF-8")
|
|
267
315
|
if not command:
|
|
268
|
-
return -1
|
|
316
|
+
return -1 # Interrupted
|
|
269
317
|
|
|
270
318
|
if self.verbose:
|
|
271
319
|
logger.debug("zbeacon: API command={0}".format(command))
|
|
@@ -276,10 +324,13 @@ class ZBeacon(object):
|
|
|
276
324
|
# unpacking code from https://bit.ly/2qN3ZUz
|
|
277
325
|
interface_data = request.pop(0)
|
|
278
326
|
|
|
279
|
-
(interface_name_len,), interface =
|
|
280
|
-
|
|
327
|
+
(interface_name_len,), interface = (
|
|
328
|
+
struct.unpack("I", interface_data[:4]),
|
|
329
|
+
interface_data[4:],
|
|
330
|
+
)
|
|
331
|
+
interface = interface.decode("UTF-8")
|
|
281
332
|
|
|
282
|
-
port = struct.unpack(
|
|
333
|
+
port = struct.unpack("I", request.pop(0))[0]
|
|
283
334
|
self.configure(interface, port)
|
|
284
335
|
elif command == "PUBLISH":
|
|
285
336
|
self.transmit = request.pop(0)
|
|
@@ -312,8 +363,8 @@ class ZBeacon(object):
|
|
|
312
363
|
is_valid = False
|
|
313
364
|
if self.filter is not None:
|
|
314
365
|
if len(self.filter) <= len(frame):
|
|
315
|
-
match_data = frame[:len(self.filter)]
|
|
316
|
-
if
|
|
366
|
+
match_data = frame[: len(self.filter)]
|
|
367
|
+
if match_data == self.filter:
|
|
317
368
|
is_valid = True
|
|
318
369
|
|
|
319
370
|
# If valid, discard our own broadcasts, which UDP echoes to us
|
|
@@ -328,13 +379,27 @@ class ZBeacon(object):
|
|
|
328
379
|
|
|
329
380
|
def send_beacon(self):
|
|
330
381
|
try:
|
|
331
|
-
self.udpsock.sendto(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
382
|
+
self.udpsock.sendto(
|
|
383
|
+
self.transmit, (str(self.broadcast_address), self.port_nbr)
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
except OSError as e:
|
|
387
|
+
|
|
388
|
+
# network down, just wait, it could come back up again.
|
|
389
|
+
# socket call errors 50 and 51 relate to the network being
|
|
390
|
+
# down or unreachable, the recommended action to take is to
|
|
391
|
+
# try again so we don't terminate in these cases.
|
|
392
|
+
if e.errno in [ENETDOWN, ENETUNREACH]:
|
|
393
|
+
pass
|
|
394
|
+
|
|
395
|
+
# all other cases, we'll terminate
|
|
396
|
+
else:
|
|
397
|
+
logger.debug("Network seems gone, exiting zbeacon")
|
|
398
|
+
self.terminated = True
|
|
399
|
+
|
|
400
|
+
except socket.error:
|
|
401
|
+
logger.debug("Network seems gone, exiting zbeacon")
|
|
402
|
+
self.terminated = True
|
|
338
403
|
|
|
339
404
|
def run(self):
|
|
340
405
|
# Signal actor successfully initialized
|
|
@@ -354,7 +419,10 @@ class ZBeacon(object):
|
|
|
354
419
|
items = dict(self.poller.poll(timeout * 1000))
|
|
355
420
|
if self.pipe in items and items[self.pipe] == zmq.POLLIN:
|
|
356
421
|
self.handle_pipe()
|
|
357
|
-
if
|
|
422
|
+
if (
|
|
423
|
+
self.udpsock.fileno() in items
|
|
424
|
+
and items[self.udpsock.fileno()] == zmq.POLLIN
|
|
425
|
+
):
|
|
358
426
|
self.handle_udp()
|
|
359
427
|
|
|
360
428
|
if self.transmit and time.time() >= self.ping_at:
|
|
@@ -362,18 +430,20 @@ class ZBeacon(object):
|
|
|
362
430
|
self.ping_at = time.time() + self.interval
|
|
363
431
|
|
|
364
432
|
|
|
365
|
-
if __name__ ==
|
|
433
|
+
if __name__ == "__main__":
|
|
366
434
|
import zmq
|
|
367
435
|
import struct
|
|
368
436
|
import time
|
|
437
|
+
|
|
369
438
|
speaker = ZActor(zmq.Context(), ZBeacon)
|
|
370
439
|
speaker.send_unicode("VERBOSE")
|
|
371
440
|
speaker.send_unicode("CONFIGURE", zmq.SNDMORE)
|
|
372
441
|
speaker.send(struct.pack("I", 9999))
|
|
373
442
|
speaker.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
374
443
|
import uuid
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
444
|
+
|
|
445
|
+
transmit = struct.pack(
|
|
446
|
+
"cccb16sH", b"Z", b"R", b"E", 1, uuid.uuid4().bytes, socket.htons(1300)
|
|
447
|
+
)
|
|
378
448
|
speaker.send(transmit)
|
|
379
449
|
speaker.destroy()
|
|
@@ -68,7 +68,7 @@ class ZreMsg(object):
|
|
|
68
68
|
def recv(self, input_socket):
|
|
69
69
|
# If we're reading from a ROUTER socket, get address
|
|
70
70
|
frames = input_socket.recv_multipart()
|
|
71
|
-
if input_socket.
|
|
71
|
+
if input_socket.type == zmq.ROUTER:
|
|
72
72
|
self.address = frames.pop(0)
|
|
73
73
|
# we drop the first byte: TODO ref!
|
|
74
74
|
try:
|
|
@@ -181,7 +181,7 @@ class ZreMsg(object):
|
|
|
181
181
|
logger.debug("Message type {0} unknown".format(self.id))
|
|
182
182
|
|
|
183
183
|
# If we're sending to a ROUTER, we send the address first
|
|
184
|
-
if output_socket.
|
|
184
|
+
if output_socket.type == zmq.ROUTER:
|
|
185
185
|
output_socket.send(self.address.bytes, zmq.SNDMORE)
|
|
186
186
|
# Now send the data frame
|
|
187
187
|
if (self.content):
|
|
@@ -414,9 +414,7 @@ class ZreMsg(object):
|
|
|
414
414
|
group_len = self._get_number4()
|
|
415
415
|
#print("needle is at: %i"% self._needle )
|
|
416
416
|
#print("grouplen: ", group_len)
|
|
417
|
-
self.groups = []
|
|
418
|
-
for x in range(group_len):
|
|
419
|
-
self.groups.append(self._get_long_string())
|
|
417
|
+
self.groups = [self._get_long_string() for _ in range(group_len)]
|
|
420
418
|
#print(self.groups)
|
|
421
419
|
#print("post_group: needle is at: %i"% self._needle )
|
|
422
420
|
self.status = self._get_number1()
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
Metadata-Version: 1
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: pyre-gevent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python ZRE implementation (green version)
|
|
5
5
|
Home-page: http://www.github.com/tangb/pyre-gevent/
|
|
6
6
|
Author: Arnaud Loonstra
|
|
7
7
|
Author-email: arnaud@sphaero.org
|
|
8
8
|
Maintainer: Tanguy Bonneau
|
|
9
9
|
Maintainer-email: tanguy.bonneau@gmail.com
|
|
10
|
-
License: UNKNOWN
|
|
11
|
-
Description: UNKNOWN
|
|
12
|
-
Platform: UNKNOWN
|
|
13
10
|
Requires: pyzmq
|
|
14
11
|
Requires: ipaddress
|
|
15
12
|
Requires: netaddr
|
|
16
|
-
Requires:
|
|
13
|
+
Requires: netifaces2
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
License-File: AUTHORS
|
|
@@ -19,4 +19,9 @@ pyre_gevent.egg-info/PKG-INFO
|
|
|
19
19
|
pyre_gevent.egg-info/SOURCES.txt
|
|
20
20
|
pyre_gevent.egg-info/dependency_links.txt
|
|
21
21
|
pyre_gevent.egg-info/requires.txt
|
|
22
|
-
pyre_gevent.egg-info/top_level.txt
|
|
22
|
+
pyre_gevent.egg-info/top_level.txt
|
|
23
|
+
tests/test_network_disconnect.py
|
|
24
|
+
tests/test_pyre.py
|
|
25
|
+
tests/test_zactor.py
|
|
26
|
+
tests/test_zbeacon.py
|
|
27
|
+
tests/test_zhelper.py
|
|
@@ -37,6 +37,6 @@ setup(
|
|
|
37
37
|
url='http://www.github.com/tangb/pyre-gevent/',
|
|
38
38
|
packages=['pyre_gevent'],
|
|
39
39
|
include_package_data=True,
|
|
40
|
-
requires=['pyzmq', 'ipaddress', 'netaddr', '
|
|
41
|
-
install_requires=['pyzmq', 'ipaddress', 'netaddr', '
|
|
40
|
+
requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces2'],
|
|
41
|
+
install_requires=['pyzmq', 'ipaddress', 'netaddr', 'netifaces2'],
|
|
42
42
|
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import logging
|
|
4
|
+
import subprocess
|
|
5
|
+
import pyre
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# The test needs the device name of the active network interface.
|
|
9
|
+
# The device name can be found under `DEVICE` column after running `nmcli c`.
|
|
10
|
+
# The device name should be set to the variable bellow, or as the `DEVICE` env variable.
|
|
11
|
+
NMCLI_DEVICE: str = None
|
|
12
|
+
|
|
13
|
+
NMCLI_LINETERMINATOR = "\n"
|
|
14
|
+
NMCLI_DELIMITER = " "
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _network_device() -> str:
|
|
21
|
+
return NMCLI_DEVICE or os.environ.get("DEVICE", None)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _network_device_is_enabled(device: str) -> bool:
|
|
25
|
+
result = subprocess.run(["nmcli", "c"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
26
|
+
assert result.returncode == 0, result.stderr.decode("ascii")
|
|
27
|
+
output = result.stdout.decode("ascii")
|
|
28
|
+
rows = [[val.strip() for val in row.split(NMCLI_DELIMITER) if val.strip()] for row in output.split(NMCLI_LINETERMINATOR) if row.strip()]
|
|
29
|
+
head, rows = rows[0], rows[1:]
|
|
30
|
+
devices = [dict(zip(head, row)) for row in rows]
|
|
31
|
+
return any(d["DEVICE"] == device for d in devices)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _network_device_enable(device: str, enable: bool):
|
|
35
|
+
if _network_device_is_enabled(device) == enable:
|
|
36
|
+
return
|
|
37
|
+
cmd = 'connect' if enable else 'disconnect'
|
|
38
|
+
result = subprocess.run(["nmcli", "d", cmd, f"{device}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
39
|
+
assert result.returncode == 0, result.stderr.decode("ascii")
|
|
40
|
+
time.sleep(3)
|
|
41
|
+
while _network_device_is_enabled(device) != enable:
|
|
42
|
+
pass
|
|
43
|
+
logger.debug("Device \"{device}\" was {cmd}ed")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_network_disconnect(group="best-group"):
|
|
47
|
+
|
|
48
|
+
device = _network_device()
|
|
49
|
+
|
|
50
|
+
if device is None:
|
|
51
|
+
logger.warn("Skipping test. Please specify an active network interface to use for testing.")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
_network_device_enable(device, enable=True)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
pyre_node = pyre.Pyre(name="foo")
|
|
58
|
+
pyre_node.join(group)
|
|
59
|
+
pyre_node.start()
|
|
60
|
+
logger.debug("Pyre started")
|
|
61
|
+
|
|
62
|
+
_network_device_enable(device, enable=False)
|
|
63
|
+
|
|
64
|
+
pyre_node.leave(group)
|
|
65
|
+
logger.debug("Pyre left group")
|
|
66
|
+
|
|
67
|
+
pyre_node.stop()
|
|
68
|
+
logger.debug("Pyre stopped")
|
|
69
|
+
|
|
70
|
+
del pyre_node
|
|
71
|
+
logger.debug("Pyre destroyed")
|
|
72
|
+
|
|
73
|
+
except KeyboardInterrupt:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
finally:
|
|
77
|
+
_network_device_enable(device, enable=True)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == '__main__':
|
|
81
|
+
test_network_disconnect()
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import pyre
|
|
3
|
+
import zmq
|
|
4
|
+
import time
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if sys.version.startswith('3'):
|
|
10
|
+
unicode = str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PyreTest(unittest.TestCase):
|
|
14
|
+
def setUp(self, *args, **kwargs):
|
|
15
|
+
ctx = zmq.Context()
|
|
16
|
+
self.node1 = pyre.Pyre("node1", ctx=ctx)
|
|
17
|
+
self.node1.set_header("X-TEST", "1")
|
|
18
|
+
self.node2 = pyre.Pyre("node2", ctx=ctx)
|
|
19
|
+
self.node2.set_header("X-TEST", "1")
|
|
20
|
+
self.node1.start()
|
|
21
|
+
self.node2.start()
|
|
22
|
+
# give time for nodes to exchange
|
|
23
|
+
time.sleep(1)
|
|
24
|
+
# end setUp
|
|
25
|
+
|
|
26
|
+
def tearDown(self):
|
|
27
|
+
self.node1.stop()
|
|
28
|
+
self.node2.stop()
|
|
29
|
+
# end tearDown
|
|
30
|
+
|
|
31
|
+
def test_get_name(self):
|
|
32
|
+
self.assertEqual("node1", self.node1.name())
|
|
33
|
+
self.assertEqual("node2", self.node2.name())
|
|
34
|
+
# end test_get_name
|
|
35
|
+
|
|
36
|
+
def test_get_peers(self):
|
|
37
|
+
id1 = self.node1.uuid()
|
|
38
|
+
peers = self.node2.peers()
|
|
39
|
+
|
|
40
|
+
self.assertIsInstance(peers, list)
|
|
41
|
+
self.assertIn(id1, peers)
|
|
42
|
+
# end test_get_peers
|
|
43
|
+
|
|
44
|
+
def test_get_peers_by_group(self):
|
|
45
|
+
id1 = self.node1.uuid()
|
|
46
|
+
self.node1.join("TEST")
|
|
47
|
+
# pyre works asynchronous so give some time to let changes disperse
|
|
48
|
+
time.sleep(0.5)
|
|
49
|
+
|
|
50
|
+
peers = self.node2.peers_by_group("TEST")
|
|
51
|
+
self.node1.leave("TEST")
|
|
52
|
+
|
|
53
|
+
self.assertIsInstance(peers, list)
|
|
54
|
+
self.assertIn(id1, peers)
|
|
55
|
+
# end test_get_peers
|
|
56
|
+
|
|
57
|
+
def test_get_peer_address(self):
|
|
58
|
+
id1 = self.node1.uuid()
|
|
59
|
+
id2 = self.node2.uuid()
|
|
60
|
+
|
|
61
|
+
self.assertIsInstance(self.node1.peer_address(id2), unicode)
|
|
62
|
+
self.assertIsInstance(self.node2.peer_address(id1), unicode)
|
|
63
|
+
# end test_get_peer_address
|
|
64
|
+
|
|
65
|
+
def test_peer_header_value(self):
|
|
66
|
+
id1 = self.node1.uuid()
|
|
67
|
+
id2 = self.node2.uuid()
|
|
68
|
+
|
|
69
|
+
self.assertEqual("1", self.node1.peer_header_value(id2, "X-TEST"))
|
|
70
|
+
self.assertEqual("1", self.node2.peer_header_value(id1, "X-TEST"))
|
|
71
|
+
# end test_get_peer_header_value
|
|
72
|
+
|
|
73
|
+
def test_get_own_groups(self):
|
|
74
|
+
self.node1.join("TEST")
|
|
75
|
+
self.node2.join("TEST")
|
|
76
|
+
# pyre works asynchronous so give some time to let changes disperse
|
|
77
|
+
time.sleep(0.5)
|
|
78
|
+
|
|
79
|
+
self.assertIn("TEST", self.node1.own_groups())
|
|
80
|
+
self.assertIn("TEST", self.node2.own_groups())
|
|
81
|
+
# end test_get_own_groups
|
|
82
|
+
|
|
83
|
+
def test_join_leave_msg(self):
|
|
84
|
+
msg = self.node1.recv()
|
|
85
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
86
|
+
msg = self.node2.recv()
|
|
87
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
88
|
+
self.node1.join("TEST")
|
|
89
|
+
self.node2.join("TEST")
|
|
90
|
+
msg = self.node1.recv()
|
|
91
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
92
|
+
msg = self.node2.recv()
|
|
93
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
94
|
+
self.node1.leave("TEST")
|
|
95
|
+
self.node2.leave("TEST")
|
|
96
|
+
msg = self.node1.recv()
|
|
97
|
+
self.assertEqual(msg[0], b'LEAVE')
|
|
98
|
+
msg = self.node2.recv()
|
|
99
|
+
self.assertEqual(msg[0], b'LEAVE')
|
|
100
|
+
|
|
101
|
+
def test_get_peer_groups(self):
|
|
102
|
+
self.node1.join("TEST")
|
|
103
|
+
self.node2.join("TEST")
|
|
104
|
+
|
|
105
|
+
# pyre works asynchronous so give some time to let changes disperse
|
|
106
|
+
time.sleep(0.5)
|
|
107
|
+
|
|
108
|
+
self.assertIn("TEST", self.node1.peer_groups())
|
|
109
|
+
self.assertIn("TEST", self.node2.peer_groups())
|
|
110
|
+
# end test_get_peer_groups
|
|
111
|
+
|
|
112
|
+
def test_whispers(self):
|
|
113
|
+
msg = self.node1.recv()
|
|
114
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
115
|
+
msg = self.node2.recv()
|
|
116
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
117
|
+
self.node1.whispers(self.node2.uuid(), "Hi")
|
|
118
|
+
msg = self.node2.recv()
|
|
119
|
+
self.assertEqual(b"WHISPER", msg[0])
|
|
120
|
+
self.assertEqual(self.node1.uuid().bytes, msg[1])
|
|
121
|
+
self.assertEqual(b"node1", msg[2])
|
|
122
|
+
self.assertEqual(b"Hi", msg[3])
|
|
123
|
+
|
|
124
|
+
def test_shouts(self):
|
|
125
|
+
msg = self.node1.recv()
|
|
126
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
127
|
+
msg = self.node2.recv()
|
|
128
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
129
|
+
self.node1.join("TEST")
|
|
130
|
+
self.node2.join("TEST")
|
|
131
|
+
msg = self.node1.recv()
|
|
132
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
133
|
+
msg = self.node2.recv()
|
|
134
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
135
|
+
self.node1.shouts("TEST", "Hi")
|
|
136
|
+
msg = self.node2.recv()
|
|
137
|
+
self.assertEqual(b"SHOUT", msg[0])
|
|
138
|
+
self.assertEqual(self.node1.uuid().bytes, msg[1])
|
|
139
|
+
self.assertEqual(b"node1", msg[2])
|
|
140
|
+
self.assertEqual(b"TEST", msg[3])
|
|
141
|
+
self.assertEqual(b"Hi", msg[4])
|
|
142
|
+
|
|
143
|
+
def test_shout(self):
|
|
144
|
+
msg = self.node1.recv()
|
|
145
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
146
|
+
msg = self.node2.recv()
|
|
147
|
+
self.assertEqual(msg[0], b'ENTER')
|
|
148
|
+
self.node1.join("TEST")
|
|
149
|
+
self.node2.join("TEST")
|
|
150
|
+
msg = self.node1.recv()
|
|
151
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
152
|
+
msg = self.node2.recv()
|
|
153
|
+
self.assertEqual(msg[0], b'JOIN')
|
|
154
|
+
self.node1.shout("TEST", b"Hi")
|
|
155
|
+
msg = self.node2.recv()
|
|
156
|
+
self.assertEqual(b"SHOUT", msg[0])
|
|
157
|
+
self.assertEqual(self.node1.uuid().bytes, msg[1])
|
|
158
|
+
self.assertEqual(b"node1", msg[2])
|
|
159
|
+
self.assertEqual(b"TEST", msg[3])
|
|
160
|
+
self.assertEqual(b"Hi", msg[4])
|
|
161
|
+
|
|
162
|
+
def test_zfinal(self):
|
|
163
|
+
global inst_count
|
|
164
|
+
inst_count = 1
|
|
165
|
+
self.assertTrue(True)
|
|
166
|
+
# end test_zfinal
|
|
167
|
+
# end PyreTest
|
|
168
|
+
|
|
169
|
+
if __name__ == '__main__':
|
|
170
|
+
inst_count = 0
|
|
171
|
+
|
|
172
|
+
logger = logging.getLogger("pyre")
|
|
173
|
+
logger.setLevel(logging.DEBUG)
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
unittest.main()
|
|
177
|
+
except Exception as a:
|
|
178
|
+
print(a)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import zmq
|
|
3
|
+
import logging
|
|
4
|
+
from pyre import zactor
|
|
5
|
+
from pyre.zactor import ZActor
|
|
6
|
+
from pyre.zbeacon import ZBeacon
|
|
7
|
+
|
|
8
|
+
class ZBeaconTest(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
def setUp(self, *args, **kwargs):
|
|
11
|
+
ctx = zmq.Context()
|
|
12
|
+
self.actor = ZActor(ctx, zactor.echo_actor, "Hello, World")
|
|
13
|
+
# end setUp
|
|
14
|
+
|
|
15
|
+
def tearDown(self):
|
|
16
|
+
self.actor.destroy()
|
|
17
|
+
# end tearDown
|
|
18
|
+
|
|
19
|
+
def test_echo(self):
|
|
20
|
+
self.actor.send_multipart((b"ECHO", b"This is a string"))
|
|
21
|
+
msg = self.actor.recv()
|
|
22
|
+
self.assertEqual(b"This is a string", msg)
|
|
23
|
+
# end ZActorTest
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == '__main__':
|
|
27
|
+
#print(logging.Logger.manager.loggerDict)
|
|
28
|
+
logger = logging.getLogger()
|
|
29
|
+
logger.setLevel(logging.DEBUG)
|
|
30
|
+
ch = logging.StreamHandler()
|
|
31
|
+
ch.setLevel(logging.DEBUG)
|
|
32
|
+
logger.addHandler(ch)
|
|
33
|
+
logging.getLogger("pyre.zactor").setLevel(logging.DEBUG)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
unittest.main()
|
|
37
|
+
except Exception as a:
|
|
38
|
+
print(a)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
#import pyre
|
|
3
|
+
import zmq
|
|
4
|
+
import time
|
|
5
|
+
import struct
|
|
6
|
+
import uuid
|
|
7
|
+
import logging
|
|
8
|
+
import socket
|
|
9
|
+
from pyre.zactor import ZActor
|
|
10
|
+
from pyre.zbeacon import ZBeacon
|
|
11
|
+
|
|
12
|
+
class ZBeaconTest(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
def setUp(self, *args, **kwargs):
|
|
15
|
+
ctx = zmq.Context()
|
|
16
|
+
ctx = zmq.Context()
|
|
17
|
+
# two beacon frames
|
|
18
|
+
self.transmit1 = struct.pack('cccb16sH', b'Z', b'R', b'E',
|
|
19
|
+
1, uuid.uuid4().bytes,
|
|
20
|
+
socket.htons(9999))
|
|
21
|
+
self.transmit2 = struct.pack('cccb16sH', b'Z', b'R', b'E',
|
|
22
|
+
1, uuid.uuid4().bytes,
|
|
23
|
+
socket.htons(9999))
|
|
24
|
+
|
|
25
|
+
self.node1 = ZActor(ctx, ZBeacon)
|
|
26
|
+
self.node1.send_unicode("VERBOSE")
|
|
27
|
+
self.node1.send_unicode("CONFIGURE", zmq.SNDMORE)
|
|
28
|
+
self.node1.send(struct.pack("I", 9999))
|
|
29
|
+
print("Hostname 1:", self.node1.recv_unicode())
|
|
30
|
+
|
|
31
|
+
self.node2 = ZActor(ctx, ZBeacon)
|
|
32
|
+
self.node2.send_unicode("VERBOSE")
|
|
33
|
+
self.node2.send_unicode("CONFIGURE", zmq.SNDMORE)
|
|
34
|
+
self.node2.send(struct.pack("I", 9999))
|
|
35
|
+
print("Hostname 2:", self.node2.recv_unicode())
|
|
36
|
+
# end setUp
|
|
37
|
+
|
|
38
|
+
def tearDown(self):
|
|
39
|
+
self.node1.destroy()
|
|
40
|
+
self.node2.destroy()
|
|
41
|
+
# end tearDown
|
|
42
|
+
|
|
43
|
+
def test_node1(self):
|
|
44
|
+
self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
45
|
+
self.node1.send(self.transmit1)
|
|
46
|
+
|
|
47
|
+
def test_node2(self):
|
|
48
|
+
self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
49
|
+
self.node2.send(self.transmit2)
|
|
50
|
+
|
|
51
|
+
def test_recv_beacon1(self):
|
|
52
|
+
self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
53
|
+
self.node1.send(self.transmit1)
|
|
54
|
+
self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
55
|
+
self.node2.send(self.transmit2)
|
|
56
|
+
req = self.node1.recv_multipart()
|
|
57
|
+
self.assertEqual(self.transmit2, req[1])
|
|
58
|
+
|
|
59
|
+
def test_recv_beacon1(self):
|
|
60
|
+
self.node1.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
61
|
+
self.node1.send(self.transmit1)
|
|
62
|
+
self.node2.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
63
|
+
self.node2.send(self.transmit2)
|
|
64
|
+
req = self.node2.recv_multipart()
|
|
65
|
+
self.assertEqual(self.transmit1, req[1])
|
|
66
|
+
|
|
67
|
+
# end ZBeaconTest
|
|
68
|
+
|
|
69
|
+
if __name__ == '__main__':
|
|
70
|
+
|
|
71
|
+
#print(logging.Logger.manager.loggerDict)
|
|
72
|
+
logger = logging.getLogger()
|
|
73
|
+
logger.setLevel(logging.DEBUG)
|
|
74
|
+
ch = logging.StreamHandler()
|
|
75
|
+
ch.setLevel(logging.DEBUG)
|
|
76
|
+
logger.addHandler(ch)
|
|
77
|
+
logging.getLogger("pyre.zbeacon2").setLevel(logging.DEBUG)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
unittest.main()
|
|
81
|
+
except Exception as a:
|
|
82
|
+
print(a)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from pyre import zhelper
|
|
3
|
+
from pyre import zbeacon
|
|
4
|
+
import zmq
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
class ZHelperTest(unittest.TestCase):
|
|
8
|
+
|
|
9
|
+
def test_get_ifaddrs(self):
|
|
10
|
+
ifs = zhelper.get_ifaddrs()
|
|
11
|
+
self.assertIsInstance(ifs, list)
|
|
12
|
+
self.assertIsInstance(ifs[0], dict)
|
|
13
|
+
# end test_get_ifaddrs
|
|
14
|
+
|
|
15
|
+
def test_get_ifaddrs_loopback(self):
|
|
16
|
+
ifs = zhelper.get_ifaddrs()
|
|
17
|
+
addrs = []
|
|
18
|
+
for iface in ifs:
|
|
19
|
+
#print(iface)
|
|
20
|
+
for i,v in iface.items():
|
|
21
|
+
#print(i,v)
|
|
22
|
+
# 2 is for ipv4
|
|
23
|
+
if v.get(2):
|
|
24
|
+
addrs.append(v[2]['addr'])
|
|
25
|
+
self.assertIn('127.0.0.1', addrs)
|
|
26
|
+
# end test_get_ifaddrs_loopback
|
|
27
|
+
|
|
28
|
+
# end ZHelperTest
|
|
29
|
+
|
|
30
|
+
if __name__ == '__main__':
|
|
31
|
+
unittest.main()
|
|
32
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|