Last active
October 8, 2018 18:51
-
-
Save thEpisode/31adfd8d14576c0c3ac898a3bfd8fd30 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
'use strict'; | |
// Import dependencies | |
const crypto = require('crypto'); | |
const bunyan = require('bunyan'); | |
const levelup = require('levelup'); | |
const encoding = require('encoding-down'); | |
const leveldown = require('leveldown'); | |
const kadence = require('@kadenceproject/kadence'); | |
// Prepare required options | |
const storage = levelup(encoding(leveldown(`${__dirname}/db`))); | |
const logger = bunyan.createLogger({ name: 'kadence example' }); | |
const transport = new kadence.HTTPTransport(); | |
const identity = kadence.utils.getRandomKeyBuffer(); | |
const contact = { hostname: 'localhost', port: 8080 }; | |
// Construct a kademlia node interface; the returned `Node` object exposes: | |
// - router | |
// - rpc | |
// - storage | |
// - identity | |
const node = new kadence.KademliaNode({ | |
transport, | |
storage, | |
logger, | |
identity, | |
contact | |
}); | |
// Use rule "extensions" from plugins to add additional functionality. | |
// Plugins can also extend the `KademliaNode` object with additional methods | |
node.plugin(kadence.quasar()); | |
// Use "global" rules for preprocessing *all* incoming messages | |
// This is useful for things like blacklisting certain nodes | |
node.use((request, response, next) => { | |
let [identityString] = request.contact | |
if ([/* identity blacklist */].includes(identityString)) { | |
return next(new Error('You have been blacklisted')); | |
} | |
next(); | |
}); | |
// Use existing "base" rules to add additional logic to the base kad routes | |
// This is useful for things like validating key/value pairs | |
node.use('STORE', (request, response, next) => { | |
let [key, val] = request.params; | |
let hash = crypto.createHash('rmd160').update(val).digest('hex'); | |
// Ensure values are content-addressable | |
if (key !== hash) { | |
return next(new Error('Key must be the RMD-160 hash of value')); | |
} | |
next(); | |
}); | |
// Use "userland" (that's you!) rules to create your own protocols | |
node.use('ECHO', (request, response, next) => { | |
if ([/* some naughty words */].includes(request.params.message)) { | |
return next(new Error( | |
`Oh goodness, I dare not say "${request.params.message}"` | |
)); | |
} | |
response.send(request.params); | |
}); | |
// Define a global custom error handler rule, simply by including the `err` | |
// argument in the handler | |
node.use((err, request, response, next) => { | |
response.send({ error: err.message }); | |
}); | |
// Define error handlers for specific rules the same way, but including the | |
// rule name as the first argument | |
node.use('ECHO', (err, request, response, next) => { | |
response.send({ | |
error: err.message.replace(request.params.message, '[redacted]') | |
}); | |
}); | |
// Extend the Node interface with your own plugins | |
// In many cases, you probably want parity with any userland message routes | |
// you have defined - in this case for the ECHO method | |
node.plugin(function(node) { | |
node.sendNeighborEcho = (text, callback) => { | |
const neighbor = [ | |
...node.router.getClosestContactsToKey(node.identity).entries(), | |
].shift(); | |
node.send('ECHO', { | |
message: text | |
}, neighbor, callback); | |
}; | |
}); | |
// When you are ready, start listening for messages and join the network | |
// The Node#listen method takes different arguments based on the transport | |
// adapter being used | |
node.listen(contact.port) | |
console.log(`Listening on ${contact.port}`) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment