Skip to content

Commit baca504

Browse files
committed
Added drive API tests
1 parent 3814b8b commit baca504

File tree

6 files changed

+313
-32
lines changed

6 files changed

+313
-32
lines changed

index.js

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const grpc = require('grpc')
99

1010
const { rpc, loadMetadata } = require('hyperdrive-daemon-client')
1111
const corestore = require('random-access-corestore')
12-
const SwarmNetworker = require('megastore-swarm-networking')
12+
const SwarmNetworker = require('corestore-swarm-networking')
1313

1414
const { DriveManager, createDriveHandlers } = require('./lib/drives')
1515
const { catchErrors, serverError, requestError } = require('./lib/errors')
@@ -63,7 +63,6 @@ class HyperdriveDaemon extends EventEmitter {
6363
_ready () {
6464
return Promise.all([
6565
this.db.open(),
66-
this.megastore.ready(),
6766
this.networking.listen(),
6867
this.drives.ready(),
6968
this.fuse ? this.fuse.ready() : Promise.resolve()
@@ -72,15 +71,10 @@ class HyperdriveDaemon extends EventEmitter {
7271
})
7372
}
7473

75-
close () {
74+
async close () {
7675
if (this._isClosed) return Promise.resolve()
77-
return new Promise((resolve, reject) => {
78-
this.megastore.close(err => {
79-
if (err) return reject(err)
80-
this._isClosed = true
81-
return resolve()
82-
})
83-
})
76+
if (this.networking) await this.networking.close()
77+
this._isClosed = true
8478
}
8579

8680
async cleanup () {
@@ -90,20 +84,23 @@ class HyperdriveDaemon extends EventEmitter {
9084
}
9185
}
9286

93-
async function start () {
87+
module.exports = async function start (opts = {}) {
9488
const metadata = await new Promise((resolve, reject) => {
9589
loadMetadata((err, metadata) => {
9690
if (err) return reject(err)
9791
return resolve(metadata)
9892
})
9993
})
100-
const storageRoot = argv.storage
94+
const storageRoot = opts.storage || argv.storage
10195
await ensureStorage()
10296

10397
const daemonOpts = {}
104-
if (argv.bootstrap.length) {
105-
daemonOpts.network = {
106-
bootstrap: argv.bootstrap
98+
const bootstrapOpts = opts.bootstrap || argv.bootstrap
99+
if (bootstrapOpts.length) {
100+
if (bootstrapOpts === false && bootstrapOpts[0] === 'false') {
101+
daemonOpts.network = { bootstrap: false }
102+
} else {
103+
daemonOpts.network = { bootstrap: bootstrapOpts }
107104
}
108105
}
109106
const daemon = new HyperdriveDaemon(storageRoot, daemonOpts)
@@ -122,18 +119,22 @@ async function start () {
122119
...wrap(metadata, createMainHandlers(server, daemon), { authenticate: true })
123120
})
124121

125-
server.bind(`0.0.0.0:${argv.port}`, grpc.ServerCredentials.createInsecure())
122+
123+
const port = opts.port || argv.port
124+
server.bind(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure())
126125
server.start()
127-
log.info({ port: argv.port }, 'server listening')
126+
log.info({ port: port }, 'server listening')
128127

129128
process.once('SIGINT', cleanup)
130129
process.once('SIGTERM', cleanup)
131130
process.once('unhandledRejection', cleanup)
132131
process.once('uncaughtException', cleanup)
133132

133+
return cleanup
134+
134135
async function cleanup () {
135136
await daemon.close()
136-
server.tryDestroy()
137+
server.forceShutdown()
137138
}
138139

139140
function ensureStorage () {

lib/drives/index.js

Lines changed: 135 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ const collectStream = require('stream-collector')
77
const bjson = require('buffer-json-encoding')
88
const datEncoding = require('dat-encoding')
99

10-
const { fromHyperdriveOptions, toHyperdriveOptions } = require('hyperdrive-daemon-client/lib/common')
10+
const {
11+
fromHyperdriveOptions,
12+
toHyperdriveOptions,
13+
fromStat,
14+
toStat
15+
} = require('hyperdrive-daemon-client/lib/common')
16+
const { rpc } = require('hyperdrive-daemon-client')
17+
1118
const log = require('../log').child({ component: 'drive-manager' })
1219

1320
class DriveManager extends EventEmitter {
@@ -30,6 +37,8 @@ class DriveManager extends EventEmitter {
3037
// TODO: Replace with an LRU cache.
3138
this._drives = new Map()
3239
this._sessions = new Map()
40+
this._watchers = new Map()
41+
this._sessionCounter = 0
3342

3443
this._ready = new Promise(async resolve => {
3544
await this._reseed()
@@ -97,6 +106,22 @@ class DriveManager extends EventEmitter {
97106
return keyString
98107
}
99108

109+
driveForSession (sessionId) {
110+
const drive = this._sessions.get(sessionId)
111+
if (!drive) throw new Error('Session does not exist.')
112+
return drive
113+
}
114+
115+
async createSession (key, opts) {
116+
const drive = await this.get(key, opts)
117+
this._sessions.set(++this._sessionCounter, drive)
118+
return { drive, session: this._sessionCounter }
119+
}
120+
121+
async closeSession (id) {
122+
this._sessions.delete(id)
123+
}
124+
100125
async get (key, opts) {
101126
key = (key instanceof Buffer) ? datEncoding.decode(key) : key
102127
var keyString = this._generateKeyString(key, opts)
@@ -121,7 +146,7 @@ class DriveManager extends EventEmitter {
121146
})
122147

123148
key = datEncoding.encode(drive.key)
124-
keyString = this._generateKeystring(key, opts)
149+
keyString = this._generateKeyString(key, opts)
125150

126151

127152
if (drive.writable) {
@@ -192,12 +217,117 @@ function createDriveHandlers (driveManager) {
192217
var driveOpts = call.request.getOpts()
193218
if (driveOpts) driveOpts = fromHyperdriveOptions(driveOpts)
194219

195-
const drive = await driveManager.get(driveOpts.key, driveOpts)
220+
const { drive, session } = await driveManager.createSession(driveOpts.key, driveOpts)
196221
driveOpts.key = drive.key
197222
driveOpts.version = drive.version
198223

199-
const rsp = new rpc.drive.messages.GetResponse()
200-
rsp.setOpts(driveOpts)
224+
const rsp = new rpc.drive.messages.GetDriveResponse()
225+
rsp.setId(session)
226+
rsp.setOpts(toHyperdriveOptions(driveOpts))
227+
228+
return rsp
229+
},
230+
231+
readFile: async (call) => {
232+
const id = call.request.getId()
233+
const path = call.request.getPath()
234+
235+
if (!id) throw new Error('A readFile request must specify a session ID.')
236+
if (!path) throw new Error('A writeFile request must specify a path.')
237+
const drive = driveManager.driveForSession(id)
238+
239+
return new Promise((resolve, reject) => {
240+
drive.readFile(path, (err, content) => {
241+
if (err) return reject(err)
242+
243+
const rsp = new rpc.drive.messages.ReadFileResponse()
244+
rsp.setContent(content)
245+
246+
return resolve(rsp)
247+
})
248+
})
249+
},
250+
251+
writeFile: async (call) => {
252+
const id = call.request.getId()
253+
const path = call.request.getPath()
254+
const contents = Buffer.from(call.request.getContent())
255+
256+
if (!id) throw new Error('A writeFile request must specify a session ID.')
257+
if (!path) throw new Error('A writeFile request must specify a path.')
258+
if (!contents) throw new Error('A writeFile request must specify contents.')
259+
const drive = driveManager.driveForSession(id)
260+
261+
return new Promise((resolve, reject) => {
262+
drive.writeFile(path, contents, (err) => {
263+
if (err) return reject(err)
264+
const rsp = new rpc.drive.messages.WriteFileResponse()
265+
return resolve(rsp)
266+
})
267+
})
268+
},
269+
270+
stat: async (call) => {
271+
const id = call.request.getId()
272+
const path = call.request.getPath()
273+
const lstat = call.request.getLstat()
274+
275+
if (!id) throw new Error('A stat request must specify a session ID.')
276+
if (!path) throw new Error('A stat request must specify a path. ')
277+
const drive = driveManager.driveForSession(id)
278+
279+
return new Promise((resolve, reject) => {
280+
drive.stat(path, { followLink: lstat }, (err, stat) => {
281+
if (err) return reject(err)
282+
283+
const rsp = new rpc.drive.messages.StatResponse()
284+
rsp.setStat(toStat(stat))
285+
286+
return resolve(rsp)
287+
})
288+
})
289+
},
290+
291+
readdir: async (call) => {
292+
const id = call.request.getId()
293+
const path = call.request.getPath()
294+
const recursive = call.request.getRecursive()
295+
296+
if (!id) throw new Error('A readdir request must specify a session ID.')
297+
if (!path) throw new Error('A readdir request must specify a path. ')
298+
const drive = driveManager.driveForSession(id)
299+
300+
return new Promise((resolve, reject) => {
301+
drive.readdir(path, { recursive }, (err, files) => {
302+
if (err) return reject(err)
303+
304+
const rsp = new rpc.drive.messages.ReadDirectoryResponse()
305+
console.log('FILES:', files)
306+
rsp.setFilesList(files)
307+
308+
return resolve(rsp)
309+
})
310+
})
311+
},
312+
313+
watch: async (call) => {
314+
315+
},
316+
317+
listen: async (call) => {
318+
319+
},
320+
321+
unwatch: async (call) => {
322+
323+
},
324+
325+
closeSession: async (call) => {
326+
const id = call.request.getId()
327+
328+
const drive = driveManager.driveForSession(id)
329+
driveManager.closeSession(id)
330+
const rsp = new rpc.drive.messages.CloseSessionResponse()
201331

202332
return rsp
203333
}

lib/fuse/index.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,19 +248,16 @@ class FuseManager extends EventEmitter {
248248

249249
async _driveForPath (path, opts = {}) {
250250
const self = this
251-
console.error('GETTING DRIVE FOR PATH:', path)
252251
if (!this._rootDrive && path !== '/hyperdrive') throw new Error('You can only mount the root hyperdrive at /hyperdrive')
253252

254253
if (!this._rootDrive) {
255-
console.log('NO ROOT DRIVE')
256254
const drive = await this.driveManager.get(opts.key, { ...opts, configure: { rootDrive: true } })
257255
return { drive, root: true }
258256
}
259257

260258
if (path.startsWith(this._rootMnt) && path !== this._rootMnt) {
261259
const relativePath = path.slice(this._rootMnt.length)
262260
if (!relativePath.startsWith('/home')) throw new Error('You can only mount sub-hyperdrives within the home directory.')
263-
console.error('IT IS A SUBDRIVE, RELATIVE:', relativePath)
264261
return getSubdrive(relativePath)
265262
}
266263

@@ -277,9 +274,7 @@ class FuseManager extends EventEmitter {
277274
})
278275
const drive = await self.driveManager.get(key, { ...opts })
279276
if (opts.key) {
280-
console.error('PUBLISHING DRIVE BY KEY')
281277
await self.driveManager.publish(drive)
282-
console.error('PUBLISHED')
283278
}
284279
return { drive, relativePath, root: false }
285280
}

lib/log.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ const argv = require('yargs').argv
44
// Forever will redirect stdout to the correct log file.
55
module.exports = pino({
66
name: 'hyperdrive',
7-
level: argv['log-level'],
7+
level: argv['log-level'] || 'info',
88
enabled: true,
99
}, pino.destination(2))

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
},
2626
"homepage": "https://github.com/andrewosh/hyperdrive-daemon#readme",
2727
"dependencies": {
28+
"buffer-json-encoding": "^1.0.2",
2829
"chalk": "^2.4.2",
2930
"collect-stream": "^1.2.1",
3031
"dat-encoding": "^5.0.1",
@@ -37,9 +38,9 @@
3738
"hyperdrive-daemon-client": "^0.9.4",
3839
"hyperdrive-fuse": "^1.1.0",
3940
"level": "^4.0.0",
40-
"mkdirp": "^0.5.1",
41-
"mini-megastore": "^1.0.0",
4241
"megastore-swarm-networking": "^1.0.0",
42+
"mini-megastore": "^1.0.0",
43+
"mkdirp": "^0.5.1",
4344
"ora": "^3.4.0",
4445
"pino": "^5.12.6",
4546
"prettier-bytes": "^1.0.4",
@@ -51,8 +52,10 @@
5152
},
5253
"devDependencies": {
5354
"memdb": "^1.3.1",
55+
"pify": "^4.0.1",
5456
"random-access-memory": "^3.1.1",
5557
"standard": "^12.0.1",
56-
"tape": "^4.10.1"
58+
"tape": "^4.10.1",
59+
"tmp-promise": "^2.0.1"
5760
}
5861
}

0 commit comments

Comments
 (0)