Skip to content

Commit 90003af

Browse files
committed
Root drive mounting works
1 parent cba3803 commit 90003af

File tree

8 files changed

+220
-110
lines changed

8 files changed

+220
-110
lines changed

bin/setup.js

+28-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const p = require('path')
2-
const { spawn } = require('child_process')
2+
const { spawn, exec } = require('child_process')
33

44
const hyperfuse = require('hyperdrive-fuse')
55
const ora = require('ora')
@@ -9,11 +9,32 @@ exports.command = 'setup'
99
exports.desc = 'Run a one-time configuration step for FUSE.'
1010
exports.handler = async function (argv) {
1111
console.log(chalk.blue('Configuring FUSE...'))
12-
const child = spawn('sudo', ['node', p.join(__dirname, '../scripts/configure.js')], {
13-
stdio: 'inherit'
14-
})
15-
child.on('exit', code => {
16-
if (code !== 0) return console.error(chalk.red(`Could not configure FUSE.`))
17-
console.log(chalk.green('Successfully configured FUSE!'))
12+
hyperfuse.isConfigured((err, configured) => {
13+
if (err) return onerror(err)
14+
if (configured) return onsuccess('FUSE is already configured!')
15+
return configure()
1816
})
17+
18+
function configure () {
19+
exec('which node', (err, nodePath) => {
20+
if (err) return onerror(err)
21+
nodePath = nodePath.trim()
22+
const child = spawn('sudo', [nodePath, p.join(__dirname, '../scripts/configure.js')], {
23+
stdio: 'inherit'
24+
})
25+
child.on('exit', code => {
26+
if (code !== 0) return onerror()
27+
return onsuccess('Successfully configured FUSE!')
28+
})
29+
})
30+
}
31+
32+
function onsuccess (msg) {
33+
console.log(chalk.green(msg))
34+
}
35+
36+
function onerror (err) {
37+
console.error(chalk.red(`Could not configure FUSE.`))
38+
if (err) console.error(chalk.red(err))
39+
}
1940
}

bin/start.js

-4
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,13 @@ exports.builder = {
2121
}
2222
exports.handler = async function (argv) {
2323
const client = new HyperdriveClient(`localhost:${argv.port}`)
24-
console.log(0)
2524
client.ready(err => {
26-
console.log('err:', err)
2725
if (err) return onerror(err)
2826
console.log(chalk.green('The Hyperdrive daemon is already running.'))
2927
})
3028

3129
function onerror (err) {
3230
if (!err.disconnected) return showError(err)
33-
console.log('starting here')
3431
start(argv).catch(showError)
3532
}
3633

@@ -41,7 +38,6 @@ exports.handler = async function (argv) {
4138
}
4239

4340
async function start (argv) {
44-
console.log('in start')
4541
let endpoint = `localhost:${argv.port}`
4642
await createMetadata(endpoint)
4743
forever.startDaemon(p.join(__dirname, '..', 'index.js'), {

index.js

+52-25
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,21 @@ class HyperdriveDaemon extends EventEmitter {
3030
this.db = level(`${storage}/db`, { valueEncoding: 'json' })
3131
this.opts = opts
3232

33+
const dbs = {
34+
megastore: sub(this.db, 'megastore'),
35+
fuse: sub(this.db, 'fuse', { valueEncoding: 'json' }),
36+
drives: sub(this.db, 'drives', { valueEncoding: 'json' })
37+
}
38+
3339
const megastoreOpts = {
3440
storage: path => raf(`${storage}/cores/${path}`),
35-
db: sub(this.db, 'megastore'),
41+
db: dbs.megastore,
3642
networker: new SwarmNetworker(opts.network)
3743
}
44+
3845
this.megastore = new Megastore(megastoreOpts.storage, megastoreOpts.db , megastoreOpts.networker)
39-
this.drives = new DriveManager(this.megastore, sub(this.db, 'drives'), this.opts)
40-
this.fuse = hyperfuse ? new FuseManager(this.megastore, this.drives, sub(this.db, 'fuse'), this.opts) : null
46+
this.drives = new DriveManager(this.megastore, dbs.drives, this.opts)
47+
this.fuse = hyperfuse ? new FuseManager(this.megastore, this.drives, dbs.fuse, this.opts) : null
4148

4249
this.drives.on('error', err => this.emit('error', err))
4350
this.fuse.on('error', err => this.emit('error', err))
@@ -90,34 +97,33 @@ async function start () {
9097
const storageRoot = argv.storage
9198
await ensureStorage()
9299

93-
const hypermount = new HyperdriveDaemon(storageRoot)
94-
await hypermount.ready()
100+
const daemon = new HyperdriveDaemon(storageRoot)
101+
await daemon.ready()
95102

96103
const server = new grpc.Server();
97104
if (hyperfuse) {
98105
server.addService(rpc.fuse.services.FuseService, {
99-
...authenticate(metadata, catchErrors(createFuseHandlers(this.fuseManager)))
106+
...wrap(metadata, createFuseHandlers(daemon.fuse), { authenticate: true })
100107
})
101108
}
102109
server.addService(rpc.drive.services.DriveService, {
103-
...authenticate(metadata, catchErrors(createDriveHandlers(this.driveManager)))
110+
...wrap(metadata, createDriveHandlers(daemon.drives), { authenticate: true })
104111
})
105112
server.addService(rpc.main.services.HyperdriveService, {
106-
...authenticate(metadata, catchErrors(createMainHandlers(this)))
113+
...wrap(metadata, createMainHandlers(daemon), { authenticate: true })
107114
})
108115

109-
console.log('binding server...')
110116
server.bind(`0.0.0.0:${argv.port}`, grpc.ServerCredentials.createInsecure())
111117
server.start()
112-
console.log('server started.')
118+
log.info({ port: argv.port }, 'server listening')
113119

114120
process.once('SIGINT', cleanup)
115121
process.once('SIGTERM', cleanup)
116122
process.once('unhandledRejection', cleanup)
117123
process.once('uncaughtException', cleanup)
118124

119125
async function cleanup () {
120-
await hypermount.close()
126+
await daemon.close()
121127
server.tryDestroy()
122128
}
123129

@@ -131,26 +137,47 @@ async function start () {
131137
}
132138
}
133139

134-
function authenticate (metadata, methods) {
135-
const authenticated = {}
140+
function wrap (metadata, methods) {
141+
const promisified = promisify(methods)
142+
let authenticated = authenticate(metadata, methods)
143+
}
144+
145+
function wrap (metadata, methods, opts) {
146+
const wrapped = {}
147+
const authenticate = opts && opts.authenticate
136148
for (const methodName of Object.keys(methods)) {
137149
const method = methods[methodName]
138-
authenticated[methodName] = function (call, ...args) {
139-
const cb = args[args.length - 1]
140-
const token = call.metadata && call.metadata.token
141-
if (!token || !token.equals(metadata.token)) {
142-
const err = {
143-
code: grpc.status.UNAUTHENTICATED,
144-
message: 'Invalid auth token.'
150+
wrapped[methodName] = function (call, ...args) {
151+
const tag = { method: methodName, received: Date.now() }
152+
const cb = args.length ? args[args.length - 1] : null
153+
if (authenticate) {
154+
let token = call.metadata && call.metadata.get('token')
155+
if (token) token = token[0]
156+
log.trace({ ...tag, token }, 'received token')
157+
if (!token || token !== metadata.token) {
158+
log.error(tag, 'request authentication failed')
159+
const err = {
160+
code: grpc.status.UNAUTHENTICATED,
161+
message: 'Invalid auth token.'
162+
}
163+
if (cb) return cb(err)
164+
return call.destroy(err)
145165
}
146-
if (cb) return cb(err)
147-
return call.destroy(err)
166+
log.debug(tag, 'request authentication succeeded')
148167
}
149-
150-
return method(call, ...args)
168+
method(call)
169+
.then(rsp => {
170+
log.debug(tag, 'request was successful')
171+
if (cb) return cb(null, rsp)
172+
})
173+
.catch(err => {
174+
log.error({ ...tag, error: err.toString(), stack: err.stack }, 'request failed')
175+
if (cb) return cb(serverError(err))
176+
return call.destroy(err)
177+
})
151178
}
152179
}
153-
return authenticated
180+
return wrapped
154181
}
155182

156183
function createMainHandlers (daemon) {

lib/drives/index.js

+24-6
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,28 @@ class DriveManager extends EventEmitter {
3030
this.ready = () => Promise.resolve()
3131
}
3232

33-
_configureDrive (drive) {
33+
_configureDrive (drive, opts) {
3434
// TODO: Extract this into a separate, easily-modifiable script.
3535
return new Promise((resolve, reject) => {
36-
drive.writeFile('.key', drive.key.toString('hex'), err => {
37-
if (err) return reject(err)
38-
return resolve()
36+
drive.readFile('.key', err => {
37+
if (err && !err.errno === 2) return reject(err)
38+
if (err) return configure()
39+
return resolve(0)
3940
})
41+
42+
function configure () {
43+
drive.writeFile('.key', drive.key.toString('hex'), err => {
44+
if (err) return reject(err)
45+
if (opts && opts.rootDrive) {
46+
drive.mkdir('/home', err => {
47+
if (err) return reject(err)
48+
return resolve(err)
49+
})
50+
} else {
51+
return resolve()
52+
}
53+
})
54+
}
4055
})
4156
}
4257

@@ -95,7 +110,7 @@ class DriveManager extends EventEmitter {
95110
newDrive = true
96111
}
97112

98-
log.debug({ name, key, opts }, 'creating a hyperdrive')
113+
// log.debug({ name, key, opts }, 'creating a hyperdrive')
99114
const corestore = this.megastore.get(name)
100115
const driveOpts = {
101116
...opts,
@@ -110,8 +125,11 @@ class DriveManager extends EventEmitter {
110125
return resolve()
111126
})
112127
})
128+
key = datEncoding.encode(drive.key)
113129

114-
await this._configureDrive(drive)
130+
if (drive.writable) {
131+
await this._configureDrive(drive, opts && opts.configure)
132+
}
115133
if (newDrive && this.opts.stats) {
116134
this._collectStats(drive)
117135
}

lib/errors.js

+4-27
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,19 @@ const grpc = require('grpc')
33
function serverError (err) {
44
return {
55
code: grpc.status.UNKNOWN,
6-
msg: err.toString()
6+
message: err.toString()
77
}
88
}
99

10-
function requestError (msg) {
10+
function requestError (message) {
1111
return {
1212
// TODO: better error code for malformed requests?
1313
code: grpc.status.UNIMPLEMENTED,
14-
msg
14+
message
1515
}
1616
}
1717

18-
function catchErrors (methods) {
19-
const checked = {}
20-
for (const methodName of Object.keys(methods)) {
21-
const method = methods[methodName]
22-
checked[methodName] = function (call, ...args) {
23-
// TODO: Support better middleware so that this can be extracted.
24-
const cb = args[args.length - 1]
25-
method(call)
26-
.then(rsp => {
27-
if (cb) return cb(null, rsp)
28-
return call.end(rsp)
29-
})
30-
.catch(err => {
31-
const error = serverError(err)
32-
if (cb) return cb(error)
33-
return call.destroy(error)
34-
})
35-
}
36-
}
37-
return checked
38-
}
39-
4018
module.exports = {
4119
serverError,
42-
requestError,
43-
catchErrors
20+
requestError
4421
}

0 commit comments

Comments
 (0)