-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Restructure tutorials; add sync_socket tutorial
- Loading branch information
1 parent
a30b17b
commit 970701c
Showing
5 changed files
with
171 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,10 @@ | ||
Tutorial | ||
======== | ||
|
||
Mesh Socket | ||
~~~~~~~~~~~ | ||
Contents: | ||
|
||
Basic Usage | ||
----------- | ||
.. toctree:: | ||
:maxdepth: 2 | ||
|
||
To connect to a mesh network, you will use the :js:class:`~js2p.mesh.mesh_socket` object. You can instantiate this as follows: | ||
|
||
.. code-block:: javascript | ||
> const mesh = require('js2p').mesh; | ||
> sock = new mesh.mesh_socket('0.0.0.0', 4444); | ||
Using ``'0.0.0.0'`` will (this feature in progress) automatically grab your LAN address. If you want to use an outward-facing internet connection, there is a little more work. First you need to make sure that you have a port forward setup (NAT busting is not in the scope of this project). Then you will specify this outward address as follows: | ||
|
||
.. code-block:: javascript | ||
> const mesh = require('js2p').mesh; | ||
> sock = new mesh.mesh_socket('0.0.0.0', 4444, null, ['35.24.77.21', 44565]); | ||
Specifying a different protocol object will ensure that you *only* can connect to people who share your object structure. So if someone has ``'mesh2'`` instead of ``'mesh'``, you will fail to connect. | ||
|
||
Unfortunately, this failure is currently silent. Because this is asynchronous in nature, raising an error is not possible. Because of this, it's good to perform the following check the truthiness of :js:attr:`.mesh_socket.routing_table`. If it is truthy, then you are connected to the network. | ||
|
||
To send a message, you should use the :js:func:`~js2p.mesh.mesh_socket.send` method. Each argument you supply will correspond to a packet that your peer receives. In addition, there are two keyed arguments you can use. ``flag`` will specify how other nodes relay this. These flags are defined in :js:data:`js2p.base.flags` . ``broadcast`` will indicate that other nodes are supposed to relay it. ``whisper`` will indicate that your peers are *not* supposed to relay it. There are other technically valid options, but they are not recommended. ``type`` will specify what actions other nodes are supposed to take on it. It defaults to ``broadcast``, which indicates no change from the norm. There are other valid options, but they should normally be left alone, unless you've written a handler (see below) to act on this. | ||
|
||
.. code-block:: javascript | ||
> sock.send(['this is', 'a test']); | ||
Receiving is a bit simpler. When you call the :js:func:`~js2p.mesh.mesh_socket.recv` method, you receive a :js:class:`~js2p.base.message` object. 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 :js:attr:`~js2p.base.message.packets`, and reply directly with :js:func:`~js2p.base.message.reply`. | ||
|
||
.. code-block:: javascript | ||
> sock.send(['Did you get this?']); | ||
> var msg = sock.recv(); | ||
> console.log(msg); | ||
message { | ||
type: <Buffer 02> | ||
packets: [ <Buffer 79 65 73>, <Buffer 49 20 64 69 64> ] | ||
sender: '8vu4oLsvVBsnnH6N83z6y6RZqrMKRrVHr44xRwXCFaU9qcyYsjJDzVfKwmdGp51K4d' } | ||
> msg.packets.forEach((packet) => { | ||
... var str = packet.toString() | ||
... console.log(util.inspect(str)); | ||
... }); | ||
'\u0002' | ||
'yes' | ||
'I did' | ||
> console.log(msg.packets); | ||
[ <Buffer 00>, <Buffer 79 65 73>, <Buffer 49 20 64 69 64> ] | ||
> sock.recv(10).forEach((msg) => { | ||
... msg.reply(["Replying to a list"]); | ||
... }); | ||
Advanced Usage | ||
-------------- | ||
|
||
In addition to this, you can register a custom handler for incoming messages. This is appended to the end of the included ones. When writing your handler, you must keep in mind that you are only passed a :js:class:`~js2p.base.message` object and a :js:class:`~js2p.mesh.mesh_connection`. Fortunately you can get access to everything you need from these objects. This example is in Python, but the Javascript syntax is identical. | ||
|
||
.. code-block:: python | ||
>>> def relay_tx(msg, handler): | ||
... """Relays bitcoin transactions to various services""" | ||
... packets = msg.packets # Gives a list of the non-metadata packets | ||
... server = msg.server # Returns your mesh_socket object | ||
... if packets[0] == b'tx_relay': # It's important that this flag is bytes | ||
... from pycoin import tx, services | ||
... relay = tx.Tx.from_bin(packets[1]) | ||
... services.blockchain_info.send_tx(relay) | ||
... services.insight.InsightProvider().send_tx(relay) | ||
... return True # This tells the daemon to stop calling handlers | ||
... | ||
>>> import py2p | ||
>>> sock = py2p.mesh_socket('0.0.0.0', 4444) | ||
>>> sock.register_handler(relay_tx) | ||
To help debug these services, you can specify a :js:attr:`~js2p.base.base_socket.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. | ||
tutorial/mesh | ||
tutorial/sync |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
Mesh Socket | ||
~~~~~~~~~~~ | ||
|
||
Basic Usage | ||
----------- | ||
|
||
To connect to a mesh network, you will use the :js:class:`~js2p.mesh.mesh_socket` object. You can instantiate this as follows: | ||
|
||
.. code-block:: javascript | ||
> const mesh = require('js2p').mesh; | ||
> sock = new mesh.mesh_socket('0.0.0.0', 4444); | ||
Using ``'0.0.0.0'`` will (this feature in progress) automatically grab your LAN address. If you want to use an outward-facing internet connection, there is a little more work. First you need to make sure that you have a port forward setup (NAT busting is not in the scope of this project). Then you will specify this outward address as follows: | ||
|
||
.. code-block:: javascript | ||
> const mesh = require('js2p').mesh; | ||
> sock = new mesh.mesh_socket('0.0.0.0', 4444, null, ['35.24.77.21', 44565]); | ||
Specifying a different protocol object will ensure that you *only* can connect to people who share your object structure. So if someone has ``'mesh2'`` instead of ``'mesh'``, you will fail to connect. | ||
|
||
Unfortunately, this failure is currently silent. Because this is asynchronous in nature, raising an error is not possible. Because of this, it's good to perform the following check the truthiness of :js:attr:`.mesh_socket.routing_table`. If it is truthy, then you are connected to the network. | ||
|
||
To send a message, you should use the :js:func:`~js2p.mesh.mesh_socket.send` method. Each argument you supply will correspond to a packet that your peer receives. In addition, there are two keyed arguments you can use. ``flag`` will specify how other nodes relay this. These flags are defined in :js:data:`js2p.base.flags` . ``broadcast`` will indicate that other nodes are supposed to relay it. ``whisper`` will indicate that your peers are *not* supposed to relay it. There are other technically valid options, but they are not recommended. ``type`` will specify what actions other nodes are supposed to take on it. It defaults to ``broadcast``, which indicates no change from the norm. There are other valid options, but they should normally be left alone, unless you've written a handler (see below) to act on this. | ||
|
||
.. code-block:: javascript | ||
> sock.send(['this is', 'a test']); | ||
Receiving is a bit simpler. When you call the :js:func:`~js2p.mesh.mesh_socket.recv` method, you receive a :js:class:`~js2p.base.message` object. 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 :js:attr:`~js2p.base.message.packets`, and reply directly with :js:func:`~js2p.base.message.reply`. | ||
|
||
.. code-block:: javascript | ||
> sock.send(['Did you get this?']); | ||
> var msg = sock.recv(); | ||
> console.log(msg); | ||
message { | ||
type: <Buffer 02> | ||
packets: [ <Buffer 79 65 73>, <Buffer 49 20 64 69 64> ] | ||
sender: '8vu4oLsvVBsnnH6N83z6y6RZqrMKRrVHr44xRwXCFaU9qcyYsjJDzVfKwmdGp51K4d' } | ||
> msg.packets.forEach((packet) => { | ||
... var str = packet.toString() | ||
... console.log(util.inspect(str)); | ||
... }); | ||
'\u0002' | ||
'yes' | ||
'I did' | ||
> console.log(msg.packets); | ||
[ <Buffer 00>, <Buffer 79 65 73>, <Buffer 49 20 64 69 64> ] | ||
> sock.recv(10).forEach((msg) => { | ||
... msg.reply(["Replying to a list"]); | ||
... }); | ||
Advanced Usage | ||
-------------- | ||
|
||
In addition to this, you can register a custom handler for incoming messages. This is appended to the end of the included ones. When writing your handler, you must keep in mind that you are only passed a :js:class:`~js2p.base.message` object and a :js:class:`~js2p.mesh.mesh_connection`. Fortunately you can get access to everything you need from these objects. This example is in Python, but the Javascript syntax is identical. | ||
|
||
.. code-block:: python | ||
>>> def relay_tx(msg, handler): | ||
... """Relays bitcoin transactions to various services""" | ||
... packets = msg.packets # Gives a list of the non-metadata packets | ||
... server = msg.server # Returns your mesh_socket object | ||
... if packets[0] == b'tx_relay': # It's important that this flag is bytes | ||
... from pycoin import tx, services | ||
... relay = tx.Tx.from_bin(packets[1]) | ||
... services.blockchain_info.send_tx(relay) | ||
... services.insight.InsightProvider().send_tx(relay) | ||
... return True # This tells the daemon to stop calling handlers | ||
... | ||
>>> import py2p | ||
>>> sock = py2p.mesh_socket('0.0.0.0', 4444) | ||
>>> sock.register_handler(relay_tx) | ||
To help debug these services, you can specify a :js:attr:`~js2p.base.base_socket.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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
Sync Socket | ||
~~~~~~~~~~~ | ||
|
||
This is an extension of the :js:class:`~js2p.mesh.mesh_socket` which syncronizes a common :js:class:`Object`. It works by providing an extra handler to store data. This does not expose the entire :js:class:`Object` API, but it exposes a substantial subset, and we're working to expose more. | ||
|
||
.. note:: | ||
|
||
This is a fairly inefficient architecture for write intensive applications. For cases where the majority of access is reading, or for small networks, this is ideal. For larger networks where a significant portion of your operations are writing values, you should wait for the chord socket to come into beta. | ||
|
||
Basic Usage | ||
----------- | ||
|
||
There are three limitations compared to a normal :js:class:`Object`. | ||
|
||
1. Keys and values must be translatable to a :js:class:`Buffer` | ||
2. Keys and values are automatically translated to a :js:class:`Buffer` | ||
3. By default, this implements a leasing system which prevents you from changing values set by others for a certain time | ||
|
||
You can override the last restriction by constructing with ``leasing`` set to ``false``, like so: | ||
|
||
.. code-block:: javascript | ||
> const sync = require('js2p').sync; | ||
> let sock = new sync.sync_socket('0.0.0.0', 4444, false); | ||
The only API differences between this and :js:class:`~js2p.mesh.mesh_socket` are for access to this dictionary. They are as follows. | ||
|
||
:js:func:`~js2p.sync.sync_socket.get` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
A value can be retrieved by using the :js:func:`~js2p.sync.sync_socket.get` method. This is reading from a local :js:class:`Object`, so speed shouldn't be a factor. | ||
|
||
.. code-block:: javascript | ||
> let foo = sock.get('test key', null) // Returns null if there is nothing at that key | ||
> let bar = sock.get('test key') // Returns undefined if there is nothing at that key | ||
It is important to note that keys are all translated to a :js:class:`Buffer` before being used. | ||
|
||
:js:func:`~js2p.sync.sync_socket.set` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
A value can be stored by using the :js:func:`~js2p.sync.sync_socket.set` method. These calls are ``O(n)``, as it has to change values on other nodes. More accurately, the delay between your node knowing of the change and the last node knowing of the change is ``O(n)``. | ||
|
||
.. code-block:: javascript | ||
> sock.set('test key', 'value'); | ||
> sock.set('测试', 'test'); | ||
Like above, keys and values are all translated to :js:class:`Buffer` before being used | ||
|
||
This will raise an :js:class:`Error` if another node has set this value already. Their lease will expire one hour after they set it. If two leases are started at the same UTC second, the tie is settled by doing a string compare of their IDs. | ||
|
||
Any node which sets a value can change this value as well. Changing the value renews the lease on it. | ||
|
||
:js:func:`~js2p.sync.sync_socket.__delitem__` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Any node which owns a key, can clear its value. Doing this will relinquish your lease on that value. Like the above, this call is ``O(n)``. | ||
|
||
.. code-block:: javascript | ||
> sock.del('test'); | ||
:js:func:`~js2p.sync.sync_socket.update` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
The update method is simply a wrapper which updates based on a fed :js:class:`Object`. Essentially it runs the following: | ||
|
||
.. code-block:: javascript | ||
> for (var key in update_dict) { | ||
... sock.set(key, update_dict[key]); | ||
... } | ||
Advanced Usage | ||
-------------- | ||
|
||
Refer to :doc:`the mesh socket tutorial <./mesh>` |