UNPKG

5.98 kBJavaScriptView Raw
1#!/usr/bin/env node
2// transpile:main
3
4import { init as logsinkInit, clear as logsinkClear } from './logsink';
5import logger from './logger'; // logger needs to remain first of imports
6import _ from 'lodash';
7import { server as baseServer, routeConfiguringFunction as makeRouter } from 'appium-base-driver';
8import { asyncify } from 'asyncbox';
9import { default as getParser, getDefaultArgs } from './parser';
10import { logger as logFactory, util } from 'appium-support';
11import {
12 showConfig, checkNodeOk, validateServerArgs,
13 warnNodeDeprecations, validateTmpDir, getNonDefaultArgs,
14 getDeprecatedArgs, getGitRev, APPIUM_VER
15} from './config';
16import { AppiumDriver } from './appium';
17import registerNode from './grid-register';
18import { inspectObject } from './utils';
19
20
21async function preflightChecks (parser, args, throwInsteadOfExit = false) {
22 try {
23 checkNodeOk();
24 if (args.longStacktrace) {
25 require('longjohn').async_trace_limit = -1;
26 }
27 if (args.showConfig) {
28 await showConfig();
29 process.exit(0);
30 }
31 warnNodeDeprecations();
32 validateServerArgs(parser, args);
33 if (args.tmpDir) {
34 await validateTmpDir(args.tmpDir);
35 }
36 } catch (err) {
37 logger.error(err.message.red);
38 if (throwInsteadOfExit) {
39 throw err;
40 }
41
42 process.exit(1);
43 }
44}
45
46function logDeprecationWarning (deprecatedArgs) {
47 logger.warn('Deprecated server args:');
48 for (let [arg, realArg] of _.toPairs(deprecatedArgs)) {
49 logger.warn(` ${arg.red} => ${realArg}`);
50 }
51}
52
53function logNonDefaultArgsWarning (args) {
54 logger.info('Non-default server args:');
55 inspectObject(args);
56}
57
58function logDefaultCapabilitiesWarning (caps) {
59 logger.info('Default capabilities, which will be added to each request ' +
60 'unless overridden by desired capabilities:');
61 inspectObject(caps);
62}
63
64async function logStartupInfo (parser, args) {
65 let welcome = `Welcome to Appium v${APPIUM_VER}`;
66 let appiumRev = await getGitRev();
67 if (appiumRev) {
68 welcome += ` (REV ${appiumRev})`;
69 }
70 logger.info(welcome);
71
72 let showArgs = getNonDefaultArgs(parser, args);
73 if (_.size(showArgs)) {
74 logNonDefaultArgsWarning(showArgs);
75 }
76 let deprecatedArgs = getDeprecatedArgs(parser, args);
77 if (_.size(deprecatedArgs)) {
78 logDeprecationWarning(deprecatedArgs);
79 }
80 if (!_.isEmpty(args.defaultCapabilities)) {
81 logDefaultCapabilitiesWarning(args.defaultCapabilities);
82 }
83 // TODO: bring back loglevel reporting below once logger is flushed out
84 // logger.info('Console LogLevel: ' + logger.transports.console.level);
85 // if (logger.transports.file) {
86 // logger.info('File LogLevel: ' + logger.transports.file.level);
87 // }
88}
89
90function logServerPort (address, port) {
91 let logMessage = `Appium REST http interface listener started on ` +
92 `${address}:${port}`;
93 logger.info(logMessage);
94}
95
96async function main (args = null) {
97 let parser = getParser();
98 let throwInsteadOfExit = false;
99 if (args) {
100 // a containing package passed in their own args, let's fill them out
101 // with defaults
102 args = Object.assign({}, getDefaultArgs(), args);
103
104 // if we have a containing package instead of running as a CLI process,
105 // that package might not appreciate us calling 'process.exit' willy-
106 // nilly, so give it the option to have us throw instead of exit
107 if (args.throwInsteadOfExit) {
108 throwInsteadOfExit = true;
109 // but remove it since it's not a real server arg per se
110 delete args.throwInsteadOfExit;
111 }
112 } else {
113 // otherwise parse from CLI
114 args = parser.parse_args();
115 }
116 await logsinkInit(args);
117 if (args.logFilters) {
118 const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(args.logFilters);
119 if (!_.isEmpty(issues)) {
120 throw new Error(`The log filtering rules config '${args.logFilters}' has issues: ` +
121 JSON.stringify(issues, null, 2));
122 }
123 if (_.isEmpty(rules)) {
124 logger.warn(`Found no log filtering rules in '${args.logFilters}'. Is that expected?`);
125 } else {
126 logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${args.logFilters}'`);
127 }
128 }
129 await preflightChecks(parser, args, throwInsteadOfExit);
130 await logStartupInfo(parser, args);
131 let appiumDriver = new AppiumDriver(args);
132 let routeConfiguringFunction = makeRouter(appiumDriver);
133 const serverOpts = {
134 routeConfiguringFunction,
135 port: args.port,
136 hostname: args.address,
137 allowCors: args.allowCors,
138 basePath: args.basePath,
139 };
140 if (args.keepAliveTimeout) {
141 serverOpts.keepAliveTimeout = args.keepAliveTimeout * 1000;
142 }
143 let server = await baseServer(serverOpts);
144 if (args.allowCors) {
145 logger.warn('You have enabled CORS requests from any host. Be careful not ' +
146 'to visit sites which could maliciously try to start Appium ' +
147 'sessions on your machine');
148 }
149 appiumDriver.server = server;
150 try {
151 // TODO prelaunch if args.launch is set
152 // TODO: startAlertSocket(server, appiumServer);
153
154 // configure as node on grid, if necessary
155 if (args.nodeconfig !== null) {
156 await registerNode(args.nodeconfig, args.address, args.port);
157 }
158 } catch (err) {
159 await server.close();
160 throw err;
161 }
162
163 for (const signal of ['SIGINT', 'SIGTERM']) {
164 process.once(signal, async function onSignal () {
165 logger.info(`Received ${signal} - shutting down`);
166 try {
167 try {
168 await appiumDriver.deleteAllSessions({
169 force: true,
170 reason: `The process has received ${signal} signal`,
171 });
172 logsinkClear();
173 } finally {
174 await server.close();
175 }
176 process.exit(0);
177 } catch (e) {
178 logger.error(e.message);
179 process.exit(1);
180 }
181 });
182 }
183
184 logServerPort(args.address, args.port);
185
186 return server;
187}
188
189if (require.main === module) {
190 asyncify(main);
191}
192
193export { main };