The mesh schema is used as an alert and messaging network. Its primary purpose is to ensure message delivery to every participant in the network.
To connect to a mesh network, use the
MeshSocket object. This is instantiated as follows:
>>> from py2p import mesh >>> sock = mesh.MeshSocket('0.0.0.0', 4444)
'0.0.0.0' will automatically grab your LAN address. Using an outbound internet connection requires a little more work. First, ensure that you have a port forward set up (NAT busting is not in the scope of this project). Then specify your outward address as follows:
>>> from py2p import mesh >>> sock = mesh.MeshSocket('0.0.0.0', 4444, out_addr=('126.96.36.199', 44565))
>>> from py2p import mesh, base >>> sock = mesh.MeshSocket('0.0.0.0', 4444, prot=base.Protocol('mesh', 'SSL'))
Specifying a different protocol object will ensure that the node only can connect to people who share its object structure. So if someone has
'mesh2' instead of
'mesh', it will fail to connect. You can see the current default by looking at
Unfortunately, this failure is currently silent. Because this is asynchronous in nature, raising an
Exception is not possible. Because of this, it’s good to perform the following check after connecting:
>>> from py2p import mesh >>> import time >>> sock = mesh.MeshSocket('0.0.0.0', 4444) >>> sock.connect('192.168.1.14', 4567) >>> time.sleep(1) >>> assert sock.routing_table
To send a message, use the
send() method. Each argument supplied will correspond to a packet that the peer receives. In addition, there is a keyed argument you can use.
flag will specify how other nodes relay this. These flags are defined in
broadcast will indicate that other nodes are supposed to relay it.
whisper will indicate that your peers are not supposed to relay it.
>>> sock.send('this is', 'a test')
Receiving is a bit simpler. When the
recv() method is called, it returns a
Message object (or
None if there are no messages). This has a number of methods outlined which you can find by clicking its name. Most notably, you can get the packets in a message with
Message.packets, and reply directly with
>>> sock.send('Did you get this?') # A peer then replies >>> msg = sock.recv() >>> print(msg) message(type=2, packets=[b'yes', b'I did'], sender=b'6VnYj9LjoVLTvU3uPhy4nxm6yv2wEvhaRtGHeV9wwFngWGGqKAzuZ8jK6gFuvq737V') >>> print(msg.packets) [2, b'yes', b'I did'] >>> for msg in sock.recv(10): ... msg.reply("Replying to a list")
In addition to the above, the
MeshSocket object has two Events (as supplied by
Event 'connect'(). This is called whenever you finalize a connection to your distributed service. It is also called if you reconnect to the service after some failure.
>>> @sock.once('connect') >>> def call_once(conn): ... # conn is a reference to the socket, in case you're in a new scope ... # the .once() indicates that this event should only be called once ... pass ... >>> # sock.once('connect', call_once) >>> # This syntax also works >>> >>> @sock.on('connect') >>> def call_always(conn): ... # conn is still a reference to the socket ... # the .on() indicates that this event should be called *every* time ... pass ...
This class has one other event:
Event 'message'(). This one is a little bit trickier to use, and it’s recommended that you only have one callback in place at any given time. The event is called any time you receive a message that is not handled by one of the “privileged” callbacks. Such callbacks include the ones for dealing with new peers on the network.
>>> @sock.on('message') >>> def handle_msg(conn): ... # note that you are not passed a reference to the message. ... # This means that you must explicitly recv(). ... msg = conn.recv() ... if msg is not None: ... # note the guard clause for if someone else registered a callback ... msg.reply('this is an example') ...
Array.some(). In other words, when a handler returns something true-like, it stops calling handlers.
>>> from py2p import mesh, base >>> def register_1(msg, handler): # Takes in a Message and MeshConnection ... packets = msg.packets # This grabs a copy of the packets. Slightly more efficient to store this once. ... if packets == b'test': # This is the condition we want to act under ... msg.reply(b"success") # This is the response we should give ... return True # This tells the daemon we took an action, so it should stop calling handlers ... >>> def register_2(msg, handler): # This is a slightly different syntax ... packets = msg.packets ... if packets == b'test': ... handler.send(base.flags.whisper, base.flags.whisper, b"success") # One could instead reply to the node who relayed the message ... return True ... >>> sock = mesh.MeshSocket('0.0.0.0', 4444) >>> sock.register_handler(register_1) # The handler is now registered
If this does not take two arguments,
register_handler() will raise a
This library also supports the
EventEmitter API. This enables you to have methods like:
>>> from py2p import mesh >>> sock = mesh.MeshSocket('0.0.0.0', 4444) >>> @sock.on('connect') ... def on_connect(conn): ... print("Hey! You got connected!") ... >>> sock.connect('example.com', 12345) Hey! You got connected!
The mesh socket supports
To help debug these services, you can specify a
debug_level in the constructor. Using a value of 5, you can see when it enters into each handler, as well as every message which goes in or out.