helia-coord 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.on-save.json +8 -0
- package/PEDIGREE.md +3 -0
- package/README.md +3 -0
- package/config/bootstrap-circuit-relays.js +48 -0
- package/examples/start-external.js +56 -0
- package/index.js +129 -0
- package/lib/adapters/bch-adapter.js +94 -0
- package/lib/adapters/encryption-adapter.js +123 -0
- package/lib/adapters/gist.js +42 -0
- package/lib/adapters/index.js +66 -0
- package/lib/adapters/ipfs-adapter.js +263 -0
- package/lib/adapters/logs-adapter.js +44 -0
- package/lib/adapters/pubsub-adapter/README.md +86 -0
- package/lib/adapters/pubsub-adapter/about-adapter.js +117 -0
- package/lib/adapters/pubsub-adapter/index.js +275 -0
- package/lib/adapters/pubsub-adapter/messaging.js +389 -0
- package/lib/adapters/pubsub-adapter/msg-router.js +58 -0
- package/lib/adapters/pubsub-adapter/resend-msg.js +58 -0
- package/lib/controllers/index.js +24 -0
- package/lib/controllers/timer-controller.js +417 -0
- package/lib/entities/this-node-entity.js +102 -0
- package/lib/use-cases/index.js +36 -0
- package/lib/use-cases/peer-use-cases.js +146 -0
- package/lib/use-cases/pubsub-use-cases.js +56 -0
- package/lib/use-cases/relay-use-cases.js +479 -0
- package/lib/use-cases/schema.js +158 -0
- package/lib/use-cases/this-node-use-cases.js +443 -0
- package/lib/util/utils.js +12 -0
- package/package.json +52 -0
- package/test/mocks/adapter-mock.js +119 -0
- package/test/mocks/circuit-relay-mocks.js +67 -0
- package/test/mocks/ipfs-mock.js +46 -0
- package/test/mocks/peers-mock.js +75 -0
- package/test/mocks/pubsub-mocks.js +37 -0
- package/test/mocks/thisnode-mocks.js +82 -0
- package/test/mocks/use-case-mocks.js +24 -0
- package/test/unit/adapters/bch-adapter-unit.js +96 -0
- package/test/unit/adapters/encryption-adapter-unit.js +129 -0
- package/test/unit/adapters/gist.unit.adapters.js +58 -0
- package/test/unit/adapters/index-adapters-unit.js +79 -0
- package/test/unit/adapters/ipfs-adapter-unit.js +215 -0
- package/test/unit/adapters/logs-adapter-unit.js +55 -0
- package/test/unit/adapters/pubsub/about-adapter-unit.js +129 -0
- package/test/unit/adapters/pubsub/messaging-adapter-unit.js +576 -0
- package/test/unit/adapters/pubsub/pubsub-adapter-unit.js +367 -0
- package/test/unit/adapters/pubsub/resend-msg-adapter-unit.js +58 -0
- package/test/unit/controllers/controllers-index-unit.js +30 -0
- package/test/unit/controllers/timer-controller-unit.js +261 -0
- package/test/unit/entities/this-node.unit.entity.js +157 -0
- package/test/unit/index-unit.js +160 -0
- package/test/unit/use-cases/peer.unit.use-cases.js +186 -0
- package/test/unit/use-cases/pubsub.unit.use-cases.js +114 -0
- package/test/unit/use-cases/relay-use-cases-unit.js +658 -0
- package/test/unit/use-cases/schema-use-case-unit.js +101 -0
- package/test/unit/use-cases/this-node-use-cases-unit.js +427 -0
- package/test/unit/use-cases/use-cases-index-unit.js +47 -0
- package/test/unit/util/utils-unit.js +31 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This library routes incoming pubsub messages to the appropriate handler.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// This class routes 'normal' messages, which are broadcast message.
|
|
6
|
+
class BroadcastRouter {
|
|
7
|
+
constructor (localConfig = {}) {
|
|
8
|
+
this.handler = localConfig.handler
|
|
9
|
+
this.thisNode = localConfig.thisNode
|
|
10
|
+
this.parsePubsubMessage = localConfig.parsePubsubMessage
|
|
11
|
+
|
|
12
|
+
this.route = this.route.bind(this)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async route (msg) {
|
|
16
|
+
try {
|
|
17
|
+
await this.parsePubsubMessage(msg, this.handler, this.thisNode)
|
|
18
|
+
|
|
19
|
+
return true
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error('Error trying to route broadcast pubsub message: ', err)
|
|
22
|
+
// Do not throw an error. This is a top-level handler.
|
|
23
|
+
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// This class routes 'private' messages sent on this nodes private, encrypted
|
|
30
|
+
// pubsub channel, which is used for direct communication.
|
|
31
|
+
class PrivateChannelRouter {
|
|
32
|
+
constructor (localConfig = {}) {
|
|
33
|
+
this.messaging = localConfig.messaging
|
|
34
|
+
this.thisNode = localConfig.thisNode
|
|
35
|
+
this.handleNewMessage = localConfig.handleNewMessage
|
|
36
|
+
|
|
37
|
+
this.route = this.route.bind(this)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async route (msg) {
|
|
41
|
+
try {
|
|
42
|
+
const msgObj = await this.messaging.handleIncomingData(msg, this.thisNode)
|
|
43
|
+
|
|
44
|
+
// If msgObj is false, then ignore it. Typically indicates an already
|
|
45
|
+
// processed message.
|
|
46
|
+
if (msgObj) { await this.handleNewMessage(msgObj, this.thisNode) }
|
|
47
|
+
|
|
48
|
+
return true
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error('Error trying to route private pubsub message: ', err)
|
|
51
|
+
// Do not throw an error. This is a top-level handler.
|
|
52
|
+
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { BroadcastRouter, PrivateChannelRouter }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This class library is used by the messaging.js library to periodically
|
|
3
|
+
resend messages until they are acknowledged.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const RETRY_LIMIT = 3
|
|
7
|
+
|
|
8
|
+
class ResendMsg {
|
|
9
|
+
constructor (localConfig = {}) {
|
|
10
|
+
this.msgObj = localConfig.msgObj
|
|
11
|
+
this.msgLib = localConfig.msgLib
|
|
12
|
+
|
|
13
|
+
// Bind the 'this' object to all subfunctions
|
|
14
|
+
this.resend = this.resend.bind(this)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Called by an Interval Timer. This function re-publishes a message to a
|
|
18
|
+
// pubsub channel.
|
|
19
|
+
async resend () {
|
|
20
|
+
try {
|
|
21
|
+
// console.log(`resendMsg() msgObj: ${JSON.stringify(msgObj, null, 2)}`)
|
|
22
|
+
|
|
23
|
+
if (!this.msgObj) {
|
|
24
|
+
console.log('ipfs-coord-esm/lib/adapters/pubsub-adapter/resend-msg.js/resend() given empty message object. Can not resend message. Skipping.')
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { retryCnt, intervalHandle, receiver } = this.msgObj
|
|
29
|
+
|
|
30
|
+
// Throw an error if the retry count is not an integer.
|
|
31
|
+
const testRetryCnt = parseInt(retryCnt)
|
|
32
|
+
if (isNaN(testRetryCnt)) throw new Error('retryCnt must be an integer')
|
|
33
|
+
|
|
34
|
+
if (retryCnt < RETRY_LIMIT) {
|
|
35
|
+
// Increment the retry
|
|
36
|
+
this.msgObj.retryCnt++
|
|
37
|
+
|
|
38
|
+
// Send message
|
|
39
|
+
await this.msgLib.publishToPubsubChannel(receiver, this.msgObj)
|
|
40
|
+
|
|
41
|
+
return 1
|
|
42
|
+
} else {
|
|
43
|
+
// Retry count exceeded.
|
|
44
|
+
|
|
45
|
+
// Disable the interval handler
|
|
46
|
+
clearInterval(intervalHandle)
|
|
47
|
+
|
|
48
|
+
return 2
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error('Error in resendMsg(): ', err)
|
|
52
|
+
// Do not throw an error. This is a top-level function called by an Interval.
|
|
53
|
+
return 0
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default ResendMsg
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This is a top-level Controllers library. This library loads all other
|
|
3
|
+
controller libraries.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// const TimerControllers = require('./timer-controller')
|
|
7
|
+
import TimerControllers from './timer-controller.js'
|
|
8
|
+
|
|
9
|
+
class Controllers {
|
|
10
|
+
constructor (localConfig = {}) {
|
|
11
|
+
// Dependency Injection
|
|
12
|
+
this.adapters = localConfig.adapters
|
|
13
|
+
if (!this.adapters) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
'Instance of adapters required when instantiating Controllers'
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Encapsulate dependencies
|
|
20
|
+
this.timer = new TimerControllers(localConfig)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default Controllers
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This Controller library is concerned with timer-based functions that are
|
|
3
|
+
kicked off periodicially. These functions maintain connections and state
|
|
4
|
+
of the IPFS node.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Local libraries
|
|
8
|
+
import Util from '../util/utils.js'
|
|
9
|
+
|
|
10
|
+
const DEFAULT_COORDINATION_ROOM = 'psf-ipfs-coordination-002'
|
|
11
|
+
|
|
12
|
+
class TimerControllers {
|
|
13
|
+
constructor (localConfig = {}) {
|
|
14
|
+
// Dependency Injection
|
|
15
|
+
this.adapters = localConfig.adapters
|
|
16
|
+
if (!this.adapters) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'Instance of adapters required when instantiating Timer Controllers'
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
this.statusLog = localConfig.statusLog
|
|
22
|
+
if (!this.statusLog) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'Handler for status logs required when instantiating Timer Controllers'
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Encapsulate dependencies
|
|
29
|
+
this.util = new Util()
|
|
30
|
+
this.sleep = this.util.sleep
|
|
31
|
+
|
|
32
|
+
// state
|
|
33
|
+
this.debugLevel = localConfig.debugLevel
|
|
34
|
+
this.config = localConfig
|
|
35
|
+
this.circuitRelayTimerInterval = 60000
|
|
36
|
+
this.announceTimerInterval = 31000
|
|
37
|
+
this.peerTimerInterval = 2 * 50000
|
|
38
|
+
this.relaySearchInterval = 3 * 60000
|
|
39
|
+
this.checkBlacklistInterval = 30000
|
|
40
|
+
this.listPubsubChannelsInterval = 32000
|
|
41
|
+
|
|
42
|
+
// Bind 'this' object to all subfunctions
|
|
43
|
+
this.startTimers = this.startTimers.bind(this)
|
|
44
|
+
this.stopAllTimers = this.stopAllTimers.bind(this)
|
|
45
|
+
// this.monitorBandwidth = this.monitorBandwidth.bind(this)
|
|
46
|
+
this.manageCircuitRelays = this.manageCircuitRelays.bind(this)
|
|
47
|
+
this.manageAnnouncement = this.manageAnnouncement.bind(this)
|
|
48
|
+
this.managePeers = this.managePeers.bind(this)
|
|
49
|
+
this.blacklist = this.blacklist.bind(this)
|
|
50
|
+
this.searchForRelays = this.searchForRelays.bind(this)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
startTimers (thisNode, useCases) {
|
|
54
|
+
const _this = this
|
|
55
|
+
|
|
56
|
+
// Periodically maintain the connection to Circuit Relays.
|
|
57
|
+
this.circuitRelayTimerHandle = setInterval(async function () {
|
|
58
|
+
await _this.manageCircuitRelays(thisNode, useCases)
|
|
59
|
+
}, this.circuitRelayTimerInterval) // One Minute
|
|
60
|
+
|
|
61
|
+
// Periodically announce this nodes existance to the network.
|
|
62
|
+
this.announceTimerHandle = setInterval(async function () {
|
|
63
|
+
await _this.manageAnnouncement(thisNode, useCases)
|
|
64
|
+
}, this.announceTimerInterval)
|
|
65
|
+
|
|
66
|
+
// Periodically maintain the connection to other coordination peers.
|
|
67
|
+
this.peerTimerHandle = setInterval(async function () {
|
|
68
|
+
await _this.managePeers(thisNode, useCases)
|
|
69
|
+
}, this.peerTimerInterval)
|
|
70
|
+
|
|
71
|
+
// Periodically try to connect to problematic peers that advertise as
|
|
72
|
+
// potential circuit relays.
|
|
73
|
+
this.relaySearchHandle = setInterval(async function () {
|
|
74
|
+
await _this.searchForRelays(thisNode, useCases)
|
|
75
|
+
}, this.relaySearchInterval)
|
|
76
|
+
|
|
77
|
+
// Periodically ensure we are disconnected from blacklisted peers.
|
|
78
|
+
this.checkBlacklistHandle = setInterval(async function () {
|
|
79
|
+
await _this.blacklist(thisNode, useCases)
|
|
80
|
+
}, this.checkBlacklistInterval)
|
|
81
|
+
|
|
82
|
+
this.listPubsubChannelsHandle = setInterval(async function () {
|
|
83
|
+
await _this.listPubsubChannels()
|
|
84
|
+
}, this.listPubsubChannelsInterval)
|
|
85
|
+
|
|
86
|
+
// Return handles to the different timers.
|
|
87
|
+
return {
|
|
88
|
+
circuitRelayTimerHandle: this.circuitRelayTimerHandle,
|
|
89
|
+
announceTimerHandle: this.announceTimerHandle,
|
|
90
|
+
peerTimerHandle: this.peerTimerHandle,
|
|
91
|
+
relaySearchHandle: this.relaySearchHandle,
|
|
92
|
+
checkBlacklistHandle: this.checkBlacklistHandle,
|
|
93
|
+
listPubsubChannelsHandle: this.listPubsubChannelsHandle
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Used mostly for testing. Ensures all timers are stopped.
|
|
98
|
+
async stopAllTimers () {
|
|
99
|
+
clearInterval(this.circuitRelayTimerHandle)
|
|
100
|
+
clearInterval(this.announceTimerHandle)
|
|
101
|
+
clearInterval(this.peerTimerHandle)
|
|
102
|
+
clearInterval(this.relaySearchHandle)
|
|
103
|
+
clearInterval(this.checkBlacklistHandle)
|
|
104
|
+
clearInterval(this.listPubsubChannelsHandle)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async listPubsubChannels () {
|
|
108
|
+
const ipfs = this.adapters.ipfs.ipfs
|
|
109
|
+
|
|
110
|
+
// const pubsubChans = await ipfs.pubsub.ls()
|
|
111
|
+
const pubsubChans = ipfs.libp2p.services.pubsub.subscriptions
|
|
112
|
+
console.log(`subscribed pubsub channels: ${JSON.stringify(pubsubChans, null, 2)}`)
|
|
113
|
+
this.adapters.log.statusLog(2, `subscribed pubsub channels: ${JSON.stringify(pubsubChans, null, 2)}`)
|
|
114
|
+
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Dev Note: This is not curently used, but code is left because it may be
|
|
119
|
+
// enabled in the future.
|
|
120
|
+
// Monitor the bandwidth being consumed by IPFS peers.
|
|
121
|
+
// async monitorBandwidth (thisNode, useCases) {
|
|
122
|
+
// try {
|
|
123
|
+
// const ipfs = this.adapters.ipfs.ipfs
|
|
124
|
+
|
|
125
|
+
// // const bw = await ipfs.stats.bw()
|
|
126
|
+
// // console.log('bw: ', bw)
|
|
127
|
+
// for await (const stats of ipfs.stats.bw()) {
|
|
128
|
+
// // console.log(stats)
|
|
129
|
+
// this.adapters.log.statusLog(2, 'Bandwidth stats: ', stats)
|
|
130
|
+
// // this.adapters.log.statusLog(2, `${JSON.stringify(stats, null, 2)}`)
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
// const bitswap = await ipfs.stats.bitswap()
|
|
134
|
+
// this.adapters.log.statusLog(2, 'bitswap stats: ', bitswap)
|
|
135
|
+
// // this.adapters.log.statusLog(2, `${JSON.stringify(bitswap, null, 2)}`)
|
|
136
|
+
|
|
137
|
+
// return true
|
|
138
|
+
|
|
139
|
+
// } catch (err) {
|
|
140
|
+
// console.error('Error in timer-controller.js/monitorBandwidth(): ', err)
|
|
141
|
+
// // this.adapters.log.statusLog(
|
|
142
|
+
// // 2,
|
|
143
|
+
// // 'Error in timer-controller.jsmonitorBandwidth(): ',
|
|
144
|
+
// // err
|
|
145
|
+
// // )
|
|
146
|
+
|
|
147
|
+
// // Note: Do not throw an error. This is a top-level function.
|
|
148
|
+
// return false
|
|
149
|
+
// }
|
|
150
|
+
// }
|
|
151
|
+
|
|
152
|
+
// This function is intended to be called periodically by setInterval().
|
|
153
|
+
// This function finds circuit relays on the network that can be used
|
|
154
|
+
// to relay data to other nodes behind firewalls.
|
|
155
|
+
async manageCircuitRelays (thisNode, useCases) {
|
|
156
|
+
try {
|
|
157
|
+
this.adapters.log.statusLog(3, 'Entering manageCircuitRelays() Controller.')
|
|
158
|
+
|
|
159
|
+
// Disable the timer while processing is happening.
|
|
160
|
+
clearInterval(this.circuitRelayTimerHandle)
|
|
161
|
+
|
|
162
|
+
// Remove any duplicate entries
|
|
163
|
+
useCases.relays.removeDuplicates(thisNode)
|
|
164
|
+
|
|
165
|
+
// Maintain connections to Relays.
|
|
166
|
+
await useCases.relays.connectToCRs(thisNode)
|
|
167
|
+
|
|
168
|
+
// Update metrics on Relays.
|
|
169
|
+
await useCases.relays.measureRelays(thisNode)
|
|
170
|
+
|
|
171
|
+
const now = new Date()
|
|
172
|
+
this.adapters.log.statusLog(1,
|
|
173
|
+
`Renewed connections to all circuit relays at ${now.toLocaleString()}`
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
// Re-enable the timer interval.
|
|
177
|
+
const _this = this
|
|
178
|
+
this.circuitRelayTimerHandle = setInterval(async function () {
|
|
179
|
+
await _this.manageCircuitRelays(thisNode, useCases)
|
|
180
|
+
}, this.circuitRelayTimerInterval)
|
|
181
|
+
|
|
182
|
+
// console.log('Exiting manageCircuitRelays() Controller.')
|
|
183
|
+
|
|
184
|
+
return true
|
|
185
|
+
} catch (err) {
|
|
186
|
+
console.error(
|
|
187
|
+
'Error in timer-controller.js/manageCircuitRelays(): ',
|
|
188
|
+
err
|
|
189
|
+
)
|
|
190
|
+
// this.adapters.log.statusLog(
|
|
191
|
+
// 2,
|
|
192
|
+
// 'Error in timer-controller.js/manageCircuitRelays(): ',
|
|
193
|
+
// err
|
|
194
|
+
// )
|
|
195
|
+
|
|
196
|
+
// Re-enable the timer interval.
|
|
197
|
+
const _this = this
|
|
198
|
+
this.circuitRelayTimerHandle = setInterval(async function () {
|
|
199
|
+
await _this.manageCircuitRelays(thisNode, useCases)
|
|
200
|
+
}, this.circuitRelayTimerInterval)
|
|
201
|
+
|
|
202
|
+
// Note: Do not throw an error. This is a top-level function.
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// This function is intended to be called periodically by setInterval().
|
|
208
|
+
// Announce the existance of this node to the network.
|
|
209
|
+
async manageAnnouncement (thisNode, useCases) {
|
|
210
|
+
try {
|
|
211
|
+
// console.log('thisNode: ', thisNode)
|
|
212
|
+
|
|
213
|
+
// Disable the timer interval while this function executes.
|
|
214
|
+
clearInterval(this.announceTimerHandle)
|
|
215
|
+
|
|
216
|
+
// Get the information needed for the announcement.
|
|
217
|
+
const announceObj = {
|
|
218
|
+
ipfsId: thisNode.ipfsId,
|
|
219
|
+
ipfsMultiaddrs: thisNode.ipfsMultiaddrs,
|
|
220
|
+
type: thisNode.type,
|
|
221
|
+
// orbitdbId: thisNode.orbit.id,
|
|
222
|
+
|
|
223
|
+
// TODO: Allow node.js apps to pass a config setting to override this.
|
|
224
|
+
isCircuitRelay: false
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Generate the announcement message.
|
|
228
|
+
const announceMsgObj = thisNode.schema.announcement(announceObj)
|
|
229
|
+
// console.log(`announceMsgObj: ${JSON.stringify(announceMsgObj, null, 2)}`)
|
|
230
|
+
|
|
231
|
+
const announceMsgStr = JSON.stringify(announceMsgObj)
|
|
232
|
+
|
|
233
|
+
// Publish the announcement to the pubsub channel.
|
|
234
|
+
await this.adapters.pubsub.messaging.publishToPubsubChannel(
|
|
235
|
+
DEFAULT_COORDINATION_ROOM,
|
|
236
|
+
announceMsgStr
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
const now = new Date()
|
|
240
|
+
this.adapters.log.statusLog(
|
|
241
|
+
1,
|
|
242
|
+
`status: Announced self on ${DEFAULT_COORDINATION_ROOM} pubsub channel at ${now.toLocaleString()}`
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
// Re-enable the timer interval
|
|
246
|
+
const _this = this
|
|
247
|
+
this.announceTimerHandle = setInterval(async function () {
|
|
248
|
+
await _this.manageAnnouncement(thisNode, useCases)
|
|
249
|
+
}, this.announceTimerInterval)
|
|
250
|
+
|
|
251
|
+
return true
|
|
252
|
+
} catch (err) {
|
|
253
|
+
console.error('Error in timer-controller.js/manageAnnouncement(): ', err)
|
|
254
|
+
// this.adapters.log.statusLog(
|
|
255
|
+
// 2,
|
|
256
|
+
// 'Error in timer-controller.js/manageAnnouncement(): ',
|
|
257
|
+
// err
|
|
258
|
+
// )
|
|
259
|
+
|
|
260
|
+
// Re-enable the timer interval
|
|
261
|
+
const _this = this
|
|
262
|
+
this.announceTimerHandle = setInterval(async function () {
|
|
263
|
+
await _this.manageAnnouncement(thisNode, useCases)
|
|
264
|
+
}, this.announceTimerInterval)
|
|
265
|
+
|
|
266
|
+
// Note: Do not throw an error. This is a top-level function.
|
|
267
|
+
return false
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// This function is intended to be called periodically by setInterval().
|
|
272
|
+
// It refreshes the connection to all subnet peers thisNode is trying to track.
|
|
273
|
+
async managePeers (thisNode, useCases) {
|
|
274
|
+
let success = false
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
// Disable the timer while processing is happening.
|
|
278
|
+
clearInterval(this.peerTimerHandle)
|
|
279
|
+
|
|
280
|
+
// this.statusLog('managePeers')
|
|
281
|
+
await useCases.thisNode.refreshPeerConnections()
|
|
282
|
+
|
|
283
|
+
// console.error('Error in timer-controller.js/manageAnnouncement(): ', err)
|
|
284
|
+
this.adapters.log.statusLog(
|
|
285
|
+
1,
|
|
286
|
+
'Renewed connections to all subnet peers.'
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
// Reinstate the timer interval
|
|
290
|
+
const _this = this
|
|
291
|
+
this.peerTimerHandle = setInterval(async function () {
|
|
292
|
+
await _this.managePeers(thisNode, useCases)
|
|
293
|
+
}, this.peerTimerInterval)
|
|
294
|
+
|
|
295
|
+
success = true
|
|
296
|
+
} catch (err) {
|
|
297
|
+
console.log('Error in timer-controller.js/managePeers(): ', err)
|
|
298
|
+
// this.adapters.log.statusLog(
|
|
299
|
+
// 2,
|
|
300
|
+
// 'Error in timer-controller.js/managePeers(): ',
|
|
301
|
+
// err
|
|
302
|
+
// )
|
|
303
|
+
|
|
304
|
+
// Reinstate the timer interval
|
|
305
|
+
const _this = this
|
|
306
|
+
this.peerTimerHandle = setInterval(async function () {
|
|
307
|
+
await _this.managePeers(thisNode, useCases)
|
|
308
|
+
}, this.peerTimerInterval)
|
|
309
|
+
|
|
310
|
+
// Note: Do not throw an error. This is a top-level function.
|
|
311
|
+
success = false
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return success
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Actively disconnect from blacklisted peers.
|
|
318
|
+
// TODO: Rename this to whitelist, as it's not a whitelist function.
|
|
319
|
+
async blacklist (thisNode, useCases) {
|
|
320
|
+
let success = false
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
// Disable the timer while processing is happening.
|
|
324
|
+
clearInterval(this.checkBlacklistHandle)
|
|
325
|
+
|
|
326
|
+
// this.statusLog('managePeers')
|
|
327
|
+
// await useCases.thisNode.enforceBlacklist()
|
|
328
|
+
await useCases.thisNode.enforceWhitelist()
|
|
329
|
+
|
|
330
|
+
this.adapters.log.statusLog(1, 'Finished enforcing whitelist.')
|
|
331
|
+
|
|
332
|
+
// Reinstate the timer interval
|
|
333
|
+
const _this = this
|
|
334
|
+
this.checkBlacklistHandle = setInterval(async function () {
|
|
335
|
+
await _this.blacklist(thisNode, useCases)
|
|
336
|
+
}, this.checkBlacklistInterval)
|
|
337
|
+
|
|
338
|
+
success = true
|
|
339
|
+
} catch (err) {
|
|
340
|
+
console.log()
|
|
341
|
+
// this.adapters.log.statusLog('Error in timer-controller.js/blacklist(): ', err)
|
|
342
|
+
// 2,
|
|
343
|
+
// 'Error in timer-controller.js/blacklist(): ',
|
|
344
|
+
// err
|
|
345
|
+
// )
|
|
346
|
+
|
|
347
|
+
// Reinstate the timer interval
|
|
348
|
+
const _this = this
|
|
349
|
+
this.checkBlacklistHandle = setInterval(async function () {
|
|
350
|
+
await _this.blacklist(thisNode, useCases)
|
|
351
|
+
}, this.checkBlacklistInterval)
|
|
352
|
+
|
|
353
|
+
// Note: Do not throw an error. This is a top-level function.
|
|
354
|
+
success = false
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return success
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// This method looks for subnet peers that have the isCircuitRelay flag set,
|
|
361
|
+
// but are not in the list of known relays. These represent potential relays
|
|
362
|
+
// that thisNode could not connect to, but it might be able to with another
|
|
363
|
+
// try.
|
|
364
|
+
async searchForRelays (thisNode, useCases) {
|
|
365
|
+
try {
|
|
366
|
+
// console.log('Entering searchForRelays() Controller.')
|
|
367
|
+
|
|
368
|
+
// Disable the timer while processing is happening.
|
|
369
|
+
clearInterval(this.relaySearchHandle)
|
|
370
|
+
|
|
371
|
+
// Get all the known relays.
|
|
372
|
+
const knownRelays = thisNode.relayData.map(x => x.ipfsId)
|
|
373
|
+
// console.log('knownRelays: ', knownRelays)
|
|
374
|
+
|
|
375
|
+
// Get all subnet peers that have their circuit relay flag set.
|
|
376
|
+
let relayPeers = thisNode.peerData.filter(x => x.data.isCircuitRelay)
|
|
377
|
+
relayPeers = relayPeers.map(x => x.from)
|
|
378
|
+
// console.log('relayPeers: ', relayPeers)
|
|
379
|
+
|
|
380
|
+
// Diff the two arrays to get relays peers that are not in the relay list.
|
|
381
|
+
const diffRelayPeers = relayPeers.filter(x => !knownRelays.includes(x))
|
|
382
|
+
// console.log('diffRelayPeers: ', diffRelayPeers)
|
|
383
|
+
|
|
384
|
+
// Try to connect to each potential relay.
|
|
385
|
+
for (let i = 0; i < diffRelayPeers.length; i++) {
|
|
386
|
+
const thisPeer = diffRelayPeers[i]
|
|
387
|
+
await useCases.relays.addRelay(thisPeer, thisNode)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Re-enable the interval timer for this function.
|
|
391
|
+
const _this = this
|
|
392
|
+
this.relaySearchHandle = setInterval(async function () {
|
|
393
|
+
await _this.searchForRelays(thisNode, useCases)
|
|
394
|
+
}, this.relaySearchInterval)
|
|
395
|
+
|
|
396
|
+
return true
|
|
397
|
+
} catch (err) {
|
|
398
|
+
console.error('Error in timer-controller.js/searchForRelays(): ', err)
|
|
399
|
+
// this.adapters.log.statusLog(
|
|
400
|
+
// 2,
|
|
401
|
+
// 'Error in timer-controller.js/searchForRelays(): ',
|
|
402
|
+
// err
|
|
403
|
+
// )
|
|
404
|
+
|
|
405
|
+
// Re-enable the interval timer for this function.
|
|
406
|
+
const _this = this
|
|
407
|
+
this.relaySearchHandle = setInterval(async function () {
|
|
408
|
+
await _this.searchForRelays(thisNode, useCases)
|
|
409
|
+
}, this.relaySearchInterval)
|
|
410
|
+
|
|
411
|
+
// Note: Do not throw an error. This is a top-level function.
|
|
412
|
+
return false
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export default TimerControllers
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This is an Entity library for creating a representation the 'self' or
|
|
3
|
+
the current IPFS node with the adding information of a BCH wallet and
|
|
4
|
+
any future features added to ipfs-coord.
|
|
5
|
+
|
|
6
|
+
There is only one instance of this class library, as there is only one
|
|
7
|
+
IPFS node that is the 'self'.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
class ThisNodeEntity {
|
|
11
|
+
// The constructor checks the input data and throws an error if any of the
|
|
12
|
+
// required data is missing.
|
|
13
|
+
constructor (localConfig = {}) {
|
|
14
|
+
this.ipfsId = localConfig.ipfsId
|
|
15
|
+
if (!this.ipfsId) {
|
|
16
|
+
throw new Error('ipfsId required when instantiating thisNode Entity')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
this.ipfsMultiaddrs = localConfig.ipfsMultiaddrs
|
|
20
|
+
if (!this.ipfsMultiaddrs) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'ipfsMultiaddrs required when instantiating thisNode Entity'
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.bchAddr = localConfig.bchAddr
|
|
27
|
+
if (!this.bchAddr) {
|
|
28
|
+
throw new Error('bchAddr required when instantiating thisNode Entity')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.slpAddr = localConfig.slpAddr
|
|
32
|
+
if (!this.slpAddr) {
|
|
33
|
+
throw new Error('slpAddr required when instantiating thisNode Entity')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.publicKey = localConfig.publicKey
|
|
37
|
+
if (!this.publicKey) {
|
|
38
|
+
throw new Error('publicKey required when instantiating thisNode Entity')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.type = localConfig.type
|
|
42
|
+
if (!this.type) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
"Node type of 'node.js' or 'browser' required when instantiating thisNode Entity"
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.schema = localConfig.schema
|
|
49
|
+
|
|
50
|
+
// This Node will keep track of peers, relays, and services.
|
|
51
|
+
// The 'List' array tracks the IPFS ID for that peer.
|
|
52
|
+
// The 'Data' array holds instances of the other Entities.
|
|
53
|
+
this.peerList = []
|
|
54
|
+
this.peerData = []
|
|
55
|
+
this.relayData = []
|
|
56
|
+
this.serviceList = []
|
|
57
|
+
this.serviceData = []
|
|
58
|
+
|
|
59
|
+
// Create a blacklist of nodes that can burden other nodes with excessive bandwidth.
|
|
60
|
+
this.blacklistPeers = [
|
|
61
|
+
// '/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
|
62
|
+
'QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
|
63
|
+
// '/dns4/node1.preload.ipfs.io/tcp/443/wss/p2p/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6',
|
|
64
|
+
'Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6',
|
|
65
|
+
// '/dns4/node2.preload.ipfs.io/tcp/443/wss/p2p/QmV7gnbW5VTcJ3oyM2Xk1rdFBJ3kTkvxc87UFGsun29STS',
|
|
66
|
+
'QmV7gnbW5VTcJ3oyM2Xk1rdFBJ3kTkvxc87UFGsun29STS',
|
|
67
|
+
// '/dns4/node3.preload.ipfs.io/tcp/443/wss/p2p/QmY7JB6MQXhxHvq7dBDh4HpbH29v4yE9JRadAVpndvzySN'
|
|
68
|
+
'QmY7JB6MQXhxHvq7dBDh4HpbH29v4yE9JRadAVpndvzySN',
|
|
69
|
+
// '/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
70
|
+
'QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
71
|
+
// '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
72
|
+
'QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
73
|
+
// '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
74
|
+
'QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
75
|
+
// '/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
76
|
+
'QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
77
|
+
// '/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
78
|
+
'QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
79
|
+
// '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
|
80
|
+
'QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
|
81
|
+
]
|
|
82
|
+
this.blacklistMultiaddrs = [
|
|
83
|
+
'/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
|
84
|
+
'/dns4/node1.preload.ipfs.io/tcp/443/wss/p2p/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6',
|
|
85
|
+
'/dns4/node2.preload.ipfs.io/tcp/443/wss/p2p/QmV7gnbW5VTcJ3oyM2Xk1rdFBJ3kTkvxc87UFGsun29STS',
|
|
86
|
+
'/dns4/node3.preload.ipfs.io/tcp/443/wss/p2p/QmY7JB6MQXhxHvq7dBDh4HpbH29v4yE9JRadAVpndvzySN',
|
|
87
|
+
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
|
88
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
|
89
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
|
90
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
|
91
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
|
92
|
+
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
|
|
93
|
+
'/dns4/node0.delegate.ipfs.io/tcp/443/https',
|
|
94
|
+
'/dns4/node1.delegate.ipfs.io/tcp/443/https',
|
|
95
|
+
'/dns4/node2.delegate.ipfs.io/tcp/443/https',
|
|
96
|
+
'/dns4/node3.delegate.ipfs.io/tcp/443/https'
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// module.exports = ThisNodeEntity
|
|
102
|
+
export default ThisNodeEntity
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This is a top-level Use Cases library. This library loads all other
|
|
3
|
+
use case libraries, and bundles them into a single object.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Local libraries
|
|
7
|
+
import ThisNodeUseCases from './this-node-use-cases.js'
|
|
8
|
+
import RelayUseCases from './relay-use-cases.js'
|
|
9
|
+
import PubsubUseCases from './pubsub-use-cases.js'
|
|
10
|
+
import PeerUseCases from './peer-use-cases.js'
|
|
11
|
+
|
|
12
|
+
class UseCases {
|
|
13
|
+
constructor (localConfig = {}) {
|
|
14
|
+
this.adapters = localConfig.adapters
|
|
15
|
+
if (!this.adapters) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'Must inject instance of adapters when instantiating Use Cases library.'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Encapsulate dependencies
|
|
22
|
+
this.thisNode = new ThisNodeUseCases(localConfig)
|
|
23
|
+
|
|
24
|
+
// Other use-cases depend on the thisNode use case.
|
|
25
|
+
localConfig.thisNodeUseCases = this.thisNode
|
|
26
|
+
|
|
27
|
+
this.relays = new RelayUseCases(localConfig)
|
|
28
|
+
this.pubsub = new PubsubUseCases(localConfig)
|
|
29
|
+
this.peer = new PeerUseCases(localConfig)
|
|
30
|
+
|
|
31
|
+
// Pass the instances of the other use cases to the ThisNode Use Cases.
|
|
32
|
+
this.thisNode.updateUseCases(this)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default UseCases
|