1
1
const p = require ( 'path' )
2
+ const os = require ( 'os' )
2
3
const { EventEmitter } = require ( 'events' )
3
4
4
5
const mkdirp = require ( 'mkdirp' )
5
6
const raf = require ( 'random-access-file' )
6
7
const level = require ( 'level' )
7
8
const sub = require ( 'subleveldown' )
8
9
const grpc = require ( '@grpc/grpc-js' )
9
-
10
- const { rpc, loadMetadata } = require ( 'hyperdrive-daemon-client' )
11
10
const corestore = require ( 'corestore' )
12
11
const SwarmNetworker = require ( 'corestore-swarm-networking' )
13
12
14
- const { DriveManager, createDriveHandlers } = require ( './lib/drives' )
13
+ const { rpc, loadMetadata } = require ( 'hyperdrive-daemon-client' )
14
+ const constants = require ( 'hyperdrive-daemon-client/lib/constants' )
15
+
16
+ const DriveManager = require ( './lib/drives' )
15
17
const { catchErrors, serverError, requestError } = require ( './lib/errors' )
16
18
17
19
try {
18
20
var hyperfuse = require ( 'hyperdrive-fuse' )
19
- var { FuseManager, createFuseHandlers } = require ( './lib/fuse' )
21
+ var FuseManager = require ( './lib/fuse' )
20
22
} catch ( err ) {
21
23
console . warn ( 'FUSE bindings are not available on this platform.' )
22
24
}
23
25
const log = require ( './lib/log' ) . child ( { component : 'server' } )
24
- const argv = extractArguments ( )
26
+
27
+ const STOP_EVENTS = [ 'SIGINT' , 'SIGTERM' , 'unhandledRejection' , 'uncaughtException' ]
25
28
26
29
class HyperdriveDaemon extends EventEmitter {
27
- constructor ( storage , opts = { } ) {
30
+ constructor ( opts = { } ) {
28
31
super ( )
29
32
30
- this . db = level ( `${ storage } /db` , { valueEncoding : 'json' } )
31
33
this . opts = opts
34
+ this . storage = opts . storage || constants . storage
35
+ this . port = opts . port || constants . port
32
36
37
+ this . db = level ( `${ this . storage } /db` , { valueEncoding : 'json' } )
33
38
const dbs = {
34
39
fuse : sub ( this . db , 'fuse' , { valueEncoding : 'json' } ) ,
35
40
drives : sub ( this . db , 'drives' , { valueEncoding : 'json' } )
36
41
}
37
42
38
43
const corestoreOpts = {
39
- storage : path => raf ( `${ storage } /cores/${ path } ` ) ,
44
+ storage : path => raf ( `${ this . storage } /cores/${ path } ` ) ,
40
45
sparse : true ,
41
46
// Collect networking statistics.
42
47
stats : true
@@ -45,9 +50,21 @@ class HyperdriveDaemon extends EventEmitter {
45
50
// The root corestore should be bootstrapped with an empty default feed.
46
51
this . corestore . default ( )
47
52
48
- this . networking = new SwarmNetworker ( this . corestore , opts . network )
53
+ const bootstrapOpts = opts . bootstrap || constants . bootstrap
54
+ if ( bootstrapOpts && bootstrapOpts . length && bootstrapOpts [ 0 ] !== '' ) {
55
+ if ( bootstrapOpts === false && bootstrapOpts [ 0 ] === 'false' ) {
56
+ var networkOpts = { bootstrap : false }
57
+ } else {
58
+ networkOpts = { bootstrap : bootstrapOpts }
59
+ }
60
+ }
61
+ this . networking = new SwarmNetworker ( this . corestore , networkOpts )
62
+
49
63
this . drives = new DriveManager ( this . corestore , this . networking , dbs . drives , this . opts )
50
64
this . fuse = hyperfuse ? new FuseManager ( this . megastore , this . drives , dbs . fuse , this . opts ) : null
65
+ // Set in start.
66
+ this . server = null
67
+ this . _cleanup = null
51
68
52
69
this . drives . on ( 'error' , err => this . emit ( 'error' , err ) )
53
70
this . fuse . on ( 'error' , err => this . emit ( 'error' , err ) )
@@ -61,7 +78,15 @@ class HyperdriveDaemon extends EventEmitter {
61
78
}
62
79
}
63
80
64
- _ready ( ) {
81
+ async _ready ( ) {
82
+ await this . _loadMetadata ( )
83
+ await this . _ensureStorage ( )
84
+
85
+ this . _cleanup = this . stop . bind ( this )
86
+ for ( const event of STOP_EVENTS ) {
87
+ process . once ( event , this . _cleanup )
88
+ }
89
+
65
90
return Promise . all ( [
66
91
this . db . open ( ) ,
67
92
this . networking . listen ( ) ,
@@ -72,89 +97,85 @@ class HyperdriveDaemon extends EventEmitter {
72
97
} )
73
98
}
74
99
75
- async close ( ) {
76
- if ( this . _isClosed ) return Promise . resolve ( )
77
- if ( this . fuse && this . fuse . fuseConfigured ) await this . fuse . unmount ( )
78
- if ( this . networking ) await this . networking . close ( )
79
- await this . db . close ( )
80
- this . _isClosed = true
100
+ async _loadMetadata ( ) {
101
+ this . metadata = this . opts . metadata || await new Promise ( ( resolve , reject ) => {
102
+ loadMetadata ( ( err , metadata ) => {
103
+ if ( err ) return reject ( err )
104
+ return resolve ( metadata )
105
+ } )
106
+ } )
81
107
}
82
- }
83
108
84
- async function start ( opts = { } ) {
85
- const metadata = opts . metadata || await new Promise ( ( resolve , reject ) => {
86
- loadMetadata ( ( err , metadata ) => {
87
- if ( err ) return reject ( err )
88
- return resolve ( metadata )
109
+ _ensureStorage ( ) {
110
+ return new Promise ( ( resolve , reject ) => {
111
+ mkdirp ( this . storage , err => {
112
+ if ( err ) return reject ( err )
113
+ return resolve ( )
114
+ } )
89
115
} )
90
- } )
91
- const storageRoot = opts . storage || argv . storage
92
- await ensureStorage ( )
93
-
94
- const daemonOpts = { }
95
- const bootstrapOpts = opts . bootstrap || argv . bootstrap
96
- if ( bootstrapOpts . length && bootstrapOpts [ 0 ] !== '' ) {
97
- if ( bootstrapOpts === false && bootstrapOpts [ 0 ] === 'false' ) {
98
- daemonOpts . network = { bootstrap : false }
99
- } else {
100
- daemonOpts . network = { bootstrap : bootstrapOpts }
101
- }
102
116
}
103
117
104
- const daemon = new HyperdriveDaemon ( storageRoot , daemonOpts )
105
- await daemon . ready ( )
118
+ createMainHandlers ( ) {
119
+ return {
120
+ stop : async ( call ) => {
121
+ await this . close ( )
122
+ setTimeout ( ( ) => {
123
+ console . error ( 'Daemon is exiting.' )
124
+ this . server . forceShutdown ( )
125
+ } , 250 )
126
+ return new rpc . main . messages . StopResponse ( )
127
+ } ,
106
128
107
- const server = new grpc . Server ( ) ;
108
- if ( hyperfuse ) {
109
- server . addService ( rpc . fuse . services . FuseService , {
110
- ...wrap ( metadata , createFuseHandlers ( daemon . fuse ) , { authenticate : true } )
111
- } )
129
+ status : async ( call ) => {
130
+ return new rpc . main . messages . StatusResponse ( )
131
+ }
132
+ }
112
133
}
113
- server . addService ( rpc . drive . services . DriveService , {
114
- ...wrap ( metadata , createDriveHandlers ( daemon . drives ) , { authenticate : true } )
115
- } )
116
- server . addService ( rpc . main . services . HyperdriveService , {
117
- ...wrap ( metadata , createMainHandlers ( server , daemon ) , { authenticate : true } )
118
- } )
119
-
120
-
121
- const port = opts . port || argv . port
122
- await new Promise ( ( resolve , reject ) => {
123
- server . bindAsync ( `0.0.0.0:${ port } ` , grpc . ServerCredentials . createInsecure ( ) , ( err , port ) => {
124
- if ( err ) return reject ( err )
125
- log . info ( { port : port } , 'server listening' )
126
- server . start ( )
127
- return resolve ( )
128
- } )
129
- } )
130
134
131
- const cleanupEvents = [ 'SIGINT' , 'SIGTERM' , 'unhandledRejection' , 'uncaughtException' ]
132
- for ( const event of cleanupEvents ) {
133
- process . once ( event , cleanup )
135
+ async stop ( ) {
136
+ if ( this . _isClosed ) return Promise . resolve ( )
137
+
138
+ if ( this . fuse && this . fuse . fuseConfigured ) await this . fuse . unmount ( )
139
+ if ( this . networking ) await this . networking . close ( )
140
+ if ( this . server ) this . server . forceShutdown ( )
141
+ await this . db . close ( )
142
+
143
+ for ( const event of STOP_EVENTS ) {
144
+ process . removeListener ( event , this . _cleanup )
145
+ }
146
+
147
+ this . _isClosed = true
134
148
}
135
149
136
- return cleanup
150
+ async start ( ) {
151
+ await this . ready ( )
152
+ this . server = new grpc . Server ( )
137
153
138
- async function cleanup ( ) {
139
- await daemon . close ( )
140
- await new Promise ( ( resolve , reject ) => {
141
- server . tryShutdown ( err => {
142
- if ( err ) return reject ( err )
143
- return resolve ( )
154
+ if ( hyperfuse ) {
155
+ this . server . addService ( rpc . fuse . services . FuseService , {
156
+ ...wrap ( this . metadata , this . fuse . getHandlers ( ) , { authenticate : true } )
144
157
} )
145
- } )
146
- for ( const event of cleanupEvents ) {
147
- process . removeListener ( event , cleanup )
148
158
}
149
- }
159
+ this . server . addService ( rpc . drive . services . DriveService , {
160
+ ...wrap ( this . metadata , this . drives . getHandlers ( ) , { authenticate : true } )
161
+ } )
162
+ this . server . addService ( rpc . main . services . HyperdriveService , {
163
+ ...wrap ( this . metadata , this . createMainHandlers ( ) , { authenticate : true } )
164
+ } )
150
165
151
- function ensureStorage ( ) {
152
- return new Promise ( ( resolve , reject ) => {
153
- mkdirp ( storageRoot , err => {
166
+ await new Promise ( ( resolve , reject ) => {
167
+ this . server . bindAsync ( `0.0.0.0:${ this . port } ` , grpc . ServerCredentials . createInsecure ( ) , ( err , port ) => {
154
168
if ( err ) return reject ( err )
169
+ log . info ( { port : port } , 'server listening' )
170
+ this . server . start ( )
155
171
return resolve ( )
156
172
} )
157
173
} )
174
+
175
+
176
+ async function close ( ) {
177
+ await this . close ( )
178
+ }
158
179
}
159
180
}
160
181
@@ -213,26 +234,10 @@ function wrap (metadata, methods, opts) {
213
234
return wrapped
214
235
}
215
236
216
- function createMainHandlers ( server , daemon ) {
217
- return {
218
- stop : async ( call ) => {
219
- await daemon . close ( )
220
- setTimeout ( ( ) => {
221
- console . error ( 'Daemon is exiting.' )
222
- server . forceShutdown ( )
223
- process . exit ( 0 )
224
- } , 250 )
225
- return new rpc . main . messages . StopResponse ( )
226
- } ,
227
-
228
- status : async ( call ) => {
229
- return new rpc . main . messages . StatusResponse ( )
230
- }
231
- }
232
- }
233
-
234
237
if ( require . main === module ) {
235
- start ( )
238
+ const opts = extractArguments ( )
239
+ const daemon = new HyperdriveDaemon ( opts )
240
+ daemon . start ( )
236
241
} else {
237
- module . exports = start
242
+ module . exports = HyperdriveDaemon
238
243
}
0 commit comments