git ssb

0+

wanderer🌟 / js-dfinity-radix-tree



Commit 523fd9bda6df579abb596ed6e04a5c19c32ef4c2

Merge pull request #11 from dfinity/remote-datastore

add remote datastore
wanderer authored on 4/5/2018, 7:41:17 PM
GitHub committed on 4/5/2018, 7:41:17 PM
Parent: ccf8f0f9324db6b24936206bd97e1f8554e7dacb
Parent: eb2b91e814ad8589fb6c3b7c0c1d9714a040b688

Files changed

.gitignorechanged
package-lock.jsonchanged
package.jsonchanged
tests/index.jschanged
tests/remote.jsadded
fetch.jsadded
remoteDatastore.jsadded
.gitignoreView
@@ -1,2 +1,3 @@
11 node_modules
22 testdb
3+localdb
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 358065 bytes
New file size: 359194 bytes
package.jsonView
@@ -20,19 +20,24 @@
2020 ],
2121 "devDependencies": {
2222 "coveralls": "^3.0.0",
2323 "documentation": "^6.1.0",
24+ "fs-extra": "^5.0.0",
2425 "level-browserify": "^1.1.2",
2526 "nyc": "^11.6.0",
2627 "standard": "^11.0.1",
2728 "tape": "^4.6.3"
2829 },
2930 "dependencies": {
3031 "borc": "git+https://github.com/dignifiedquire/borc.git#fix/nested-array",
3132 "ipld-graph-builder": "^1.3.8",
33+ "node-fetch": "^2.1.2",
3234 "text-encoding": "^0.6.4",
3335 "uint1array": "^1.0.5"
3436 },
37+ "browser": {
38+ "node-fetch": "./fetch.js"
39+ },
3540 "standard": {
3641 "ignore": [
3742 "/benchmark/"
3843 ]
tests/index.jsView
@@ -1,8 +1,11 @@
1+const fs = require('fs-extra')
12 const tape = require('tape')
23 const crypto = require('crypto')
34 const level = require('level-browserify')
45 const RadixTree = require('../')
6+const RemoteDataStore = require('../remoteDatastore')
7+const remote = require('./remote')
58 const db = level('./testdb')
69
710 tape('root existance', async t => {
811 let tree = new RadixTree({
@@ -202,4 +205,35 @@
202205 t.deepEquals(tree._root['/'], RadixTree.emptyTreeState)
203206
204207 t.end()
205208 })
209+
210+tape('remote', async t => {
211+ // remote
212+ const remoteTree = new RadixTree({
213+ db: db
214+ })
215+ const server = remote.listen(db)
216+
217+ const entries = 100
218+ for (let i = 0; i < entries; i++) {
219+ const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20)
220+ remoteTree.set(key, Buffer.from([i]))
221+ }
222+ const stateRoot = await remoteTree.flush()
223+
224+ // local
225+ fs.removeSync('./localdb')
226+ const localTree = new RadixTree({
227+ dag: new RemoteDataStore(level('./localdb'), {uri: 'http://localhost:3000'})
228+ })
229+ localTree.root = stateRoot
230+
231+ for (let i = 0; i < entries; i++) {
232+ const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20)
233+ const value = await localTree.get(key)
234+ t.equals(value.value[0], i)
235+ }
236+
237+ server.close()
238+ t.end()
239+})
tests/remote.jsView
@@ -1,0 +1,26 @@
1+const RadixTree = require('../')
2+
3+const cbor = require('borc')
4+const http = require('http')
5+
6+let tree
7+
8+const server = http.createServer(async (req, res) => {
9+ const key = Buffer.from(req.url.slice(1), 'hex')
10+ const value = await tree.graph._dag.get(key)
11+ res.end(cbor.encode(value).toString('base64'))
12+})
13+
14+module.exports = {
15+ listen: (db, port = 3000) => {
16+ server.listen(port, (err) => {
17+ if (err) { return console.error(err) }
18+
19+ tree = new RadixTree({db})
20+
21+ console.log(`server is listening on ${port}`)
22+ })
23+
24+ return server
25+ }
26+}
fetch.jsView
@@ -1,0 +1,1 @@
1+module.exports = window.fetch
remoteDatastore.jsView
@@ -1,0 +1,52 @@
1+const Buffer = require('safe-buffer').Buffer
2+const TreeDAG = require('./datastore.js')
3+const fetch = require('node-fetch')
4+
5+module.exports = class RemoteTreeDAG extends TreeDAG {
6+ /**
7+ * @param dag {object} a level db instance
8+ * @param remoteOpts
9+ * @param remoteOpts.uri {string} the HTTP uri which has an interface: GET /:key -> value
10+ * @param remoteOpts.encoding {string} the encoding of the reponse
11+ * @param opts.decoder {object} a cbor decoder
12+ */
13+ constructor (dag, remoteOpts, decoder) {
14+ super(dag, decoder)
15+ this.remoteOpts = Object.assign({
16+ uri: null,
17+ encoding: 'base64'
18+ }, remoteOpts)
19+ }
20+
21+ async get (link) {
22+ try {
23+ return await super.get(link)
24+ } catch (e) {
25+ if (this.remoteOpts.uri) {
26+ await this.fetchRemote(link)
27+ return super.get(link)
28+ }
29+ }
30+ }
31+
32+ fetchRemote (key) {
33+ if (!Buffer.isBuffer(key)) {
34+ key = Buffer.from(key.buffer)
35+ }
36+
37+ const route = `${this.remoteOpts.uri}/${key.toString('hex')}`
38+ return fetch(route)
39+ .then(res => res.text())
40+ .then(text => {
41+ const encoded = Buffer.from(text, this.remoteOpts.encoding)
42+ return new Promise((resolve, reject) => {
43+ this._dag.put(key, encoded.toString('hex'), () => {
44+ resolve(key)
45+ })
46+ })
47+ })
48+ .catch(err => {
49+ console.warn(`error fetching ${route}:`, err.message)
50+ })
51+ }
52+}

Built with git-ssb-web