@@ -3,9 +3,13 @@ const p = require('path')
3
3
const os = require ( 'os' )
4
4
const fs = require ( 'fs' ) . promises
5
5
const repl = require ( 'repl' )
6
- const { Server , Client } = require ( './ ' )
6
+ const { spawn } = require ( 'child_process ' )
7
7
const minimist = require ( 'minimist' )
8
+ const ram = require ( 'random-access-memory' )
9
+
10
+ const { Server, Client } = require ( './' )
8
11
const { migrate : migrateFromDaemon , isMigrated } = require ( '@hyperspace/migration-tool' )
12
+ const getNetworkOptions = require ( '@hyperspace/rpc/socket' )
9
13
10
14
// TODO: Default paths are duplicated here because we need to do the async migration check.
11
15
const HYPERSPACE_STORAGE_DIR = p . join ( os . homedir ( ) , '.hyperspace' , 'storage' )
@@ -30,16 +34,19 @@ const version = `hyperspace/${require('./package.json').version} ${process.platf
30
34
const help = `Hypercore, batteries included.
31
35
${ version }
32
36
33
- Usage: hyperspace [options]
34
-
35
- --host, -h Set unix socket name
36
- --port -p Set the port (will use TCP)
37
- --storage, -s Overwrite storage folder
38
- --bootstrap, -b Overwrite DHT bootstrap servers
39
- --memory-only Run all storage in memory
40
- --no-announce Disable all network annoucnes
41
- --repl Run a debug repl
42
- --no-migrate Disable the Hyperdrive Daemon migration
37
+ Usage: hyperspace [command] [options]
38
+ Commands:
39
+ simulator <script.js> Run script.js using an in-memory Hyperspace instance
40
+
41
+ Flags:
42
+ --host, -h Set unix socket name
43
+ --port -p Set the port (will use TCP)
44
+ --storage, -s Overwrite storage folder
45
+ --bootstrap, -b Overwrite DHT bootstrap servers
46
+ --memory-only Run all storage in memory
47
+ --no-announce Disable all network annoucnes
48
+ --repl Run a debug repl
49
+ --no-migrate Disable the Hyperdrive Daemon migration
43
50
`
44
51
45
52
if ( argv . help ) {
@@ -50,6 +57,10 @@ if (argv.help) {
50
57
main ( ) . catch ( onerror )
51
58
52
59
async function main ( ) {
60
+ if ( argv . _ [ 0 ] === 'simulator' ) {
61
+ return simulator ( )
62
+ }
63
+
53
64
console . log ( 'Running ' + version )
54
65
55
66
// Note: This will be removed in future releases of Hyperspace.
@@ -68,15 +79,7 @@ async function main () {
68
79
// Else, use ~/.hyperspace/storage
69
80
const storage = argv . storage ? argv . storage : await getStoragePath ( )
70
81
71
- const s = new Server ( {
72
- host : argv . host ,
73
- port : argv . port ,
74
- storage,
75
- network : argv . bootstrap ? { bootstrap : [ ] . concat ( argv . bootstrap ) } : null ,
76
- memoryOnly : argv [ 'memory-only' ] ,
77
- noAnnounce : ! argv . announce ,
78
- noMigrate : ! argv . migrate
79
- } )
82
+ const s = createServer ( storage , argv )
80
83
global . hyperspace = s
81
84
82
85
if ( ! argv . repl ) {
@@ -133,6 +136,58 @@ async function main () {
133
136
}
134
137
}
135
138
139
+ function createServer ( storage , opts ) {
140
+ return new Server ( {
141
+ host : opts . host ,
142
+ port : opts . port ,
143
+ storage,
144
+ network : opts . bootstrap ? { bootstrap : [ ] . concat ( opts . bootstrap ) } : null ,
145
+ noAnnounce : ! opts . announce ,
146
+ noMigrate : ! opts . migrate
147
+ } )
148
+ }
149
+
150
+ async function simulator ( ) {
151
+ if ( argv . _ . length === 1 ) throw new Error ( 'Must provide a script for the simulator to run.' )
152
+ const scriptPath = p . resolve ( argv . _ [ 1 ] )
153
+ const simulatorId = await getUnusedSocket ( )
154
+ process . env [ 'HYPERSPACE_HOST' ] = simulatorId
155
+
156
+ const server = createServer ( ram , {
157
+ ...argv ,
158
+ host : simulatorId
159
+ } )
160
+ await server . open ( )
161
+
162
+ process . once ( 'SIGINT' , close )
163
+ process . once ( 'SIGTERM' , close )
164
+
165
+ const child = spawn ( process . execPath , [ scriptPath ] , {
166
+ env : {
167
+ 'HYPERSPACE_HOST' : simulatorId
168
+ } ,
169
+ stdio : 'inherit'
170
+ } )
171
+ child . on ( 'close' , close )
172
+
173
+ async function close ( ) {
174
+ console . log ( 'Shutting down simulator...' )
175
+ server . close ( ) . catch ( onerror )
176
+ }
177
+
178
+ async function getUnusedSocket ( ) {
179
+ const host = `hyperspace-simulator-${ ( Math . floor ( Math . random ( ) * 1e9 ) ) . toString ( 16 ) } `
180
+ const socketPath = getNetworkOptions ( { host } )
181
+ try {
182
+ await fs . stat ( socketPath )
183
+ return getUnusedSocket ( )
184
+ } catch ( err ) {
185
+ if ( err . code !== 'ENOENT' ) throw err
186
+ return host
187
+ }
188
+ }
189
+ }
190
+
136
191
async function getStoragePath ( ) {
137
192
try {
138
193
// If this dir exists, use it.
0 commit comments