1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | var _ = require("lodash")
|
8 | , EventEmitter = require("events").EventEmitter
|
9 | , Command = require("./command")
|
10 | , VantageServer = require("./server")
|
11 | , VantageClient = require("./client")
|
12 | , VantageUtil = require("./util")
|
13 | , ui = require("./ui")
|
14 | , Session = require("./session")
|
15 | , intercept = require("./intercept")
|
16 | , commons = require("./vantage-commons")
|
17 | , basicAuth = require("vantage-auth-basic")
|
18 | , os = require("os")
|
19 | , minimist = require("minimist")
|
20 | , npm = require("npm")
|
21 | , repl = require("vantage-repl")
|
22 | , temp = require("temp")
|
23 | , chalk = require("chalk")
|
24 | ; require("native-promise-only")
|
25 | ;
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | function Vantage() {
|
35 |
|
36 | if (!(this instanceof Vantage)) { return new Vantage(); }
|
37 |
|
38 |
|
39 |
|
40 | this._version = "";
|
41 |
|
42 |
|
43 |
|
44 | this.commands = [];
|
45 |
|
46 |
|
47 | this._queue = [];
|
48 |
|
49 |
|
50 | this._command = void 0;
|
51 |
|
52 |
|
53 | this.ui = ui;
|
54 |
|
55 |
|
56 | this._delimiter = "local@" + String(os.hostname()).split(".")[0] + "~$ ";
|
57 | ui.setDelimiter(this._delimiter);
|
58 |
|
59 |
|
60 |
|
61 | this._banner = void 0;
|
62 |
|
63 |
|
64 |
|
65 | this.client = new VantageClient(this);
|
66 |
|
67 |
|
68 |
|
69 | this.server = new VantageServer(this);
|
70 |
|
71 |
|
72 | this._hooked = false;
|
73 |
|
74 |
|
75 | this.util = VantageUtil;
|
76 |
|
77 |
|
78 | this._authFn = void 0;
|
79 |
|
80 |
|
81 | this.session = new Session({
|
82 | local: true,
|
83 | user: "local",
|
84 | parent: this,
|
85 | delimiter: this._delimiter
|
86 | });
|
87 |
|
88 | this._init();
|
89 | return this;
|
90 | }
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | var vantage = Vantage.prototype;
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | Vantage.prototype.__proto__ = EventEmitter.prototype;
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | exports = module.exports = Vantage;
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | Vantage.prototype._init = function() {
|
116 | var self = this;
|
117 |
|
118 | ui.on("vantage_ui_keypress", function(data){
|
119 | self._onKeypress(data.key, data.value);
|
120 | });
|
121 |
|
122 | self
|
123 | .use(commons)
|
124 | .use(repl);
|
125 | };
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | vantage.version = function(version) {
|
136 | this._version = version;
|
137 | return this;
|
138 | };
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 | vantage.delimiter = function(str) {
|
150 | this._delimiter = str;
|
151 | if (this.session.isLocal() && !this.session.client) {
|
152 | this.session.delimiter(str);
|
153 | }
|
154 | return this;
|
155 | };
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | vantage.connect = function(server, port, options, cb) {
|
170 | return this.client.connect.call(this.client, server, port, options, cb);
|
171 | };
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | vantage.use = function(commands, options) {
|
184 | if (!commands) { return this; }
|
185 | if (_.isFunction(commands)) {
|
186 | commands.call(this, this, options);
|
187 | } else if (_.isString(commands)) {
|
188 | return this.use(require(commands), options);
|
189 | } else {
|
190 | commands = _.isArray(commands) ? commands : [commands];
|
191 | for (var i = 0; i < commands.length; ++i) {
|
192 | var cmd = commands[i];
|
193 | if (cmd.command) {
|
194 | var command = this.command(cmd.command);
|
195 | if (cmd.description) {
|
196 | command.description(cmd.description);
|
197 | }
|
198 | if (cmd.options) {
|
199 | cmd.options = _.isArray(cmd.options) ? cmd.options : [cmd.options];
|
200 | for (var j = 0; j < cmd.options.length; ++j) {
|
201 | command.option(cmd.options[j][0], cmd.options[j][1]);
|
202 | }
|
203 | }
|
204 | if (cmd.action) {
|
205 | command.action(cmd.action);
|
206 | }
|
207 | }
|
208 | }
|
209 | }
|
210 | return this;
|
211 | };
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | vantage._use = function(options, callback) {
|
226 |
|
227 | var self = this
|
228 | , config
|
229 | , registeredCommands = 0
|
230 | ;
|
231 |
|
232 | options = (_.isString(options))
|
233 | ? { module: options }
|
234 | : (options || {});
|
235 |
|
236 | options = _.defaults(options, {
|
237 | loglevel: "silent"
|
238 | });
|
239 |
|
240 | config = {
|
241 | loglevel: options.loglevel,
|
242 | production: true
|
243 | };
|
244 |
|
245 | function registryCounter() {
|
246 | registeredCommands++;
|
247 | }
|
248 |
|
249 | function load(cbk) {
|
250 | npm.load(config, function(){
|
251 | npm.registry.log.level = config.loglevel;
|
252 | npm.commands.install(temp.dir, [options.module], function(err, data){
|
253 | if (err) {
|
254 | cbk(err, data);
|
255 | } else {
|
256 | var dir = temp.dir + "/node_modules/" + options.module;
|
257 | var mod = require(dir);
|
258 | cbk(void 0, mod);
|
259 | }
|
260 | });
|
261 | });
|
262 | }
|
263 |
|
264 | load(function(err, mod){
|
265 | if (err) {
|
266 | callback(true, "Error downloading module: " + mod);
|
267 | } else {
|
268 | self.on("command_registered", registryCounter);
|
269 | self.use(mod);
|
270 | self.removeListener("command_registered", registryCounter);
|
271 | var data = {
|
272 | registeredCommands: registeredCommands
|
273 | };
|
274 | callback(void 0, data);
|
275 | }
|
276 | });
|
277 |
|
278 | };
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 | vantage.banner = function(banner) {
|
289 | this._banner = banner || void 0;
|
290 | return this;
|
291 | };
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 | vantage.command = function(name, desc, opts) {
|
304 | opts = opts || {};
|
305 | name = String(name);
|
306 |
|
307 | var argsRegExp = /(\[[^\]]*\]|\<[^\>]*\>)/g;
|
308 | var args = [];
|
309 | var arg;
|
310 |
|
311 | while ((arg = argsRegExp.exec(name)) != null) {
|
312 | args.push(arg[1]);
|
313 | }
|
314 |
|
315 | var cmdNameRegExp = /^([^\[\<]*)/;
|
316 | var cmdName = cmdNameRegExp.exec(name)[0].trim();
|
317 |
|
318 | var cmd = new Command(cmdName, exports);
|
319 |
|
320 | if (desc) {
|
321 | cmd.description(desc);
|
322 | this.executables = true;
|
323 | }
|
324 | cmd._noHelp = !!opts.noHelp;
|
325 | cmd._mode = opts.mode || false;
|
326 | cmd._catch = opts.catch || false;
|
327 | cmd._parseExpectedArgs(args);
|
328 | cmd.parent = this;
|
329 |
|
330 | var exists = false;
|
331 | for (var i = 0; i < this.commands.length; ++i) {
|
332 | exists = (this.commands[i]._name === cmd._name) ? true : exists;
|
333 | if (exists) {
|
334 | this.commands[i] = cmd;
|
335 | break;
|
336 | }
|
337 | }
|
338 | if (!exists) {
|
339 | this.commands.push(cmd);
|
340 | }
|
341 |
|
342 | this.emit("command_registered", { command: cmd, name: name });
|
343 |
|
344 | return cmd;
|
345 | };
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 | vantage.mode = function(name, desc, opts) {
|
358 | return this.command(name, desc, _.extend((opts || {}), { mode: true }));
|
359 | };
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 | vantage.catch = function(name, desc, opts) {
|
373 | return this.command(name, desc, _.extend((opts || {}), { catch: true }));
|
374 | };
|
375 |
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 | vantage.log = function() {
|
386 | this.ui.log.apply(this.ui, arguments);
|
387 | return this;
|
388 | };
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 | vantage.pipe = function(fn) {
|
401 | if (this.ui) {
|
402 | this.ui._pipeFn = fn;
|
403 | }
|
404 | return this;
|
405 | };
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 | vantage.hook = function(fn) {
|
416 | if (fn !== undefined) {
|
417 | this._hook(fn);
|
418 | } else {
|
419 | this._unhook();
|
420 | }
|
421 | return this;
|
422 | };
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 | vantage._unhook = function() {
|
432 | if (this._hooked && this._unhook !== undefined) {
|
433 | this._unhook();
|
434 | this._hooked = false;
|
435 | }
|
436 | return this;
|
437 | };
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 | vantage._hook = function(fn) {
|
448 | if (this._hooked && this._unhook !== undefined) {
|
449 | this._unhook();
|
450 | }
|
451 | this._unhook = intercept(fn);
|
452 | this._hooked = true;
|
453 | return this;
|
454 | };
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 |
|
464 | vantage.show = function() {
|
465 | ui.attach(this);
|
466 | return this;
|
467 | };
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 | vantage.hide = function() {
|
478 | ui.detach(this);
|
479 | return this;
|
480 | };
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 | vantage._onKeypress = function(key, value) {
|
493 | var self = this;
|
494 | if (this.session.isLocal() && !this.session.client) {
|
495 | this.session.getKeypressResult(key, value, function(err, result) {
|
496 | if (result !== undefined) {
|
497 | if (_.isArray(result)) {
|
498 | var formatted = VantageUtil.prettifyArray(result);
|
499 | self.ui.imprint();
|
500 | self.session.log(formatted);
|
501 | } else {
|
502 | self.ui.redraw(result);
|
503 | }
|
504 |
|
505 |
|
506 | }
|
507 | });
|
508 | } else {
|
509 | this._send("vantage-keypress-upstream", "upstream", {
|
510 | key: key,
|
511 | value: value,
|
512 | sessionId: this.session.id
|
513 | });
|
514 | }
|
515 | };
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 |
|
526 |
|
527 |
|
528 |
|
529 | vantage.prompt = function(options, cb) {
|
530 | var self = this;
|
531 | options = options || {};
|
532 | var ssn = self.getSessionById(options.sessionId);
|
533 |
|
534 | if (!ssn) {
|
535 | throw new Error("Vantage.prompt was called without a passed Session ID.");
|
536 | }
|
537 |
|
538 | function handler(data) {
|
539 | var response = data.value;
|
540 | self.removeListener("vantage-prompt-upstream", handler);
|
541 | cb(response);
|
542 | }
|
543 |
|
544 | if (ssn.isLocal()) {
|
545 | ui.setDelimiter(options.message || ssn.delimiter);
|
546 | ui.prompt(options, function(result) {
|
547 | ui.setDelimiter(ssn.delimiter);
|
548 | cb(result);
|
549 | });
|
550 | } else {
|
551 | self.on("vantage-prompt-upstream", handler);
|
552 | self._send("vantage-prompt-downstream", "downstream", { options: options, value: void 0, sessionId: ssn.id });
|
553 | }
|
554 | return self;
|
555 | };
|
556 |
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 | vantage._prompt = function(data) {
|
567 | var self = this;
|
568 | data = data || {};
|
569 | if (!data.sessionId) {
|
570 | data.sessionId = self.session.id;
|
571 | }
|
572 | var ssn = self.getSessionById(data.sessionId);
|
573 |
|
574 |
|
575 |
|
576 | if (!ssn.isLocal()) {
|
577 | this._send("vantage-resume-downstream", "downstream", { sessionId: data.sessionId });
|
578 | return self;
|
579 | }
|
580 |
|
581 | if (ui.midPrompt()) { return self; }
|
582 |
|
583 | ui.prompt({
|
584 | type: "input",
|
585 | name: "command",
|
586 | message: ssn.fullDelimiter()
|
587 | }, function(result){
|
588 | if (self.ui._cancelled === true) { self.ui._cancelled = false; return; }
|
589 | var str = String(result.command).trim();
|
590 | self.emit("client_prompt_submit", str);
|
591 | if (str === "" || str === "undefined") { self._prompt(data); return; }
|
592 | self.exec(str, function(){
|
593 | self._prompt(data);
|
594 | });
|
595 | });
|
596 |
|
597 | return self;
|
598 | };
|
599 |
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 | vantage.exec = function(cmd, args, cb) {
|
630 | var self = this
|
631 | , ssn = self.session
|
632 | ;
|
633 |
|
634 | cb = (_.isFunction(args)) ? args : cb;
|
635 | args = args || {};
|
636 |
|
637 | if (args.sessionId) {
|
638 | ssn = self.getSessionById(args.sessionId);
|
639 | }
|
640 |
|
641 | var command = {
|
642 | command: cmd,
|
643 | args: args,
|
644 | callback: cb,
|
645 | session: ssn
|
646 | };
|
647 |
|
648 | if (cb !== undefined) {
|
649 | self._queue.push(command);
|
650 | self._queueHandler.call(self);
|
651 | return self;
|
652 | } else {
|
653 | return new Promise(function(resolve, reject) {
|
654 | command.resolve = resolve;
|
655 | command.reject = reject;
|
656 | self._queue.push(command);
|
657 | self._queueHandler.call(self);
|
658 | });
|
659 | }
|
660 | };
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 |
|
667 |
|
668 |
|
669 |
|
670 |
|
671 |
|
672 | vantage._queueHandler = function() {
|
673 | if (this._queue.length > 0 && this._command === undefined) {
|
674 | var item = this._queue.shift();
|
675 | this._execQueueItem(item);
|
676 | }
|
677 | };
|
678 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 |
|
687 | vantage._execQueueItem = function(cmd) {
|
688 | var self = this;
|
689 | if (cmd.session.isLocal() && !cmd.session.client) {
|
690 | this._exec(cmd);
|
691 | } else {
|
692 | self._command = cmd;
|
693 | self._send("vantage-command-upstream", "upstream", {
|
694 | command: cmd.command,
|
695 | args: cmd.args,
|
696 | completed: false,
|
697 | sessionId: cmd.session.id
|
698 | });
|
699 | }
|
700 | };
|
701 |
|
702 |
|
703 |
|
704 |
|
705 |
|
706 |
|
707 |
|
708 |
|
709 |
|
710 | vantage._exec = function(item) {
|
711 |
|
712 | var self = this
|
713 | , parts
|
714 | , match = false
|
715 | , modeCommand
|
716 | , args = {}
|
717 | ;
|
718 |
|
719 | function parseArgsByType(arg, cmdArg) {
|
720 | if (arg && cmdArg.variadic === true) {
|
721 | args[cmdArg.name] = remainingArgs;
|
722 | } else if (arg) {
|
723 | args[cmdArg.name] = arg;
|
724 | remainingArgs.shift();
|
725 | }
|
726 | }
|
727 |
|
728 | function validateArg(arg, cmdArg) {
|
729 | if (!arg && cmdArg.required === true) {
|
730 | item.session.log(" ");
|
731 | item.session.log(" Missing required argument. Showing Help:");
|
732 | item.session.log(match.helpInformation());
|
733 | item.callback();
|
734 | return false;
|
735 | } else {
|
736 | return true;
|
737 | }
|
738 | }
|
739 |
|
740 | item = item || {};
|
741 |
|
742 | if (!item.session) {
|
743 | throw new Error("Fatal Error: No session was passed into command for execution: " + item);
|
744 | }
|
745 |
|
746 | if (String(item.command).indexOf("undefine") > -1) {
|
747 | console.trace("Undefined ._exec command passed.");
|
748 | throw new Error("vantage._exec was called with an undefined command.");
|
749 | }
|
750 |
|
751 | item.command = item.command || "";
|
752 | modeCommand = item.command;
|
753 | item.command = (item.session._mode) ? item.session._mode : item.command;
|
754 | parts = item.command.split(" ");
|
755 |
|
756 |
|
757 | item.session.history((item.session._mode ? modeCommand : item.command));
|
758 |
|
759 |
|
760 |
|
761 | for (var i = 0; i < parts.length; ++i) {
|
762 | var subcommand = String(parts.slice(0, parts.length - i).join(" ")).trim().toLowerCase();
|
763 | match = _.findWhere(this.commands, { _name: subcommand }) || match;
|
764 | if (!match) {
|
765 | for (var j = 0; j < this.commands.length; ++j) {
|
766 | var idx = this.commands[j]._aliases.indexOf(subcommand);
|
767 | match = (idx > -1) ? this.commands[j] : match;
|
768 | }
|
769 | }
|
770 | if (match) {
|
771 | args = parts.slice(parts.length - i, parts.length).join(" ");
|
772 | break;
|
773 | }
|
774 | }
|
775 |
|
776 | if (!match) {
|
777 | match = _.findWhere(this.commands, { _catch: true });
|
778 | args = item.command;
|
779 | }
|
780 |
|
781 |
|
782 | if (match) {
|
783 |
|
784 | var fn = match._fn
|
785 | , afterFn = match._after
|
786 | , init = match._init || function(arrgs, cb) { cb(); }
|
787 | , delimiter = match._delimiter || String(item.command).toLowerCase() + ":"
|
788 | , origArgs = match._args
|
789 | , origOptions = match.options
|
790 | , variadic = _.findWhere(origArgs, { variadic: true })
|
791 | ;
|
792 |
|
793 | var parsedBasic = VantageUtil.parseArgs(args);
|
794 |
|
795 |
|
796 | var parsedArgs = minimist(parsedBasic);
|
797 |
|
798 | parsedArgs._ = parsedArgs._ || [];
|
799 | args = {};
|
800 | args.options = {};
|
801 |
|
802 |
|
803 | if (parsedArgs.help || parsedArgs._.indexOf("/?") > -1) {
|
804 | item.session.log(match.helpInformation());
|
805 | item.callback(); return;
|
806 | }
|
807 |
|
808 | var remainingArgs = _.clone(parsedArgs._);
|
809 |
|
810 | var supportedArgs = 10;
|
811 | var valid = true;
|
812 | for (var i = 0; i < supportedArgs; ++i) {
|
813 | if (origArgs[i]) {
|
814 | valid = (!valid) ? false : validateArg(parsedArgs._[i], origArgs[i]);
|
815 | if (!valid) { break; }
|
816 | parseArgsByType(parsedArgs._[i], origArgs[i]);
|
817 | }
|
818 | }
|
819 |
|
820 | if (!valid) {
|
821 | return;
|
822 | }
|
823 |
|
824 |
|
825 |
|
826 | for (var k = 0; k < origOptions.length; ++k) {
|
827 | var o = origOptions[k];
|
828 | var short = String(o.short || "").replace(/-/g, "");
|
829 | var long = String(o.long || "").replace(/--no-/g, "").replace(/-/g, "");
|
830 | var exist = parsedArgs[short] || parsedArgs[long];
|
831 | if (exist === true && o.required !== 0) {
|
832 | item.session.log(" ");
|
833 | item.session.log(" Missing required option. Showing Help:");
|
834 | item.session.log(match.helpInformation());
|
835 | item.callback("Missing required option.");
|
836 | return;
|
837 | }
|
838 | if (exist !== undefined) {
|
839 | args.options[long || short] = exist;
|
840 | }
|
841 | }
|
842 |
|
843 |
|
844 |
|
845 | if (match._mode === true && !item.session._mode) {
|
846 |
|
847 | item.session._mode = item.command;
|
848 |
|
849 |
|
850 | fn = init;
|
851 |
|
852 |
|
853 |
|
854 | self._histCache = _.clone(self._hist);
|
855 | self._histCtrCache = parseFloat(self._histCtr);
|
856 | self._hist = [];
|
857 | self._histCtr = 0;
|
858 |
|
859 | item.session.modeDelimiter(delimiter);
|
860 |
|
861 | } else if (item.session._mode) {
|
862 | if (String(modeCommand).trim() === "exit") {
|
863 | self._exitMode({ sessionId: item.session.id });
|
864 | if (item.callback) {
|
865 | item.callback.call(self);
|
866 | } else if (item.resolve !== undefined) {
|
867 | item.resolve();
|
868 | }
|
869 | return;
|
870 | }
|
871 |
|
872 |
|
873 |
|
874 |
|
875 |
|
876 | args = modeCommand;
|
877 | }
|
878 |
|
879 |
|
880 |
|
881 |
|
882 | if (item.args && _.isObject(item.args)) {
|
883 | args = _.extend(args, item.args);
|
884 | }
|
885 |
|
886 |
|
887 |
|
888 |
|
889 |
|
890 |
|
891 |
|
892 |
|
893 |
|
894 |
|
895 |
|
896 |
|
897 |
|
898 |
|
899 |
|
900 |
|
901 |
|
902 |
|
903 |
|
904 |
|
905 |
|
906 |
|
907 | var res = fn.call(item.session, args, function() {
|
908 | self.emit("client_command_executed", { command: item.command });
|
909 | var fixedArgs = VantageUtil.fixArgsForApply(arguments);
|
910 |
|
911 | var error = fixedArgs[0];
|
912 | if (item.callback) {
|
913 | item.callback.apply(self, fixedArgs);
|
914 | if (afterFn) { afterFn.call(item.session, args); }
|
915 | } else {
|
916 | if (error !== undefined && item.reject !== undefined) {
|
917 | item.reject.apply(self, fixedArgs);
|
918 | if (afterFn) { afterFn.call(item.session, args); }
|
919 | return;
|
920 | } else if (item.resolve !== undefined) {
|
921 | item.resolve.apply(self, fixedArgs);
|
922 | if (afterFn) { afterFn.call(item.session, args); }
|
923 | return;
|
924 | }
|
925 | }
|
926 | });
|
927 |
|
928 |
|
929 |
|
930 | if (res && _.isFunction(res.then)) {
|
931 | res.then(function(data) {
|
932 | if (item.session.isLocal()) {
|
933 | self.emit("client_command_executed", { command: item.command });
|
934 | }
|
935 | if (item.callback !== undefined) {
|
936 | item.callback(void 0, data);
|
937 | if (afterFn) { afterFn.call(item.session, args); }
|
938 | } else if (item.resolve !== undefined) {
|
939 | item.resolve(data);
|
940 | if (afterFn) { afterFn.call(item.session, args); }
|
941 | return;
|
942 | }
|
943 | }).catch(function(err) {
|
944 | item.session.log(chalk.red("Error: ") + err);
|
945 | if (item.session.isLocal()) {
|
946 | self.emit("client_command_error", { command: item.command, error: err });
|
947 | }
|
948 | if (item.callback !== undefined) {
|
949 | item.callback(true, err);
|
950 | if (afterFn) { afterFn.call(item.session, args); }
|
951 | } else if (item.reject !== undefined) {
|
952 | item.reject(err);
|
953 | if (afterFn) { afterFn.call(item.session, args); }
|
954 | }
|
955 | });
|
956 | }
|
957 | } else {
|
958 |
|
959 | item.session.log(this._commandHelp(item.command));
|
960 |
|
961 |
|
962 |
|
963 | item.callback();
|
964 | }
|
965 | };
|
966 |
|
967 |
|
968 |
|
969 |
|
970 |
|
971 |
|
972 |
|
973 |
|
974 |
|
975 |
|
976 |
|
977 |
|
978 |
|
979 | vantage.auth = function(middleware, options) {
|
980 | middleware = (middleware === "basic") ? basicAuth
|
981 | : middleware
|
982 | ;
|
983 |
|
984 | if (!middleware) {
|
985 | this._authFn = void 0;
|
986 | } else if (!_.isFunction(middleware)) {
|
987 | this._authFn = void 0;
|
988 | throw new Error("Invalid middleware string passed into Vantage.auth: " + middleware);
|
989 | } else {
|
990 | var fn = middleware.call(this, this, options);
|
991 | this._authFn = fn;
|
992 | }
|
993 | return this;
|
994 | };
|
995 |
|
996 |
|
997 |
|
998 |
|
999 |
|
1000 |
|
1001 |
|
1002 |
|
1003 |
|
1004 | vantage._authenticate = function(args, cb) {
|
1005 | var ssn = this.getSessionById(args.sessionId);
|
1006 | if (!this._authFn) {
|
1007 | var nodeEnv = process.env.NODE_ENV || "development";
|
1008 | if (nodeEnv !== "development") {
|
1009 | var msg = "The Node server you are connecting to appears "
|
1010 | + "to be a production server, and yet its Vantage.js "
|
1011 | + "instance does not support any means of authentication. \n"
|
1012 | + "To connect to this server without authentication, "
|
1013 | + "ensure its 'NODE_ENV' environmental variable is set "
|
1014 | + "to 'development' (it is currently '" + nodeEnv + "').";
|
1015 | ssn.log(chalk.yellow(msg));
|
1016 | ssn.authenticating = false;
|
1017 | ssn.authenticated = false;
|
1018 | cb(msg, false);
|
1019 | } else {
|
1020 | ssn.authenticating = false;
|
1021 | ssn.authenticated = true;
|
1022 | cb(void 0, true);
|
1023 | }
|
1024 | } else {
|
1025 | this._authFn.call(ssn, args, function(message, authenticated) {
|
1026 | ssn.authenticating = false;
|
1027 | ssn.authenticated = authenticated;
|
1028 | if (authenticated === true) {
|
1029 | cb(void 0, true);
|
1030 | } else {
|
1031 | cb(message);
|
1032 | }
|
1033 | });
|
1034 | }
|
1035 | };
|
1036 |
|
1037 |
|
1038 |
|
1039 |
|
1040 |
|
1041 |
|
1042 |
|
1043 |
|
1044 |
|
1045 | vantage._exitMode = function(options) {
|
1046 | var ssn = this.getSessionById(options.sessionId);
|
1047 | ssn._mode = false;
|
1048 | this._hist = this._histCache;
|
1049 | this._histCtr = this._histCtrCache;
|
1050 | this._histCache = [];
|
1051 | this._histCtrCache = 0;
|
1052 | ssn.modeDelimiter(false);
|
1053 | };
|
1054 |
|
1055 |
|
1056 |
|
1057 |
|
1058 |
|
1059 |
|
1060 |
|
1061 |
|
1062 |
|
1063 |
|
1064 | vantage.removeCommand = function(name) {
|
1065 | this.commands = _.reject(this.commands, function(command){
|
1066 | if (command._name === name) {
|
1067 | return true;
|
1068 | }
|
1069 | })
|
1070 | return this;
|
1071 | };
|
1072 |
|
1073 |
|
1074 |
|
1075 |
|
1076 |
|
1077 |
|
1078 |
|
1079 |
|
1080 |
|
1081 | vantage.hideCommand = function(name) {
|
1082 | this.commands = _.map(this.commands, function(command){
|
1083 | if (command._name === name) {
|
1084 | command._hidden = true;
|
1085 | }
|
1086 | return command;
|
1087 | })
|
1088 | return this;
|
1089 | };
|
1090 |
|
1091 |
|
1092 |
|
1093 |
|
1094 |
|
1095 |
|
1096 |
|
1097 |
|
1098 | vantage._commandHelp = function(command) {
|
1099 | if (!this.commands.length) { return ""; }
|
1100 |
|
1101 | var matches = [];
|
1102 | var singleMatches = [];
|
1103 |
|
1104 | command = (command) ? String(command).trim().toLowerCase() : void 0;
|
1105 | for (var i = 0; i < this.commands.length; ++i) {
|
1106 | var parts = String(this.commands[i]._name).split(" ");
|
1107 | if (parts.length === 1 && parts[0] === command && !this.commands[i]._hidden && !this.commands[i]._catch) { singleMatches.push(command); }
|
1108 | var str = "";
|
1109 | for (var j = 0; j < parts.length; ++j) {
|
1110 | str = String(str + " " + parts[j]).trim();
|
1111 | if (str === command && !this.commands[i]._hidden && !this.commands[i]._catch) {
|
1112 | matches.push(this.commands[i]);
|
1113 | break;
|
1114 | }
|
1115 | }
|
1116 | }
|
1117 |
|
1118 | var invalidString =
|
1119 | (command && matches.length === 0 && singleMatches.length === 0)
|
1120 | ? ["", " Invalid Command. Showing Help:", ""].join("\n")
|
1121 | : "";
|
1122 |
|
1123 | var commandMatch = (matches.length > 0) ? true : false;
|
1124 | var commandMatchLength = (commandMatch) ? String(command).trim().split(" ").length + 1 : 1;
|
1125 | matches = (matches.length === 0) ? this.commands : matches;
|
1126 |
|
1127 | var commands = matches.filter(function(cmd) {
|
1128 | return !cmd._noHelp;
|
1129 | }).filter(function(cmd){
|
1130 | return !cmd._catch;
|
1131 | }).filter(function(cmd){
|
1132 | return !cmd._hidden;
|
1133 | }).filter(function(cmd){
|
1134 | return (String(cmd._name).trim().split(" ").length <= commandMatchLength);
|
1135 | }).map(function(cmd) {
|
1136 | var args = cmd._args.map(function(arg) {
|
1137 | return VantageUtil.humanReadableArgName(arg);
|
1138 | }).join(" ");
|
1139 |
|
1140 | return [
|
1141 | cmd._name
|
1142 | + (cmd._alias
|
1143 | ? "|" + cmd._alias
|
1144 | : "")
|
1145 | + (cmd.options.length
|
1146 | ? " [options]"
|
1147 | : "")
|
1148 | + " " + args
|
1149 | , cmd.description()
|
1150 | ];
|
1151 | });
|
1152 |
|
1153 | var width = commands.reduce(function(max, commandX) {
|
1154 | return Math.max(max, commandX[0].length);
|
1155 | }, 0);
|
1156 |
|
1157 | var counts = {};
|
1158 |
|
1159 | var groups = _.uniq(matches.filter(function(cmd) {
|
1160 | return (String(cmd._name).trim().split(" ").length > commandMatchLength);
|
1161 | }).map(function(cmd){
|
1162 | return String(cmd._name).split(" ").slice(0, commandMatchLength).join(" ");
|
1163 | }).map(function(cmd){
|
1164 | counts[cmd] = counts[cmd] || 0;
|
1165 | counts[cmd]++;
|
1166 | return cmd;
|
1167 | })).map(function(cmd){
|
1168 | return " " + VantageUtil.pad(cmd + " *", width) + " " + counts[cmd] + " sub-command" + ((counts[cmd] === 1) ? "" : "s") + ".";
|
1169 | });
|
1170 |
|
1171 | var results = [
|
1172 | invalidString + "\n Commands:"
|
1173 | , ""
|
1174 | , commands.map(function(cmd) {
|
1175 | return VantageUtil.pad(cmd[0], width) + " " + cmd[1];
|
1176 | }).join("\n").replace(/^/gm, " ")
|
1177 | , (groups.length < 1
|
1178 | ? ""
|
1179 | : "\n Command Groups:\n\n" + groups.join("\n") + "\n")
|
1180 | ].join("\n");
|
1181 |
|
1182 | return results;
|
1183 | };
|
1184 |
|
1185 |
|
1186 |
|
1187 |
|
1188 |
|
1189 |
|
1190 |
|
1191 |
|
1192 |
|
1193 |
|
1194 |
|
1195 |
|
1196 |
|
1197 |
|
1198 |
|
1199 | vantage._send = function(str, direction, data, options) {
|
1200 | options = options || {};
|
1201 | data = data || {};
|
1202 | var ssn = this.getSessionById(data.sessionId);
|
1203 | if (!ssn) {
|
1204 | throw new Error("No Sessions logged for ID " + data.sessionId + " in vantage._send.");
|
1205 | }
|
1206 | if (direction === "upstream") {
|
1207 | if (ssn.client) {
|
1208 | ssn.client.emit(str, data);
|
1209 | }
|
1210 | } else if (direction === "downstream") {
|
1211 | if (ssn.server) {
|
1212 | ssn.server.emit(str, data);
|
1213 | }
|
1214 | }
|
1215 | };
|
1216 |
|
1217 |
|
1218 |
|
1219 |
|
1220 |
|
1221 |
|
1222 |
|
1223 |
|
1224 |
|
1225 |
|
1226 |
|
1227 |
|
1228 |
|
1229 |
|
1230 |
|
1231 |
|
1232 |
|
1233 | vantage._proxy = function(str, direction, data, options) {
|
1234 | var self = this;
|
1235 | return new Promise(function(resolve){
|
1236 | var ssn = self.getSessionById(data.sessionId);
|
1237 | if (ssn && (!ssn.isLocal() && ssn.client)) {
|
1238 | self._send(str, direction, data, options);
|
1239 | } else {
|
1240 | resolve();
|
1241 | }
|
1242 | });
|
1243 | };
|
1244 |
|
1245 |
|
1246 |
|
1247 |
|
1248 |
|
1249 |
|
1250 |
|
1251 |
|
1252 |
|
1253 |
|
1254 | vantage.listen = function(app, options, cb) {
|
1255 | this.server.init(app, options, cb);
|
1256 | return this;
|
1257 | };
|
1258 |
|
1259 |
|
1260 |
|
1261 |
|
1262 |
|
1263 |
|
1264 |
|
1265 |
|
1266 |
|
1267 | vantage.getSessionById = function(id) {
|
1268 | if (_.isObject(id)) {
|
1269 | throw new Error("vantage.getSessionById: id " + JSON.stringify(id) + " should not be an object.");
|
1270 | }
|
1271 | var ssn = _.findWhere(this.server.sessions, { id: id });
|
1272 | ssn = (this.session.id === id) ? this.session : ssn;
|
1273 | if (!id) {
|
1274 | throw new Error("vantage.getSessionById was called with no ID passed.");
|
1275 | }
|
1276 | if (!ssn) {
|
1277 | var sessions = {
|
1278 | local: this.session.id,
|
1279 | server: _.pluck(this.server.sessions, "id")
|
1280 | };
|
1281 | throw new Error("No session found for id " + id + " in vantage.getSessionById. Sessions: " + JSON.stringify(sessions));
|
1282 | }
|
1283 | return ssn;
|
1284 | };
|
1285 |
|
1286 |
|
1287 |
|
1288 |
|
1289 |
|
1290 |
|
1291 |
|
1292 |
|
1293 |
|
1294 |
|
1295 |
|
1296 | vantage.exit = function(options) {
|
1297 | var self = this;
|
1298 | var ssn = this.getSessionById(options.sessionId);
|
1299 | if (ssn.isLocal()) {
|
1300 | if (options.force) {
|
1301 | process.exit(1);
|
1302 | } else {
|
1303 | this.prompt({
|
1304 | type: "confirm",
|
1305 | name: "continue",
|
1306 | default: false,
|
1307 | message: "This will actually kill this node process. Continue?",
|
1308 | sessionId: ssn.id
|
1309 | }, function(result){
|
1310 | if (result.continue) {
|
1311 | process.exit(1);
|
1312 | } else {
|
1313 | self._prompt({ sessionId: ssn.id });
|
1314 | }
|
1315 | });
|
1316 | }
|
1317 | } else {
|
1318 | ssn.server.emit("vantage-close-downstream", { sessionId: ssn.id });
|
1319 | }
|
1320 | };
|