| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 |
1
1
11
11
2
11
1
2
2
2
16
2
1
6
6
6
6
6
59
1
323
323
323
323
1
1560
1560
1560
1272
1
59
1
32
506
134
134
128
512
134
8
538
538
538
1351
1351
331
323
323
8
1343
1343
530
538
361
| /*
* Copyright 2014-2016, Sébastien Piquemal <sebpiq@gmail.com>
*
* rhizome is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* rhizome is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rhizome. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var crypto = require('crypto')
, fs = require('fs')
, path = require('path')
, tmp = require('tmp')
, async = require('async')
, _ = require('underscore')
, chai = require('chai')
, coreMessages = require('./messages')
// Validates that the directory at `dirPath` exists, then calls `done`
var assertDirExists = exports.assertDirExists = function(dirPath, done) {
fs.open(dirPath, 'r', (err) => {
if (err && err.code === 'ENOENT')
err = new chai.AssertionError('path \'' + dirPath + '\' does not exist')
done(err)
})
}
// Gets a random string using `byteNum` bytes.
var getRandomString = exports.getRandomString = function(byteNum) {
byteNum = byteNum || 4
var str = '', i, length, buf = crypto.randomBytes(byteNum)
for (i = 0, length = buf.length; i < length; i++)
str += buf[i].toString(10)
return str
}
// Utility to save `blob` in `dirName`, automatically assigning it a filename.
// When this is complete, `done(err, filePath)` is called.
exports.saveBlob = function(dirName, blob, done, extension) {
var tmpl = path.join(dirName, 'XXXXXX')
if (extension) tmpl += extension
async.waterfall([
(next) => tmp.tmpName({ template: tmpl }, next),
(filePath, next) => fs.writeFile(filePath, blob, (err) => next(err, filePath))
], done)
}
// ========================= NAMESPACE TREE ========================= //
exports.createNsTree = function() { return new NsTree() }
var NsNode = function(address) {
this.address = address
this.children = {}
this.connections = []
this.lastMessage = null
}
_.extend(NsNode.prototype, {
// Calls `iter(ns)` on all the nodes in the subtree.
forEach: function(iter) {
var children = _.values(this.children)
iter(this)
if (children.length)
_.forEach(children, (ns) => ns.forEach(iter))
}
})
var NsTree = function() {
this._root = { children: {}, address: '' }
}
_.extend(NsTree.prototype, {
has: function(address) { return this._traverse(address) !== null },
get: function(address, iter) { return this._traverse(address, iter, true) },
toJSON: function() {
var returned = []
_.values(this._root.children).forEach((rootNode) => {
rootNode.forEach((node) => {
returned.push({ address: node.address, lastMessage: node.lastMessage })
})
})
return returned
},
fromJSON: function(nodeData) {
nodeData.forEach((data) => this.get(data.address).lastMessage = data.lastMessage)
},
_traverse: function(address, iter, create) {
address = coreMessages.normalizeAddress(address)
var parts = this._getParts(address)
, ns = this._root
, part, currentAddr
while (parts.length) {
part = parts.shift()
if (!ns.children[part]) {
if (create) {
currentAddr = ns.address === '/' ? ('/' + part) : (ns.address + '/' + part)
ns.children[part] = new NsNode(currentAddr)
} else return null
}
ns = ns.children[part]
if (iter) iter(ns)
}
return ns
},
// Split address into normalized parts.
// /a/b/c -> ['', 'a', 'b']
// / -> ['']
_getParts: function(address) {
if (address === '/') return ['']
else return address.split('/')
}
})
|