Skip to content
This repository was archived by the owner on Jul 21, 2023. It is now read-only.

chore: add basic usage example #69

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions examples/deaddrops/deaddrop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'

const waterfall = require('async').waterfall

const DHTNode = require('./dht').DHTNode

class DeadDrop {
constructor(userId, dht) {
this.userId = userId
this.userIdKey = Buffer.from(userId)
this.dht = dht
}

init(cb) {
this.dht.start(cb)
}

dial(target, cb) {
this.dht.dial(target, cb)
}

shutdown(cb) {
this.dht.stop(cb)
}

leaveMessageToUser(receiver, message, cb) {
const key = Buffer.from(receiver)
const value = Buffer.from(message)
this.dht.put(key, value, cb)
}

readMyMessages(cb) {
this.dht.get(this.userIdKey, cb)
}
}

function instantiateDeaddrop(userId, callback) {
let deaddrop
waterfall(
[
(cb) => DHTNode.createInstance(cb),
(dht, cb) => {
deaddrop = new DeadDrop(userId, dht)
deaddrop.init(cb)
}
],
(err) => {
if (err) callback(err, null);

console.log(`Deaddrop[${userId}] was successfuly initialized...`);
callback(null, deaddrop)
}
)
}

module.exports = {
instantiateDeaddrop
}
114 changes: 114 additions & 0 deletions examples/deaddrops/dht.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
'use strict'

const {
series
} = require('async')

const TCP = require('libp2p-tcp')
const Switch = require('libp2p-switch')
const Mplex = require('libp2p-mplex')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book')

const KadDHT = require('../../src');

function createPeerInfo(callback) {
// Creation of PeerId should be done only once, persisted and then read upon initialization.
PeerId.create({bits: 512}, (err, id) => {
if (err) callback(err, null)

callback(null, new PeerInfo(id))
})
}

function createTCPSwitch(peerInfo) {
// Required for the nodes to be able to communicate
// N.B. You cannot add solely a transport, a stream multiplexer is needed as well so that it
// allows for a TCP stream to be multiplexed over a connection (even though you have only one transport), IIUC.
const sw = new Switch(peerInfo, new PeerBook())
sw.transport.add('tcp', new TCP())
sw.connection.addStreamMuxer(Mplex)
sw.connection.reuse()
return sw
}

class DHTNode {
/**
* Initializes a DHT node.
* @param {Switch} sw A libp2p-switch implementation. More info https://github.com/libp2p/js-libp2p-switch
*/
constructor(sw) {
const options = { kBucketSize: 1 }
this._sw = sw
// Discovery is enabled by default since KadDHT implements also
// https://github.com/libp2p/interface-peer-discovery through its RandomWalk module.
this._dht = new KadDHT(sw, options)
}

/**
* Creates a new DHT Node.
* The node listens on localhost, using TCP, at any port, using the js-libp2p-switch implementation.
*/
static createInstance(callback) {
createPeerInfo((err, peerInfo) => {
if (err) callback(err, null)

// This allows the node (its switch actually) to act as a "listener" (server).
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')

const sw = createTCPSwitch(peerInfo)
const dht = new DHTNode(sw)
callback(null, dht)
})
}

start(callback) {
series(
[
(cb) => this._sw.start(cb),
(cb) => this._dht.start(cb),
],
(err) => {
if (err) callback(err, null)

console.log(`DHTNode[${this._dht.peerInfo.id.toB58String()}] initialized and listening on:`)
this._dht.peerInfo.multiaddrs.forEach(ma => console.log(`\tMultiAddress[${ma.toString()}]`))

callback()
}
)
}

stop(callback) {
series(
[
(cb) => this._dht.stop(cb),
(cb) => this._sw.stop(cb),
],
(err) => {
if (err) callback(err, null)

callback()
}
)
}

dial(target, cb) {
this._sw.dial(target, cb)
}

put(key, value, cb) {
this._dht.put(key, value, cb)
}

get(key, cb) {
this._dht.get(key, null, cb)
}

getPeerInfo() {
return this._dht.peerInfo
}
}

module.exports.DHTNode = DHTNode
92 changes: 92 additions & 0 deletions examples/deaddrops/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
'use strict'

const _ = require('lodash')
const {
each,
series,
parallel,
waterfall,
} = require('async')

const instantiateDeaddrop = require('./deaddrop').instantiateDeaddrop

// Dummy example:
// Create 3 deaddrops. One that's always on (for bootstrapping) and two others.
// Once the bootstrapping process completes, userA leaves a message in
// user's B deaddrop, who then later reads it.
const userAlwaysOnId = 'userAlwaysOn'
const userAId = 'userA'
const userBId = 'userB'
let deaddropAlwaysOn, deaddropA, deaddropB

// Utility method for instantiating the three deaddrops.
function instantiateAll(callback) {
parallel(
[
(cb) => instantiateDeaddrop(userAlwaysOnId, cb),
(cb) => instantiateDeaddrop(userAId, cb),
(cb) => instantiateDeaddrop(userBId, cb),
],
(err, deaddrops) => {
if (err) callback(err)

deaddropAlwaysOn = deaddrops[0]
deaddropA = deaddrops[1]
deaddropB = deaddrops[2]

console.log('Deaddrops were instantiated.\n')
callback()
}
)
}

// Adapted from https://github.com/libp2p/js-libp2p-kad-dht/blob/master/test/kad-dht.spec.js#L34-L39
function connectNoSync(a, b, callback) {
const target = _.cloneDeep(b.dht.getPeerInfo())
target.id._pubKey = target.id.pubKey
target.id._privKey = null
a.dht.dial(target, callback)
}

// Utility method for connecting the two deaddrops with the always-on one.
function bootstrap(callback) {
series(
[
(cb) => connectNoSync(deaddropA, deaddropAlwaysOn, cb),
(cb) => connectNoSync(deaddropB, deaddropAlwaysOn, cb),
],
(err) => {
if (err) callback(err)

console.log('Deaddrops connected to the always-on one.')
callback()
}
)
}

waterfall(
[
(cb) => instantiateAll(cb),
(cb) => bootstrap(cb),
(cb) => deaddropA.leaveMessageToUser(userBId, `Greetings from ${userAId}`, cb),
(cb) => deaddropB.readMyMessages(cb),
(message, cb) => {
console.log(`${userBId}: received message[${message}]`)
cb()
},
(cb) => {
each(
[deaddropAlwaysOn, deaddropA, deaddropB],
(deaddrop, callback) => {
deaddrop.shutdown(callback)
},
(err) => {
if (err) cb(err)

console.log('\nAll deaddrops were shutdown.')
cb()
}
)
}
]
)