1 | #!/usr/bin/env node
|
2 |
|
3 |
|
4 |
|
5 | const help=`Usage: skale [options] <command> [<args>]
|
6 |
|
7 | Create, run, deploy clustered node applications
|
8 |
|
9 | Commands:
|
10 | create <app> Create a new application
|
11 | run [<args>...] Run application
|
12 | deploy [<args>...] Deploy application (coming soon)
|
13 | status print status of local skale cluster
|
14 | stop Stop local skale cluster
|
15 |
|
16 | Options:
|
17 | -h, --help Show help
|
18 | -V, --version Show version
|
19 | `;
|
20 |
|
21 | const child_process = require('child_process');
|
22 | const fs = require('fs');
|
23 | const net = require('net');
|
24 |
|
25 | const argv = require('minimist')(process.argv.slice(2), {
|
26 | string: ['c', 'config', 'H', 'host', 'p', 'port', 'k', 'key'],
|
27 | boolean: ['h', 'help', 'V', 'version', 's', 'ssl'],
|
28 | });
|
29 |
|
30 | var skale_port = 12346;
|
31 |
|
32 | if (argv.h || argv.help) {
|
33 | console.log(help);
|
34 | process.exit();
|
35 | }
|
36 | if (argv.V || argv.version) {
|
37 | var pkg = require('./package');
|
38 | console.log(pkg.name + '-' + pkg.version);
|
39 | process.exit();
|
40 | }
|
41 |
|
42 |
|
43 | const proto = config.ssl ? require('https') : require('http');
|
44 |
|
45 | switch (argv._[0]) {
|
46 | case 'create':
|
47 | create(argv._[1]);
|
48 | break;
|
49 | case 'deploy':
|
50 | console.log('this command is not yet implemented. Coming soon.');
|
51 | break;
|
52 | case 'run':
|
53 | run_local(argv._.splice(1));
|
54 | break;
|
55 | case 'status':
|
56 | status_local();
|
57 | break;
|
58 | case 'stop':
|
59 | stop_local_server();
|
60 | break;
|
61 | default:
|
62 | die('Error: invalid command: ' + argv._[0]);
|
63 | }
|
64 |
|
65 | function create(name) {
|
66 | console.log('create application ' + name);
|
67 | try {
|
68 | fs.mkdirSync(name);
|
69 | } catch (error) {
|
70 | die('skale create error: ' + error.message);
|
71 | }
|
72 | process.chdir(name);
|
73 | const pkg = {
|
74 | name: name,
|
75 | version: '0.0.0',
|
76 | private: true,
|
77 | keywords: [ 'skale' ],
|
78 | dependencies: {
|
79 | 'skale-engine': '^0.3.2'
|
80 | }
|
81 | };
|
82 | fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
|
83 | var src = `#!/usr/bin/env node
|
84 |
|
85 | var sc = require('skale-engine').context();
|
86 |
|
87 | sc.parallelize(['Hello world'])
|
88 | .collect()
|
89 | .on('data', console.log)
|
90 | .on('end', sc.end);
|
91 | `;
|
92 | fs.writeFileSync(name + '.js', src);
|
93 | const npm = child_process.spawnSync('npm', ['install'], {stdio: 'inherit'});
|
94 | if (npm.status) die('skale create error: npm install failed');
|
95 | console.log(`Project ${name} is now ready.
|
96 | Pleas change directory to ${name}: "cd ${name}"
|
97 | To run your app: "skale run"
|
98 | To modify your app: edit ${name}.js`)
|
99 | }
|
100 |
|
101 | function die(err) {
|
102 | console.error(help);
|
103 | console.error(err);
|
104 | process.exit(1);
|
105 | }
|
106 |
|
107 | function load(argv) {
|
108 | var conf = {}, save = false;
|
109 | var path = argv.c || argv.config || process.env.SKALE_CONFIG || process.env.HOME + '/.skalerc';
|
110 | try { conf = JSON.parse(fs.readFileSync(path)); } catch (error) { save = true; }
|
111 | conf.host = argv.H || argv.host || process.env.SKALE_HOST || conf.host || die('Error: missing host');
|
112 | conf.port = argv.p || argv.port || process.env.SKALE_PORT || conf.port || die('Error: missing port');
|
113 | conf.key = argv.k || argv.key || conf.key;
|
114 | conf.ssl = argv.s || argv.ssl || (conf.ssl ? true : false);
|
115 | if (save || argv._[0] == 'init') fs.writeFileSync(path, JSON.stringify(conf, null, 2));
|
116 | return conf;
|
117 | }
|
118 |
|
119 | function start_skale(done) {
|
120 | const out = fs.openSync('skale-server.log', 'a');
|
121 | const err = fs.openSync('skale-server.log', 'a');
|
122 | const child = child_process.spawn('node_modules/skale-engine/bin/server.js', ['-l', '2'], {
|
123 | detached: true,
|
124 | stdio: ['ignore', out, err]
|
125 | });
|
126 | child.unref();
|
127 | try_connect(5, 1000, done);
|
128 | }
|
129 |
|
130 | function try_connect(nb_try, timeout, done) {
|
131 | const sock = net.connect(skale_port);
|
132 | sock.on('connect', function () {
|
133 | sock.end();
|
134 | done(null);
|
135 | });
|
136 | sock.on('error', function (err) {
|
137 | if (--nb_try <= 0) return done('skale-server not ok');
|
138 | setTimeout(function () { try_connect(nb_try, timeout, done); }, timeout);
|
139 | });
|
140 | }
|
141 |
|
142 | function stop_local_server() {
|
143 | const child = child_process.execFile('/usr/bin/pgrep', ['skale-server'], function (err, pid) {
|
144 | if (! pid) return;
|
145 | process.kill(pid.trim());
|
146 | });
|
147 | }
|
148 |
|
149 | function status_local() {
|
150 | const child = child_process.execFile('/bin/ps', ['ux'], function (err, out) {
|
151 | var lines = out.split(/\r\n|\r|\n/);
|
152 | for (var i = 0; i < lines.length; i++)
|
153 | if (i == 0 || lines[i].match(/ skale-/)) console.log(lines[i]);
|
154 | });
|
155 | }
|
156 |
|
157 | function run_local(args) {
|
158 | const pkg = JSON.parse(fs.readFileSync('package.json'));
|
159 | var cmd = pkg.name + '.js';
|
160 | args.splice(0, 0, cmd);
|
161 | try_connect(0, 0, function (err) {
|
162 | if (!err) return run_app();
|
163 | start_skale(run_app);
|
164 | });
|
165 | function run_app() { child = child_process.spawn('node', args, {stdio: 'inherit'}); }
|
166 | }
|
167 |
|
168 | function run_remote(src, args) {
|
169 | fs.readFile(src, {encoding: 'utf8'}, function (err, data) {
|
170 | if (err) throw err;
|
171 |
|
172 | var postdata = JSON.stringify({src: data, args: args});
|
173 |
|
174 | var options = {
|
175 | hostname: config.host,
|
176 | port: config.port,
|
177 | path: '/run',
|
178 | method: 'POST',
|
179 | headers: {
|
180 | 'X-Auth': config.key,
|
181 | 'Content-Type': 'application/json',
|
182 | 'Content-Length': Buffer.byteLength(postdata)
|
183 | }
|
184 | };
|
185 |
|
186 | var req = proto.request(options, function (res) {
|
187 | res.setEncoding('utf8');
|
188 | res.pipe(process.stdout);
|
189 | });
|
190 |
|
191 | req.on('error', function (err) {throw err;});
|
192 | req.end(postdata);
|
193 | });
|
194 | }
|