2018-02-14 11:30:36 +01:00
|
|
|
'use strict'
|
|
|
|
|
2019-02-26 14:15:30 +00:00
|
|
|
const nextTick = require('async/nextTick')
|
|
|
|
const { messages, codes } = require('./errors')
|
2019-07-29 14:40:40 +01:00
|
|
|
const promisify = require('promisify-es6')
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-02-26 14:15:30 +00:00
|
|
|
const errCode = require('err-code')
|
|
|
|
|
2019-08-19 17:06:08 +02:00
|
|
|
module.exports = (node, Pubsub, config) => {
|
|
|
|
const pubsub = new Pubsub(node, config)
|
2018-02-14 11:30:36 +01:00
|
|
|
|
|
|
|
return {
|
2019-07-30 12:36:23 +02:00
|
|
|
/**
|
|
|
|
* Subscribe the given handler to a pubsub topic
|
|
|
|
*
|
|
|
|
* @param {string} topic
|
|
|
|
* @param {function} handler The handler to subscribe
|
|
|
|
* @param {object|null} [options]
|
|
|
|
* @param {function} [callback] An optional callback
|
|
|
|
*
|
|
|
|
* @returns {Promise|void} A promise is returned if no callback is provided
|
|
|
|
*
|
|
|
|
* @example <caption>Subscribe a handler to a topic</caption>
|
|
|
|
*
|
|
|
|
* // `null` must be passed for options until subscribe is no longer using promisify
|
|
|
|
* const handler = (message) => { }
|
|
|
|
* await libp2p.subscribe(topic, handler, null)
|
|
|
|
*
|
|
|
|
* @example <caption>Use a callback instead of the Promise api</caption>
|
|
|
|
*
|
|
|
|
* // `options` may be passed or omitted when supplying a callback
|
|
|
|
* const handler = (message) => { }
|
|
|
|
* libp2p.subscribe(topic, handler, callback)
|
|
|
|
*/
|
2019-09-24 13:02:07 +01:00
|
|
|
subscribe: (topic, handler, options, callback) => {
|
|
|
|
// can't use promisify because it thinks the handler is a callback
|
2018-02-14 11:30:36 +01:00
|
|
|
if (typeof options === 'function') {
|
2019-07-30 12:36:23 +02:00
|
|
|
callback = options
|
2018-02-14 11:30:36 +01:00
|
|
|
options = {}
|
|
|
|
}
|
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
if (!node.isStarted() && !pubsub.started) {
|
2019-09-24 13:02:07 +01:00
|
|
|
const err = errCode(new Error(messages.NOT_STARTED_YET), codes.PUBSUB_NOT_STARTED)
|
2018-02-15 20:14:54 +01:00
|
|
|
|
2019-09-24 13:02:07 +01:00
|
|
|
if (callback) {
|
|
|
|
return nextTick(() => callback(err))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
2019-09-24 13:02:07 +01:00
|
|
|
return Promise.reject(err)
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
2019-09-24 13:02:07 +01:00
|
|
|
if (pubsub.listenerCount(topic) === 0) {
|
|
|
|
pubsub.subscribe(topic)
|
|
|
|
}
|
|
|
|
|
|
|
|
pubsub.on(topic, handler)
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
return nextTick(() => callback())
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.resolve()
|
|
|
|
},
|
2019-07-29 14:40:40 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Unsubscribes from a pubsub topic
|
|
|
|
*
|
|
|
|
* @param {string} topic
|
|
|
|
* @param {function|null} handler The handler to unsubscribe from
|
|
|
|
* @param {function} [callback] An optional callback
|
|
|
|
*
|
|
|
|
* @returns {Promise|void} A promise is returned if no callback is provided
|
|
|
|
*
|
|
|
|
* @example <caption>Unsubscribe a topic for all handlers</caption>
|
|
|
|
*
|
|
|
|
* // `null` must be passed until unsubscribe is no longer using promisify
|
|
|
|
* await libp2p.unsubscribe(topic, null)
|
|
|
|
*
|
|
|
|
* @example <caption>Unsubscribe a topic for 1 handler</caption>
|
|
|
|
*
|
|
|
|
* await libp2p.unsubscribe(topic, handler)
|
|
|
|
*
|
|
|
|
* @example <caption>Use a callback instead of the Promise api</caption>
|
|
|
|
*
|
|
|
|
* libp2p.unsubscribe(topic, handler, callback)
|
|
|
|
*/
|
2019-09-24 13:02:07 +01:00
|
|
|
unsubscribe: (topic, handler, callback) => {
|
|
|
|
// can't use promisify because it thinks the handler is a callback
|
2019-07-31 09:38:14 +02:00
|
|
|
if (!node.isStarted() && !pubsub.started) {
|
2019-09-24 13:02:07 +01:00
|
|
|
const err = errCode(new Error(messages.NOT_STARTED_YET), codes.PUBSUB_NOT_STARTED)
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
return nextTick(() => callback(err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.reject(err)
|
2018-02-15 19:39:06 +01:00
|
|
|
}
|
2019-07-29 14:40:40 +01:00
|
|
|
|
|
|
|
if (!handler) {
|
2019-07-31 09:38:14 +02:00
|
|
|
pubsub.removeAllListeners(topic)
|
2019-02-21 15:46:31 +02:00
|
|
|
} else {
|
2019-07-31 09:38:14 +02:00
|
|
|
pubsub.removeListener(topic, handler)
|
2019-02-21 15:46:31 +02:00
|
|
|
}
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
if (pubsub.listenerCount(topic) === 0) {
|
|
|
|
pubsub.unsubscribe(topic)
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
2018-12-20 11:48:07 -05:00
|
|
|
|
2019-09-24 13:02:07 +01:00
|
|
|
if (callback) {
|
2019-07-29 14:40:40 +01:00
|
|
|
return nextTick(() => callback())
|
2018-12-20 11:48:07 -05:00
|
|
|
}
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-07-29 14:40:40 +01:00
|
|
|
return Promise.resolve()
|
2019-09-24 13:02:07 +01:00
|
|
|
},
|
2019-07-29 14:40:40 +01:00
|
|
|
|
|
|
|
publish: promisify((topic, data, callback) => {
|
2019-07-31 09:38:14 +02:00
|
|
|
if (!node.isStarted() && !pubsub.started) {
|
2019-02-26 14:15:30 +00:00
|
|
|
return nextTick(callback, errCode(new Error(messages.NOT_STARTED_YET), codes.PUBSUB_NOT_STARTED))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
try {
|
|
|
|
data = Buffer.from(data)
|
|
|
|
} catch (err) {
|
|
|
|
return nextTick(callback, errCode(new Error('data must be convertible to a Buffer'), 'ERR_DATA_IS_NOT_VALID'))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
pubsub.publish(topic, data, callback)
|
2019-07-29 14:40:40 +01:00
|
|
|
}),
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-07-29 14:40:40 +01:00
|
|
|
ls: promisify((callback) => {
|
2019-07-31 09:38:14 +02:00
|
|
|
if (!node.isStarted() && !pubsub.started) {
|
2019-02-26 14:15:30 +00:00
|
|
|
return nextTick(callback, errCode(new Error(messages.NOT_STARTED_YET), codes.PUBSUB_NOT_STARTED))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
const subscriptions = Array.from(pubsub.subscriptions)
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-02-26 14:15:30 +00:00
|
|
|
nextTick(() => callback(null, subscriptions))
|
2019-07-29 14:40:40 +01:00
|
|
|
}),
|
2018-02-14 11:30:36 +01:00
|
|
|
|
2019-07-29 14:40:40 +01:00
|
|
|
peers: promisify((topic, callback) => {
|
2019-07-31 09:38:14 +02:00
|
|
|
if (!node.isStarted() && !pubsub.started) {
|
2019-02-26 14:15:30 +00:00
|
|
|
return nextTick(callback, errCode(new Error(messages.NOT_STARTED_YET), codes.PUBSUB_NOT_STARTED))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof topic === 'function') {
|
|
|
|
callback = topic
|
|
|
|
topic = null
|
|
|
|
}
|
|
|
|
|
2019-07-31 09:38:14 +02:00
|
|
|
const peers = Array.from(pubsub.peers.values())
|
2018-02-14 11:30:36 +01:00
|
|
|
.filter((peer) => topic ? peer.topics.has(topic) : true)
|
|
|
|
.map((peer) => peer.info.id.toB58String())
|
|
|
|
|
2019-02-26 14:15:30 +00:00
|
|
|
nextTick(() => callback(null, peers))
|
2019-07-29 14:40:40 +01:00
|
|
|
}),
|
2018-02-14 11:30:36 +01:00
|
|
|
|
|
|
|
setMaxListeners (n) {
|
2019-07-31 09:38:14 +02:00
|
|
|
return pubsub.setMaxListeners(n)
|
|
|
|
},
|
|
|
|
|
2019-07-31 14:33:00 +02:00
|
|
|
start: promisify((cb) => pubsub.start(cb)),
|
2019-07-31 09:38:14 +02:00
|
|
|
|
2019-07-31 14:33:00 +02:00
|
|
|
stop: promisify((cb) => pubsub.stop(cb))
|
2018-02-14 11:30:36 +01:00
|
|
|
}
|
|
|
|
}
|