UNPKG

5.11 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3// Copyright 2016 Luca-SAS, licensed under the Apache License 2.0
4
5const help=`Usage: skale [options] <command> [<args>]
6
7Create, run, deploy clustered node applications
8
9Commands:
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
16Options:
17 -h, --help Show help
18 -V, --version Show version
19`;
20
21const child_process = require('child_process');
22const fs = require('fs');
23const net = require('net');
24
25const 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
30var skale_port = 12346;
31
32if (argv.h || argv.help) {
33 console.log(help);
34 process.exit();
35}
36if (argv.V || argv.version) {
37 var pkg = require('./package');
38 console.log(pkg.name + '-' + pkg.version);
39 process.exit();
40}
41
42//const config = load(argv);
43const proto = config.ssl ? require('https') : require('http');
44
45switch (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
65function 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
85var sc = require('skale-engine').context();
86
87sc.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.
96Pleas change directory to ${name}: "cd ${name}"
97To run your app: "skale run"
98To modify your app: edit ${name}.js`)
99}
100
101function die(err) {
102 console.error(help);
103 console.error(err);
104 process.exit(1);
105}
106
107function 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
119function 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
130function 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
142function 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
149function 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
157function 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
168function 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}