pyre-gevent 0.2.4.dev0__tar.gz → 0.3.1__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.4.dev0/pyre_gevent.egg-info → pyre-gevent-0.3.1}/PKG-INFO +5 -6
- pyre-gevent-0.3.1/pyre_gevent/__init__.py +8 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre.py +1 -1
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_event.py +2 -4
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_node.py +3 -4
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zbeacon.py +138 -82
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zre_msg.py +1 -3
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1/pyre_gevent.egg-info}/PKG-INFO +5 -6
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/SOURCES.txt +6 -1
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/requires.txt +1 -1
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/setup.py +2 -2
- pyre-gevent-0.3.1/tests/test_network_disconnect.py +81 -0
- pyre-gevent-0.3.1/tests/test_pyre.py +178 -0
- pyre-gevent-0.3.1/tests/test_zactor.py +38 -0
- pyre-gevent-0.3.1/tests/test_zbeacon.py +82 -0
- pyre-gevent-0.3.1/tests/test_zhelper.py +32 -0
- pyre-gevent-0.2.4.dev0/pyre_gevent/__init__.py +0 -8
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/AUTHORS +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/LICENSE +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/MANIFEST.in +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/README.md +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_group.py +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/pyre_peer.py +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zactor.py +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zhelper.py +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent/zsocket.py +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/dependency_links.txt +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/pyre_gevent.egg-info/top_level.txt +0 -0
- {pyre-gevent-0.2.4.dev0 → pyre-gevent-0.3.1}/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.1
|
|
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,7 @@ 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
305
|
self.remove_peer(peer)
|
|
306
306
|
peer.disconnect()
|
|
307
307
|
logger.debug("Purge peer: {0}{1}".format(peer,endpoint))
|
|
@@ -411,7 +411,7 @@ class PyreNode(object):
|
|
|
411
411
|
|
|
412
412
|
# Ignore command if peer isn't ready
|
|
413
413
|
if not peer or not peer.get_ready():
|
|
414
|
-
logger.
|
|
414
|
+
logger.debug("Peer {0} isn't ready".format(peer))
|
|
415
415
|
return
|
|
416
416
|
|
|
417
417
|
if peer.messages_lost(zmsg):
|
|
@@ -531,8 +531,7 @@ class PyreNode(object):
|
|
|
531
531
|
reap_at = time.time() + REAP_INTERVAL
|
|
532
532
|
while not self._terminated:
|
|
533
533
|
timeout = reap_at - time.time()
|
|
534
|
-
|
|
535
|
-
timeout = 0
|
|
534
|
+
timeout = max(timeout, 0)
|
|
536
535
|
items = dict(self.poller.poll(timeout * 1000))
|
|
537
536
|
|
|
538
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,28 +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 =
|
|
43
|
-
ENETDOWN = 50
|
|
44
|
-
ENETUNREACH = 51
|
|
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
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
class ZBeacon(object):
|
|
48
47
|
|
|
49
48
|
def __init__(self, ctx, pipe, *args, **kwargs):
|
|
50
|
-
self.ctx = ctx
|
|
51
|
-
self.pipe = pipe
|
|
52
|
-
self.udpsock = socket.socket(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
self.
|
|
57
|
-
self.
|
|
58
|
-
self.
|
|
59
|
-
|
|
60
|
-
self.
|
|
61
|
-
|
|
62
|
-
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
|
|
63
64
|
|
|
64
65
|
self.address = None
|
|
65
66
|
self.mac = None
|
|
@@ -73,23 +74,25 @@ class ZBeacon(object):
|
|
|
73
74
|
self.udpsock.close()
|
|
74
75
|
|
|
75
76
|
def prepare_udp(self, interface_name=None):
|
|
76
|
-
|
|
77
|
+
try:
|
|
78
|
+
self._prepare_socket(interface_name)
|
|
79
|
+
except ValueError:
|
|
80
|
+
logger.exception("Error preparing socket:")
|
|
81
|
+
return
|
|
77
82
|
try:
|
|
78
83
|
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
79
84
|
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
80
85
|
|
|
81
86
|
# On some platforms we have to ask to reuse the port
|
|
82
87
|
try:
|
|
83
|
-
self.udpsock.setsockopt(socket.SOL_SOCKET,
|
|
84
|
-
socket.SO_REUSEPORT, 1)
|
|
88
|
+
self.udpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
|
85
89
|
|
|
86
90
|
except AttributeError:
|
|
87
91
|
pass
|
|
88
92
|
|
|
89
93
|
if self.broadcast_address.is_multicast:
|
|
90
94
|
# TTL
|
|
91
|
-
self.udpsock.setsockopt(socket.IPPROTO_IP,
|
|
92
|
-
socket.IP_MULTICAST_TTL, 2)
|
|
95
|
+
self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
|
|
93
96
|
|
|
94
97
|
# TODO: This should only be used if we do not have inproc method!
|
|
95
98
|
self.udpsock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
|
|
@@ -117,48 +120,63 @@ class ZBeacon(object):
|
|
|
117
120
|
self.udpsock.bind(("", self.port_nbr))
|
|
118
121
|
|
|
119
122
|
group = socket.inet_aton("{0}".format(self.broadcast_address))
|
|
120
|
-
mreq = struct.pack(
|
|
123
|
+
mreq = struct.pack("4sl", group, socket.INADDR_ANY)
|
|
121
124
|
|
|
122
|
-
self.udpsock.setsockopt(socket.SOL_IP,
|
|
123
|
-
socket.IP_ADD_MEMBERSHIP, mreq)
|
|
125
|
+
self.udpsock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
|
124
126
|
|
|
125
127
|
else:
|
|
126
128
|
# Platform specifics
|
|
127
129
|
if platform.startswith("linux"):
|
|
128
130
|
# on linux we bind to the broadcast address and send to
|
|
129
131
|
# the broadcast address
|
|
130
|
-
self.udpsock.bind((str(self.broadcast_address),
|
|
131
|
-
self.port_nbr))
|
|
132
|
+
self.udpsock.bind((str(self.broadcast_address), self.port_nbr))
|
|
132
133
|
else:
|
|
133
134
|
self.udpsock.bind(("", self.port_nbr))
|
|
134
135
|
|
|
135
|
-
logger.debug(
|
|
136
|
+
logger.debug(
|
|
137
|
+
"Set up a broadcast beacon to {0}:{1}".format(
|
|
138
|
+
self.broadcast_address, self.port_nbr
|
|
139
|
+
)
|
|
140
|
+
)
|
|
136
141
|
except socket.error:
|
|
137
|
-
logger.exception(
|
|
142
|
+
logger.exception(
|
|
143
|
+
"Initializing of {0} raised an exception".format(
|
|
144
|
+
self.__class__.__name__
|
|
145
|
+
)
|
|
146
|
+
)
|
|
138
147
|
|
|
139
148
|
def _prepare_socket(self, interface_name=None):
|
|
140
149
|
netinf = zhelper.get_ifaddrs()
|
|
141
150
|
logger.debug("Available interfaces: {0}".format(netinf))
|
|
142
151
|
|
|
143
|
-
#get default gateway interface
|
|
152
|
+
# get default gateway interface
|
|
144
153
|
default_interface_names = []
|
|
145
154
|
netifaces_default_interface_names = []
|
|
146
155
|
gateways = netifaces.gateways()
|
|
147
156
|
logger.debug("Gateways: {0}".format(gateways))
|
|
148
157
|
if netifaces.AF_INET in gateways:
|
|
149
158
|
for address, interface, is_default in gateways[netifaces.AF_INET]:
|
|
150
|
-
#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)
|
|
151
160
|
if platform.startswith("win"):
|
|
152
161
|
netifaces_default_interface_names.append(interface)
|
|
153
162
|
for iface in netinf:
|
|
154
163
|
for name, data in iface.items():
|
|
155
|
-
if
|
|
164
|
+
if (
|
|
165
|
+
netifaces.AF_INET in data
|
|
166
|
+
and data[netifaces.AF_INET]["adapter"] == interface
|
|
167
|
+
):
|
|
156
168
|
default_interface_names.append(name)
|
|
157
169
|
else:
|
|
158
170
|
default_interface_names.append(interface)
|
|
159
|
-
|
|
160
|
-
logger.debug(
|
|
161
|
-
|
|
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
|
+
)
|
|
162
180
|
|
|
163
181
|
for iface in netinf:
|
|
164
182
|
# Loop over the interfaces and their settings to try to find the broadcast address.
|
|
@@ -168,39 +186,53 @@ class ZBeacon(object):
|
|
|
168
186
|
if interface_name and interface_name != name:
|
|
169
187
|
continue
|
|
170
188
|
|
|
171
|
-
#Interface of default route found, skip other ones
|
|
172
|
-
#This trick allows to skip invalid interfaces like docker ones.
|
|
173
|
-
if
|
|
174
|
-
|
|
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
|
+
)
|
|
175
198
|
continue
|
|
176
199
|
|
|
177
|
-
logger.debug(
|
|
200
|
+
logger.debug("Checking out interface '{0}'.".format(name))
|
|
178
201
|
|
|
179
|
-
#Get addr and netmask infos
|
|
202
|
+
# Get addr and netmask infos
|
|
180
203
|
data_2 = data.get(netifaces.AF_INET)
|
|
181
204
|
if not data_2:
|
|
182
|
-
logger.debug(
|
|
205
|
+
logger.debug("No data_2 found for interface '{0}'.".format(name))
|
|
183
206
|
continue
|
|
184
207
|
|
|
185
|
-
#get mac address infos
|
|
186
|
-
data_17 = data.get(netifaces.
|
|
208
|
+
# get mac address infos
|
|
209
|
+
data_17 = data.get(netifaces.AF_PACKET)
|
|
187
210
|
if not data_17 and platform.startswith("win"):
|
|
188
|
-
#last chance to get mac address on windows platform
|
|
189
|
-
for
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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]
|
|
193
223
|
break
|
|
194
224
|
if not data_17:
|
|
195
|
-
logger.debug(
|
|
225
|
+
logger.debug("No data_17 found for interface '{0}'.".format(name))
|
|
196
226
|
continue
|
|
197
227
|
|
|
198
228
|
address_str = data_2.get("addr")
|
|
199
229
|
netmask_str = data_2.get("netmask")
|
|
200
|
-
mac_str = data_17.get("addr")
|
|
230
|
+
mac_str = data_17.get("addr")
|
|
201
231
|
|
|
202
232
|
if not address_str or not netmask_str:
|
|
203
|
-
logger.debug(
|
|
233
|
+
logger.debug(
|
|
234
|
+
"Address or netmask not found for interface '{0}'.".format(name)
|
|
235
|
+
)
|
|
204
236
|
continue
|
|
205
237
|
|
|
206
238
|
if isinstance(address_str, bytes):
|
|
@@ -212,10 +244,24 @@ class ZBeacon(object):
|
|
|
212
244
|
if isinstance(mac_str, bytes):
|
|
213
245
|
mac_str = mac_str.decode("utf8")
|
|
214
246
|
|
|
215
|
-
#keep only private interface
|
|
247
|
+
# keep only private interface
|
|
216
248
|
ip_address = netaddr.IPAddress(address_str)
|
|
217
|
-
|
|
218
|
-
|
|
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
|
+
)
|
|
219
265
|
continue
|
|
220
266
|
|
|
221
267
|
interface_string = "{0}/{1}".format(address_str, netmask_str)
|
|
@@ -223,11 +269,11 @@ class ZBeacon(object):
|
|
|
223
269
|
interface = ipaddress.ip_interface(u(interface_string))
|
|
224
270
|
|
|
225
271
|
if interface.is_loopback:
|
|
226
|
-
logger.debug(
|
|
272
|
+
logger.debug("Interface {0} is a loopback device.".format(name))
|
|
227
273
|
continue
|
|
228
274
|
|
|
229
275
|
if interface.is_link_local:
|
|
230
|
-
logger.debug(
|
|
276
|
+
logger.debug("Interface {0} is a link-local device.".format(name))
|
|
231
277
|
continue
|
|
232
278
|
|
|
233
279
|
self.address = interface.ip
|
|
@@ -238,17 +284,17 @@ class ZBeacon(object):
|
|
|
238
284
|
|
|
239
285
|
if self.address:
|
|
240
286
|
break
|
|
241
|
-
|
|
287
|
+
|
|
242
288
|
if self.address:
|
|
243
289
|
break
|
|
244
290
|
|
|
245
291
|
logger.debug("Finished scanning interfaces.")
|
|
246
292
|
|
|
247
293
|
if not self.address:
|
|
248
|
-
self.network_address = ipaddress.IPv4Address(u(
|
|
294
|
+
self.network_address = ipaddress.IPv4Address(u("127.0.0.1"))
|
|
249
295
|
self.broadcast_address = ipaddress.IPv4Address(u(MULTICAST_GRP))
|
|
250
|
-
self.interface_name =
|
|
251
|
-
self.address = u(
|
|
296
|
+
self.interface_name = "loopback"
|
|
297
|
+
self.address = u("127.0.0.1")
|
|
252
298
|
self.mac = None
|
|
253
299
|
|
|
254
300
|
logger.debug("Address: {0}".format(self.address))
|
|
@@ -265,9 +311,9 @@ class ZBeacon(object):
|
|
|
265
311
|
def handle_pipe(self):
|
|
266
312
|
# Get just the commands off the pipe
|
|
267
313
|
request = self.pipe.recv_multipart()
|
|
268
|
-
command = request.pop(0).decode(
|
|
314
|
+
command = request.pop(0).decode("UTF-8")
|
|
269
315
|
if not command:
|
|
270
|
-
return -1
|
|
316
|
+
return -1 # Interrupted
|
|
271
317
|
|
|
272
318
|
if self.verbose:
|
|
273
319
|
logger.debug("zbeacon: API command={0}".format(command))
|
|
@@ -278,10 +324,13 @@ class ZBeacon(object):
|
|
|
278
324
|
# unpacking code from https://bit.ly/2qN3ZUz
|
|
279
325
|
interface_data = request.pop(0)
|
|
280
326
|
|
|
281
|
-
(interface_name_len,), interface =
|
|
282
|
-
|
|
327
|
+
(interface_name_len,), interface = (
|
|
328
|
+
struct.unpack("I", interface_data[:4]),
|
|
329
|
+
interface_data[4:],
|
|
330
|
+
)
|
|
331
|
+
interface = interface.decode("UTF-8")
|
|
283
332
|
|
|
284
|
-
port = struct.unpack(
|
|
333
|
+
port = struct.unpack("I", request.pop(0))[0]
|
|
285
334
|
self.configure(interface, port)
|
|
286
335
|
elif command == "PUBLISH":
|
|
287
336
|
self.transmit = request.pop(0)
|
|
@@ -314,8 +363,8 @@ class ZBeacon(object):
|
|
|
314
363
|
is_valid = False
|
|
315
364
|
if self.filter is not None:
|
|
316
365
|
if len(self.filter) <= len(frame):
|
|
317
|
-
match_data = frame[:len(self.filter)]
|
|
318
|
-
if
|
|
366
|
+
match_data = frame[: len(self.filter)]
|
|
367
|
+
if match_data == self.filter:
|
|
319
368
|
is_valid = True
|
|
320
369
|
|
|
321
370
|
# If valid, discard our own broadcasts, which UDP echoes to us
|
|
@@ -330,22 +379,24 @@ class ZBeacon(object):
|
|
|
330
379
|
|
|
331
380
|
def send_beacon(self):
|
|
332
381
|
try:
|
|
333
|
-
self.udpsock.sendto(
|
|
334
|
-
|
|
335
|
-
|
|
382
|
+
self.udpsock.sendto(
|
|
383
|
+
self.transmit, (str(self.broadcast_address), self.port_nbr)
|
|
384
|
+
)
|
|
385
|
+
|
|
336
386
|
except OSError as e:
|
|
337
|
-
|
|
387
|
+
|
|
338
388
|
# network down, just wait, it could come back up again.
|
|
339
389
|
# socket call errors 50 and 51 relate to the network being
|
|
340
|
-
# down or unreachable, the recommended action to take is to
|
|
390
|
+
# down or unreachable, the recommended action to take is to
|
|
341
391
|
# try again so we don't terminate in these cases.
|
|
342
|
-
if e.errno in [ENETDOWN, ENETUNREACH]:
|
|
343
|
-
|
|
392
|
+
if e.errno in [ENETDOWN, ENETUNREACH]:
|
|
393
|
+
pass
|
|
394
|
+
|
|
344
395
|
# all other cases, we'll terminate
|
|
345
396
|
else:
|
|
346
397
|
logger.debug("Network seems gone, exiting zbeacon")
|
|
347
398
|
self.terminated = True
|
|
348
|
-
|
|
399
|
+
|
|
349
400
|
except socket.error:
|
|
350
401
|
logger.debug("Network seems gone, exiting zbeacon")
|
|
351
402
|
self.terminated = True
|
|
@@ -368,7 +419,10 @@ class ZBeacon(object):
|
|
|
368
419
|
items = dict(self.poller.poll(timeout * 1000))
|
|
369
420
|
if self.pipe in items and items[self.pipe] == zmq.POLLIN:
|
|
370
421
|
self.handle_pipe()
|
|
371
|
-
if
|
|
422
|
+
if (
|
|
423
|
+
self.udpsock.fileno() in items
|
|
424
|
+
and items[self.udpsock.fileno()] == zmq.POLLIN
|
|
425
|
+
):
|
|
372
426
|
self.handle_udp()
|
|
373
427
|
|
|
374
428
|
if self.transmit and time.time() >= self.ping_at:
|
|
@@ -376,18 +430,20 @@ class ZBeacon(object):
|
|
|
376
430
|
self.ping_at = time.time() + self.interval
|
|
377
431
|
|
|
378
432
|
|
|
379
|
-
if __name__ ==
|
|
433
|
+
if __name__ == "__main__":
|
|
380
434
|
import zmq
|
|
381
435
|
import struct
|
|
382
436
|
import time
|
|
437
|
+
|
|
383
438
|
speaker = ZActor(zmq.Context(), ZBeacon)
|
|
384
439
|
speaker.send_unicode("VERBOSE")
|
|
385
440
|
speaker.send_unicode("CONFIGURE", zmq.SNDMORE)
|
|
386
441
|
speaker.send(struct.pack("I", 9999))
|
|
387
442
|
speaker.send_unicode("PUBLISH", zmq.SNDMORE)
|
|
388
443
|
import uuid
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
444
|
+
|
|
445
|
+
transmit = struct.pack(
|
|
446
|
+
"cccb16sH", b"Z", b"R", b"E", 1, uuid.uuid4().bytes, socket.htons(1300)
|
|
447
|
+
)
|
|
392
448
|
speaker.send(transmit)
|
|
393
449
|
speaker.destroy()
|
|
@@ -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.1
|
|
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
|