UNPKG

12.2 kBJavaScriptView Raw
1"use strict";
2
3/**
4 * Module dependencies.
5 */
6
7var _ = require("lodash")
8 , util = require("util")
9 , VantageUtil = require("./util")
10 , chalk = require("chalk")
11 ; require("native-promise-only")
12 ;
13
14/**
15 * Initialize a new `VantageClient` instance.
16 *
17 * @param {Vantage} parent
18 * @return {VantageClient}
19 * @api public
20 */
21
22function VantageClient(parent) {
23 this.parent = parent;
24 // Sessions are created when you use
25 // vantage as a client to connect to
26 // other instances of vantage.
27 this.sessions = [];
28
29 return this;
30}
31
32/**
33 * VantageClient prototype.
34 */
35
36var vantageClient = VantageClient.prototype;
37
38/**
39 * Expose `VantageClient`.
40 */
41
42exports = module.exports = VantageClient;
43
44/**
45 * Connects to another listening vantage server.
46 *
47 * @param {String} server
48 * @param {Integer} port
49 * @param {Object} options
50 * @param {Function} cb
51 * @return {Promise}
52 * @api public
53 */
54
55vantageClient.connect = function(server, port, options, cb) {
56 var self = this;
57
58 return new Promise(function(resolve, reject) {
59
60 // Callback can be passed in the options parameter, if
61 // no options are needed.
62 cb = (_.isFunction(options)) ? options : (cb || function(){});
63 options = (_.isFunction(options)) ? {} : options;
64 options = _.defaults(options, {
65 ssl: false,
66 user: void 0,
67 pass: void 0,
68 pipe: false,
69 sessionId: self.parent.session.id
70 });
71
72 var method = (options.ssl) ? "https" : "http";
73
74 var ssn = self.parent.getSessionById(options.sessionId);
75
76 ssn.log("Connecting to " + server + ":" + port + " using " + method + "...");
77
78 if (!ssn) {
79 throw new Error("vantageClient.connect was called with an invalid Session ID: " + options.sessionId);
80 }
81
82 ssn.client = require("socket.io-client")(method + "://" + server + ":" + port, {
83 "force new connection": true,
84 "forceNew": true,
85 "secure": true,
86 "query": "id=" + self.parent.session.id + "&sessionId=" + options.sessionId,
87 "reconnection": true,
88 "reconnectionDelay": 1000,
89 "reconnectionAttempts": 1
90 });
91
92 ssn.client.on("connect", function() {
93
94 if (!ssn.client) { return; }
95 self.parent.emit("client_connect", this);
96
97 ssn.client.on("vantage-banner-downstream", function(data) {
98 self.parent._proxy("vantage-banner-downstream", "downstream", data).then(function(){
99 if (data.banner) {
100 ssn.log(data.banner);
101 }
102 });
103 });
104
105 ssn.client.on("vantage-keypress-downstream", function(data) {
106 self.parent._proxy("vantage-keypress-downstream", "downstream", data).then(function(){
107 if (data.value !== undefined) {
108 if (_.isArray(data.value)) {
109 self.parent.ui.imprint();
110 ssn.log(data.value);
111 } else {
112 self.parent.ui.redraw(data.value);
113 }
114 }
115 });
116 });
117
118 // Command completion.
119 ssn.client.on("vantage-command-downstream", function(data) {
120 self.parent._proxy("vantage-command-downstream", "downstream", data).then(function(){
121 if (data.completed === true) {
122 data.data = VantageUtil.fixArgsForApply(data.data);
123 if (self.parent._command) {
124 if (self.parent._command.command !== data.command) {
125 console.log("Downstream command does not match stored comand: ", data.command, " -vs -", self.parent._command.command);
126 }
127 var name = self.parent._command.command;
128 var res = self.parent._command.resolve;
129 var rej = self.parent._command.reject;
130 var cbk = self.parent._command.callback;
131 delete self.parent._command;
132 self.parent._command = void 0;
133 try {
134 self.parent._queueHandler.call(self.parent);
135 } catch(e) {
136 console.log("Error on vantage command downstream: ", e.stack);
137 }
138
139 if (cbk !== undefined) {
140 self.parent.emit("client_command_executed", { command: name });
141 cbk.apply(null, data.data);
142 } else if (data.error !== undefined && rej !== undefined) {
143 self.parent.emit("client_command_error", { command: name, error: data.error });
144 try {
145 rej(data.error);
146 } catch(e) {
147 console.log("Error calling Promise reject on vantage command downstream: ", e);
148 }
149 } else if (res !== undefined) {
150 self.parent.emit("client_command_executed", { command: name });
151 if (data.error === undefined && _.isArray(data.data) && data.data.length === 2) {
152 data.data.shift();
153 }
154 try {
155 res.apply(null, data.data);
156 } catch(e) {
157 console.log("Error calling Promise resolve on vantage command downstream: ", e);
158 }
159 }
160 }
161 if (!self.parent.ui.midPrompt()) {
162 self.parent._prompt({ sessionId: data.sessionId });
163 }
164 } else {
165 console.log("Vantage command downstream was called with no completed boolean.");
166 console.trace();
167 }
168 });
169 });
170
171 ssn.client.on("vantage-stdout-downstream", function(data) {
172 self.parent._proxy("vantage-stdout-downstream", "downstream", data).then(function(){
173 var stdout = data.value || "";
174 stdout =
175 (_.isString(stdout) && (util.inspect(stdout.slice(stdout.length - 2, stdout.length).trim() === "\n")))
176 ? stdout.slice(0, stdout.length - 1)
177 : stdout;
178 ssn.log(stdout);
179 });
180 });
181
182 ssn.client.on("vantage-heartbeat-downstream", function(data){
183 self.parent._proxy("vantage-heartbeat-downstream", "downstream", data).then(function(){
184 if (data.delimiter) {
185 ssn.delimiter(data.delimiter);
186 }
187 self.parent.emit("vantage-heartbeat-downstream");
188 });
189 });
190
191 ssn.client.on("vantage-mode-delimiter-downstream", function(data){
192 self.parent._proxy("vantage-mode-delimiter-downstream", "downstream", data).then(function(){
193 if (typeof data.value !== "undefined") {
194 ssn.modeDelimiter(data.value);
195 self.parent.emit("vantage-mode-delimiter-downstream");
196 }
197 });
198 });
199
200 ssn.client.on("vantage-delimiter-downstream", function(data){
201 self.parent._proxy("vantage-delimiter-downstream", "downstream", data).then(function(){
202 if (data.value) {
203 ssn.delimiter(data.value);
204 self.parent.emit("vantage-delimiter-downstream");
205 }
206 });
207 });
208
209 ssn.client.on("vantage-prompt-downstream", function(data) {
210 self.parent._proxy("vantage-prompt-downstream", "downstream", data).then(function(){
211 data = data || {};
212 data.options = data.options || {};
213 // Set local prompt delimiter to question
214 // from upstream prompt command.
215 if (self.parent.ui.midPrompt()) {
216 self.parent.ui.pause();
217 }
218 self.parent.ui.setDelimiter(data.options.message || ssn.delimiter);
219 self.parent.ui.prompt(data.options, function(result) {
220 // Reset local prompt delimiter.
221 self.parent.ui.setDelimiter(ssn.delimiter);
222 // Pipe prompt response back upstream so command
223 // execution can continue.
224 self.parent._send("vantage-prompt-upstream", "upstream", { value: result, sessionId: data.sessionId });
225 });
226 });
227 });
228
229 ssn.client.on("vantage-close-downstream", function(data){
230 ssn.client.close();
231 if (self.parent._command !== undefined) {
232 var name = self.parent._command.command;
233 var res = self.parent._command.resolve;
234 var cbk = self.parent._command.callback;
235 delete self.parent._command;
236 self.parent._command = void 0;
237 self.parent._queueHandler.call(self.parent);
238 if (name.indexOf("exit") > -1) {
239 if (cbk !== undefined) {
240 cbk(void 0, "Exited successfully.");
241 } else if (res !== undefined) {
242 res("Exited successfully.");
243 }
244 self.parent.emit("client_command_executed", { command: name });
245 }
246
247 } else {
248 self.parent._send("vantage-command-downstream", "downstream", { completed: true, data: "Exited successfully.", sessionId: data.sessionId, command: "exit" });
249 }
250 });
251
252 ssn.client.on("vantage-resume-downstream", function(data) {
253 self.parent._proxy("vantage-resume-downstream", "downstream", data).then(function(){
254 self.parent._prompt({ sessionId: data.sessionId });
255 });
256 });
257
258 ssn.client.on("vantage-ssn-stdout-downstream", function(data) {
259 self.parent._proxy("vantage-ssn-stdout-downstream", "downstream", data).then(function() {
260 var sessn = self.parent.getSessionById(data.sessionId);
261 if (sessn) {
262 sessn.log.apply(sessn, data.value);
263 }
264 });
265 });
266
267 if (ssn.isLocal() && self.parent.ui.midPrompt()) {
268 self.parent.ui.pause();
269 }
270
271 ssn.client.on("vantage-auth-downstream", function(data){
272 data = data || {};
273 var error = data.error;
274 var authenticated = data.authenticated;
275 if (authenticated === true) {
276 ssn.user = options.user || "guest";
277 resolve(void 0);
278 cb(void 0);
279 } else {
280 self.parent._send("vantage-close-upstream", "upstream", { sessionId: ssn.id });
281 reject(error || authenticated);
282 cb(true, error || authenticated);
283 }
284 });
285
286 var authData = {
287 handshake: (ssn.client.io.opts || {}),
288 user: options.user,
289 pass: options.pass,
290 sessionId: ssn.id
291 };
292
293 self.parent._send("vantage-auth-upstream", "upstream", authData);
294 });
295
296 function disconnect(data) {
297 self.parent.emit("client_disconnect", data);
298 if (ssn.client) {
299 ssn.client.close();
300 }
301 if (!ssn.isLocal()) {
302 self.parent._send("vantage-heartbeat-downstream", "downstream", {
303 delimiter: self.parent._delimiter,
304 sessionId: ssn.id
305 });
306 } else {
307 ssn.delimiter(self.parent._delimiter);
308 self.parent._prompt({ sessionId: ssn.id });
309 }
310 delete ssn.client;
311 ssn.client = void 0;
312 }
313
314 ssn.client.on("connect_error", function(err) {
315 self.parent.emit("client_connect_error", err);
316 var sessn = self.parent.getSessionById(options.sessionId);
317 var description =
318 (_.isObject(err)) ? ((err.description === 503) ? "503 Service Unavailable" : err.description)
319 : err;
320 sessn.log(chalk.yellow("Connection Error: ") + description);
321 disconnect(err);
322 reject("Connection Error: " + description);
323 cb("Error connecting: " + description);
324 });
325
326 ssn.client.on("error", function(err){
327 self.parent.emit("client_error", err);
328 ssn.log(err);
329 disconnect(err);
330 reject("Connection Error: " + err);
331 cb("Error connecting: " + err);
332 });
333
334 ssn.client.on("disconnect", function(data) {
335 self.parent.emit("client_disconnect", data);
336 // Reset delimiter back.
337 if (!ssn.isLocal()) {
338 self.parent._send("vantage-heartbeat-downstream", "downstream", {
339 delimiter: self.parent._delimiter,
340 sessionId: ssn.id
341 });
342 } else {
343 ssn.delimiter(self.parent._delimiter);
344 self.parent._prompt({ sessionId: ssn.id });
345 }
346 delete ssn.client;
347 ssn.client = void 0;
348 });
349 });
350};