{"_id":"r5n","_rev":"26-27730e963421896c6775d64177181b3a","name":"r5n","description":"An implementation of the R5N distributed hash table","dist-tags":{"latest":"0.2.11"},"versions":{"0.2.0":{"name":"r5n","version":"0.2.0","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"deferred":"*"},"_id":"r5n@0.2.0","dist":{"shasum":"bf8a21a8123417727f0f996470d1dbb5e6727a56","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.0.tgz","integrity":"sha512-wDiFfujabxdI+4ijIwV9Ja9YBu8uLSYWMj0J8vwV6nTgKOF2vOllT+MgoyoPEHj7Qy9iINM8wQrMy1I6bNjv3Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDBrRWxAedw0s0YrQVFh7q8GEbnorkefuqigU+sRVnhEAIgPB6fu98pijocwjusbbeBaJfj3vy/PCeGWfXAKOZn3Mg="}]},"_from":"./","_npmVersion":"1.4.3","_npmUser":{"name":"staltz","email":"andre+npm@staltz.com"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"}]},"0.2.1":{"name":"r5n","version":"0.2.1","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"deferred":"*"},"_id":"r5n@0.2.1","dist":{"shasum":"e0c8d4415273f2da9db794aa546f196ff9e6d82e","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.1.tgz","integrity":"sha512-xEXsj5kGkBZj+ZsBXQHlAXDHrXgQvgx1briK2P3bYPyq1syxReDiIXp+h7oiE65ipbI6phaPfOfRqlQPlC8+5w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDWZtWhO+Z3gQtQwKmDUs2WbjEOtoesyIYHOk1v7GivKAiEApbbYZ8yzNI2WxrB3gkMI4gt7c6jBhllecpwlf84SaVk="}]},"_from":".","_npmVersion":"1.4.3","_npmUser":{"name":"staltz","email":"andre+npm@staltz.com"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"}]},"0.2.3":{"name":"r5n","version":"0.2.3","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"deferred":"*"},"_id":"r5n@0.2.3","dist":{"shasum":"1b5f575eb0d8306bb6d41883d121fdc1139cb74d","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.3.tgz","integrity":"sha512-GS4l40URx3sSpfc/d4AJmHbYu1fT2/aGVsBvJrSC5mX26D4zLUO2UdMRzsyf61d3glKGW5xFVwQBbGIkF73zDQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzkfvzi/+6dXA0ufGGBwtyqzk91ZLAl0beFxp53iI9AQIgUVSOze6g5N7DlTOu8c4IeYpU8RYu2AfjwxxU9ad/POw="}]},"_from":".","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.4":{"name":"r5n","version":"0.2.4","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"deferred":"*"},"_id":"r5n@0.2.4","dist":{"shasum":"41fa73c6228d2e1f766122476ac460544e9fbe52","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.4.tgz","integrity":"sha512-PFDdSnSJusxwLkMm1dWtcZqJ9Octzyl9i5nmeFoavl4CDNAKEwCa++fZEDnwEhKpCqkIc+hQB5t8S/S4SQ67ug==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDV57Mow2OBVeL+cZEsGRy2UYZuhRJTafAr+FXxWaRnxQIgSgXdNafpXT0wdTbQbCaYy6KJg77Fap+wiZ8XP72IrV0="}]},"_from":"./","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.5":{"name":"r5n","version":"0.2.5","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"deferred":"0.7.1"},"_id":"r5n@0.2.5","dist":{"shasum":"749c6c3fb4f198c7bed9d2e3d8a1029eeac105fb","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.5.tgz","integrity":"sha512-vyZaDPXvyhx8ZdhtPGldQhezgi+SX7DCCLY6VWUeVIHgUtdf7FtyqAT4FDyL58aco3n8uhPdFiEe52O+uZQs+Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEqTTlq8UyWLftcbrciJ4BYuXn27YQRZ+8wT24ANrGpyAiEAp9iJbJakK45s2O3tGlbNV4GKNZp0Nj+dc6jEmmtMNQg="}]},"_from":"./","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.6":{"name":"r5n","version":"0.2.6","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"avlogger":"git+https://code.avatar.ai/avatar/logger.git#0.1.0","deferred":"0.7.1"},"devDependencies":{"gulp":"^3.6.1","gulp-jshint":"^1.5.3","gulp-jscs":"^0.4.1","jshint-stylish":"^0.1.5","exec-sync":"^0.1.6","semver":"^2.3.0"},"_id":"r5n@0.2.6","dist":{"shasum":"6cf434b8315fd5ddb2d6c98e914131b49299d6f3","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.6.tgz","integrity":"sha512-/6iwkxF0gvOmrPOvT+znzs/Gf86WCDYAj4g0SdSko88MQSTORKiWx1u+VBQFhzEvAU5zdI5Z1Vj8jmrXQgTupQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMf6lv6opttNV3soU6y11A1SP8OXJPrnuEjaQmNt3yGQIhAKI7iq9jJ7Ic85eJ/XtgEBLGZaPDTjq17xT8kOz5fwGE"}]},"_from":".","_npmVersion":"1.4.3","_npmUser":{"name":"staltz","email":"andre+npm@staltz.com"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.8":{"name":"r5n","version":"0.2.8","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"avlogger":"git+https://code.avatar.ai/avatar/logger.git#0.1.0","deferred":"0.7.1"},"devDependencies":{"gulp":"^3.6.1","gulp-jshint":"^1.5.3","gulp-jscs":"^0.4.1","jshint-stylish":"^0.1.5","execSync":"*","semver":"^2.3.0"},"_id":"r5n@0.2.8","dist":{"shasum":"25ee7245b2048d3d639b656ed84f4eaf7c5274ed","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.8.tgz","integrity":"sha512-nxkES9o7GauD14piDXAiGFu6Bq7fjDkSGumniE6rm3sS41leSarZEFYXppCbzuUXtfHsWT0aknhNjPIKXhYWoQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCZpbyCf0DSG4rLkU+lW3j0FHSsafNOQT0z+GW+QXqAogIgKWN/PvfvOredxBeGaVHKKOqgCY7GxuDUzfUSXULbKcY="}]},"_from":".","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.9":{"name":"r5n","version":"0.2.9","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"avlogger":"git+https://code.avatar.ai/avatar/logger.git#0.1.0","deferred":"0.7.1"},"devDependencies":{"gulp":"^3.6.1","gulp-jshint":"^1.5.3","gulp-jscs":"^0.4.1","jshint-stylish":"^0.1.5","execSync":"^1.0.1","semver":"^2.3.0"},"_id":"r5n@0.2.9","dist":{"shasum":"3e9031f59e98ceef54ad54d7783cc284f95c18bf","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.9.tgz","integrity":"sha512-U+n751QlfUMSQWrisHJl98uhqo6dM2opO6oCIq/lAiOniWRQVGLpKgqhJwJZ8AKwEgDUdastXlmrhSOgVwW+Lg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC8crhGRN3mX2bNIhDjFaz//pNiYHNuY+LdBHRFyuB51wIhAMbGCzB3117w0MT6gYWtac8Vf7gfoibgS5zPyp1zlN9H"}]},"_from":"./","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.10":{"name":"r5n","version":"0.2.10","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"avlogger":"git+https://code.avatar.ai/avatar/logger.git#0.1.0","deferred":"0.7.1"},"devDependencies":{"gulp":"^3.6.1","gulp-jshint":"^1.5.3","gulp-jscs":"^0.4.1","jshint-stylish":"^0.1.5","execSync":"^1.0.1","semver":"^2.3.0"},"_id":"r5n@0.2.10","dist":{"shasum":"198f42f1fec7213a832230e7e1a120d543bb530f","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.10.tgz","integrity":"sha512-/zG3Mv/jQaxMYzQQP7WnOaXfsscMWqBU3fs4yluXva6CfcyEcfQxOF/u6ZxvgMsz/TIxQSZMcLjxzMomih1a9w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCznZk29GcBV/oE+YFz4LA2O2LEWwVaxcuzbvlF5/yWpwIgFhQ4kjSVzp4R6r5cjGI522D7OeZPu4mdO3DbRJLCiUI="}]},"_from":"./","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]},"0.2.11":{"name":"r5n","version":"0.2.11","author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"description":"An implementation of the R5N distributed hash table","contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"main":"./lib/dht","repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"keywords":["dht","r5n","avatar"],"license":"MIT","engines":{"node":"0.10.x"},"dependencies":{"avlogger":"git+ssh://git@code.avatar.ai:6000/avatar/logger.git#0.1.0","deferred":"0.7.1"},"devDependencies":{"gulp":"^3.6.1","gulp-jshint":"^1.5.3","gulp-jscs":"^0.4.1","jshint-stylish":"^0.1.5","execSync":"^1.0.1","semver":"^2.3.0"},"_id":"r5n@0.2.11","dist":{"shasum":"9a812781c596c8da235da04357db789dd127dc8d","tarball":"https://registry.npmjs.org/r5n/-/r5n-0.2.11.tgz","integrity":"sha512-MTAYfoaYLFxVbYGZxsIdxYQNW30QrGx4+/vz5eL3dOLyalbujt3xZaLN5yDpE4w0mFMTVnYEoNuRLL0dzZpTSA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgB6CXYj6cUJqRoNga2ZGcgKJoyyEZRPYqIAWYgAG/0QIhAMaKbR3lZHGqW/7h5dsS4EPAjPYNK2vpgjwFBPSm7mPY"}]},"_from":".","_npmVersion":"1.3.24","_npmUser":{"name":"avatar_dave","email":"dave@avatar.ai"},"maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}]}},"readme":"# Welcome to the R5N DHT Repository\nProject Lead: Dave Hagman aka [avatar_dave](https://discussions.avatar.ai/user/avatar_dave)\n\nProject Start: 2/8/2014\n\nProject Description: A JavaScript DHT implementation using the [R5N routing algorithm](https://gnunet.org/sites/default/files/nss2011.pdf).\n\nCurrent development notes: Since this is in active development this code should not be used in any production applications. The code is still\nin Alpha stage.\n\n### Introduction\n\nR5N is a Javascript implementation of a [Distributed Hash Table](http://en.wikipedia.org/wiki/Distributed_hash_table)  using the [R5N routing algorithm](https://gnunet.org/sites/default/files/nss2011.pdf).\nThis module has all the functionality of a DHT plus the ability to define custom message handlers.\n\n### Configuring the DHT\nAll configuration options are stored in a Globals object (`/lib/globals.js`). Some of the common, *safe* configuration values are below. We call them\n*safe* if it is something the developer can change without serious implications to the DHT. Any configuration setting not mentioned below __should not__ be changed\nunless you are 100% sure of the implications.\n\n#### Category: Network\n\n* `DHT_PUBLIC_ADDRESS` - The public address for the DHT **(required)**\n* `DHT_INIT_PORT` - The start port for the DHT. This is the port that the DHT will bind a listener socket to. **(required)**\n* `ESTIMATED_PEER_COUNT` - The estimated number of peers on the network. This should be adjusted if the network grows or shrinks by any significant amount.\n* `ESTIMATED_CONN_PER_PEER` - The estimated amount of connections a peer will have at any one time. \n\n#### Category: KeyProps\n\n* `DEFAULT_KEY_LENGTH` - The default length for generated keys such as client ID and node ID.\n\n#### Category: RecursiveRouting\n\n* `MAX_FIND_VALUE_ATTEMPTS` - The maximum number of times to retry a failed FIND_VALUE operation.\n\n#### Category: AsyncTasks\n\n* `CLEAR_PING_REQ_QUEUE` - Interval for clearing the failed ping request queue and clearing stale nodes.\n* `CLEAR_PING_REQ_QUEUE` - Interval (in ms) for performing replication of data to peer nodes. \n\n\n### Starting the DHT\nThe process for starting the DHT differs upon whether we are \"bootstrapping\" off a running DHT node or we are spinning up a new DHT.\n\n\n#### Creating the first node\nIn this scenario we are creating a new DHT. All we need to do is instantiate a new DHT and start it. Once other nodes are spun up we \nneed to follow the bootstrap process below.\n\n```javascript\nvar DHT = require(__dirname + '/lib/dht');\n\n// Put the IP address and port for the DHT here\n// NOTE: This is the public IP for this node, not localhost or 127.0.0.1\nvar address = 'IP_ADDRESS';\nvar port = 3000;\n\n// Instantiate new DHT and start it\nvar dht = new DHT({\n    IP: address,\n    port: port\n});\ndht.start().then(function(res) {\n\tconsole.log('DHT started.');\n});\n\n\n```\n\n#### Bootstrapping off an existing DHT node\nIn this scenario, we have an existing DHT and we just want to add a new node. In order to do that we need to \"bootstrap\" it off\nof another node using the `boostrap()` method. The `bootstrap()` method returns a promise object.\n\n```javascript\nvar DHT = require(__dirname + '/lib/dht');\n\n// Put the IP address and port for the DHT here\n// NOTE: This is the public IP for this node, not localhost or 127.0.0.1\nvar address = 'IP_ADDRESS';\nvar port = 3000;\n\n// Instantiate new DHT and start it\nvar dht = new DHT({\n    IP: address,\n    port: port\n});\ndht.start().then(function(res) {\n\tconsole.log('DHT started.');\n});\n\n// Bootstrap off existing DHT. Internally, this sends a FIND_NODE message to \n// the other DHT which then returns a list of closest peers from it's routing table\n// and also gets added to the routing tables of it's closest peers\n// NOTE: You have to know the IP address and port of an existing DHT\ndht.boostrap('OTHER_NODE_ADDRESS', 3000)\n    .then(function(res) {\n        console.log('Bootstrap complete with %d new routes.', res.number_of_routes);\n    })\n    .catch(function(err) {\n        console.log('ERROR: %s', err);\n    })\n    .done();\n\n```\n\n\n### Storing Data\nData in a DHT is stored according to an XOR Distance metric. Each Node ID is compared to the key and whichever\nNode is closest to the key stores the data. \n\nTo store data, pass a key/value pair to the `store()` method on the DHT. A promise is returned where you\ncan perform post processing and error handling for the RPC.\n\n```javascript\ndht.store(key, value)\n    .catch(function(err) {\n        console.log('Error in STORE RPC: %s', err);\n    })\n    .then(function(res) {\n        console.log('Store complete!\\nKey %s was stored at node ID: %s', res.rpc.get('key'), res.rpc.get('stored_at'));\n    });\n\n```\nAs long as there were no errors, the log above would print:\n\n> Store complete!\n> Key {SOME_KEY_FOR_VALUE} was stored at node ID: {NODE_ID}\n\n\n### Retrieving Data\nData in a DHT is retrieved the same way it is stored. To retrieve data, pass a key to the `findValue()` method\non the DHT. A deferred promise is returned. If the key is found, the promise is resolved and the success function is called. \nIf not the promise is rejected and the error function is called.\n\n```javascript\ndht.findValue(key)\n    .then(\n        function(res) {\n            // Success!\n            console.log('Find complete!\\nValue %s was retrieved at node ID: %s', res.rpc.get('value'), res.rpc.get('found_at'));\n        },\n        function(err) {\n            // No value found for that key\n            console.log('No values found.');\n        }\n    );\n```\nAs long as a value was found, the log below would look like this:\n\n> Find complete!\n> Value {SOME_VALUE} was retrieved at node ID: {NODE_ID}\n\n\n### Adding custom message handlers\nThe need may arise when you need to add custom functionality to the DHT such as a new message type. This R5N implementation has an API for adding\ncustom messages and handlers without having to modify the core DHT code. The custom message API employs a [decorator](http://en.wikipedia.org/wiki/Decorator_pattern)\npattern to accomplish this.\n\nThe DHT has a method called `addCustomMessageHandler()`. This method takes an object as a parameter with the following properties:  messageType, onMessage\n\n* The **messageType** property is a string for the message type (such as `'get_random_kvs'`). This is used throughout the lifecycle of an RPC to identify the message type.\n* The **onMessage** property is a callback function. This callback is called when the DHT receives an RPC with the above message type. This is where you handle the message and you can choose to forward it to another DHT or end it and send the response back to the initiating node.\n\nOnce you have configured your custom message type, you can initiate a request of that type with the `sendCustomRPC()` method on the DHT. This method takes 2 parameters:\n\n* The message type string (like `'get_random_kvs'`)\n* An RPC object\n\nThe `sendCustomRPC()` method returns a promise and you can process the response when it gets resolved (see the example below). Combining the custom message API with the flexible data container in the RPC makes this solution extremely flexible. \nWe have already implemented custom message types for Avatar using only this API. Custom message types for the DHT are modular and new additions are highly unlikely to break existing functionality. \n\nFor the sake of the example below, assume we have a DHT instance running. The DHT instance is associated with the variable named 'dht' (for obvious reasons). \nThis is how you would configure a DHT to handle custom message types.\n\n```javascript\n// This is our setup object\n// We need to initialize the 3 properties stated above\n var customMessageOptions = {\n\t// This is the unique message type string\n\t// It can be whatever you want it to be\n\t// NOTE: This is important because this is how we identify and handle RPC's of this type.\n\t// Consider keeping this in a global constant somewhere in your app\n\tmessageType: 'my_custom_message_type',\n\tonMessage: function(rpc) {\n\t\t\n\t\t// Here we can process a message for 'my_custom_message_type'\n\t\t// The onMessage and onResponse methods are called within the context\n\t\t// of the DHT so using the 'this' reference is actually pointing to the\n\t\t// DHT currently calling your callback. That makes it easy to use any of\n\t\t// the DHT functionality. For example, if we wanted to access the DHT's routing\n\t\t// table to get a list of all routes, we could do this:\n\t\tvar allRoutes = this.routingTable.getAllRoutes();\n\t\t\n\t\t// Do something with the routes here\n\t\t\n\t}\n};\n\n// Add the custom message to the DHT\ndht.addCustomMessageHandler(customMessageOptions);\n\n```\n\nThe DHT is now configured to handle message types of **my_custom_message_type**. But what if you want to initiate a request with that type? See below.\n\n```javascript\n\t// To send a custom message, use the sendCustomRPC method\n\t// NOTE: This will throw an exception if you haven't setup handlers for this message type\n\tvar rpc = new RPC();\n    rpc.address = 'SOME_IP_ADDRESS';\n    rpc.port = 9999;\n\t\n\t// Let's add some arbitrary data to the RPC specific to this message type\n\trpc.set('some_random_data', 123456);\n\t\n\t// Initiate the request\n    dht.sendCustomRPC('my_custom_message_type', rpc)\n    .then(function(result) {\n        // Here we process the response. In the custom message API, the onResponse\n        // method is only called on the initiating node. This mimicks the request/response\n        // feel of typical HTTP functionality. \n        console.log('RECEIVED CUSTOM RESPONSE: %j', result.rpc);\n    });\n```\n\n------\n","maintainers":[{"name":"staltz","email":"andre+npm@staltz.com"},{"name":"avatar_dave","email":"dave@avatar.ai"}],"time":{"modified":"2022-06-25T08:47:53.211Z","created":"2014-04-13T08:43:04.278Z","0.2.0":"2014-04-13T08:43:04.278Z","0.2.1":"2014-04-16T19:52:02.397Z","0.2.3":"2014-04-17T13:07:54.500Z","0.2.4":"2014-05-02T21:58:31.425Z","0.2.5":"2014-05-08T19:15:33.417Z","0.2.6":"2014-05-13T17:46:21.215Z","0.2.8":"2014-05-14T16:49:46.758Z","0.2.9":"2014-05-14T19:08:48.384Z","0.2.10":"2014-05-14T19:21:36.140Z","0.2.11":"2014-09-07T01:16:32.349Z"},"keywords":["dht","r5n","avatar"],"repository":{"type":"git","url":"https://code.avatar.ai/avatar/r5n-js.git"},"contributors":[{"name":"Dave Hagman","email":"dave@avatar.ai"},{"name":"Marko Polojarvi","email":"marko@avatar.ai"},{"name":"Andre Staltz","email":"andre@avatar.ai"}],"author":{"name":"Dave Hagman","email":"dave@avatar.ai"},"license":"MIT","readmeFilename":"README.md","users":{"staltz":true,"haggy":true,"jhbruhn":true}}