@vpalmisano/webrtcperf 4.2.2 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,15 @@
1
1
  import { Config } from './config';
2
+ import { Server } from './server';
2
3
  import { Stats } from './stats';
3
- export declare function setupApplication(config: Config): Promise<{
4
- stats: Stats;
5
- stop: () => Promise<void>;
6
- }>;
4
+ import { EventEmitter } from 'events';
5
+ export declare class Application extends EventEmitter {
6
+ readonly config: Config;
7
+ readonly stats: Stats;
8
+ readonly server?: Server;
9
+ private mediaPaths;
10
+ constructor(config: Config);
11
+ start(): Promise<void>;
12
+ private startSession;
13
+ private postTest;
14
+ stop(canceled?: boolean): Promise<void>;
15
+ }
package/build/src/app.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.setupApplication = setupApplication;
6
+ exports.Application = void 0;
7
7
  const throttler_1 = require("@vpalmisano/throttler");
8
8
  const change_case_1 = require("change-case");
9
9
  const fs_1 = __importDefault(require("fs"));
@@ -18,6 +18,7 @@ const visqol_1 = require("./visqol");
18
18
  const vmaf_1 = require("./vmaf");
19
19
  const path_1 = __importDefault(require("path"));
20
20
  const marked_terminal_1 = require("marked-terminal");
21
+ const events_1 = require("events");
21
22
  // eslint-disable-next-line @typescript-eslint/no-require-imports
22
23
  const { marked } = require('marked');
23
24
  marked.use((0, marked_terminal_1.markedTerminal)({ reflowText: true, tab: 2 }));
@@ -46,129 +47,148 @@ Default value: \`${value.default}\`
46
47
  process.exit(0);
47
48
  }
48
49
  }
49
- async function postTest(config) {
50
- // vmaf score.
51
- if (config.vmafPath) {
52
- console.log('Calculating VMAF score...');
53
- try {
54
- await (0, vmaf_1.calculateVmafScore)(config);
50
+ class Application extends events_1.EventEmitter {
51
+ config;
52
+ stats;
53
+ server;
54
+ mediaPaths = [];
55
+ constructor(config) {
56
+ super();
57
+ if (!config.startTimestamp) {
58
+ config.startTimestamp = Date.now();
55
59
  }
56
- catch (err) {
57
- log.error(`vmaf score error: ${err.stack}`);
60
+ this.config = config;
61
+ this.stats = new stats_1.Stats(config);
62
+ if (config.serverPort) {
63
+ this.server = new server_1.Server(config, this.stats);
58
64
  }
59
65
  }
60
- // visqol score
61
- if (config.visqolPath) {
62
- console.log('Calculating Visqol score...');
63
- try {
64
- await (0, visqol_1.calculateVisqolScore)(config);
66
+ async start() {
67
+ log.debug(`start (runDuration: ${this.config.runDuration})`);
68
+ await this.stats.start();
69
+ if (this.server) {
70
+ await this.server.start();
65
71
  }
66
- catch (err) {
67
- log.error(`visqol score error: ${err.stack}`);
72
+ const config = this.config;
73
+ // Handle vmaf commands.
74
+ if (config.vmafPrepareVideo) {
75
+ await (0, vmaf_1.prepareVideo)(config, true);
68
76
  }
69
- }
70
- }
71
- async function setupApplication(config) {
72
- if (!config.startTimestamp) {
73
- config.startTimestamp = Date.now();
74
- }
75
- // Stats.
76
- const stats = new stats_1.Stats(config);
77
- await stats.start();
78
- // Control server.
79
- let server;
80
- if (config.serverPort) {
81
- server = new server_1.Server(config, stats);
82
- await server.start();
83
- }
84
- // If sessions are set, prepare fake video/audio and start sessions.
85
- if (config.sessions > 0) {
86
- // Prepare fake video and audio.
87
- const mediaPaths = [];
88
- if (config.videoPath) {
89
- for (const videoPath of config.videoPath.split(',')) {
90
- const ret = await (0, media_1.prepareFakeMedia)({ ...config, videoPath });
91
- mediaPaths.push(ret);
92
- }
77
+ if (config.vmafProcessVideo) {
78
+ await (0, vmaf_1.convertToIvf)(config.vmafProcessVideo, config.vmafVideoCrop, config.vmafKeepSourceFiles, config.vmafSkipDuplicated);
93
79
  }
94
- // Network throttle.
95
- if (config.throttleConfig) {
96
- await (0, throttler_1.startThrottle)(config.throttleConfig);
80
+ // Handle sessions.
81
+ if (config.sessions > 0) {
82
+ // Prepare fake video and audio.
83
+ if (config.videoPath && !this.mediaPaths.length) {
84
+ for (const videoPath of config.videoPath.split(',')) {
85
+ const ret = await (0, media_1.prepareFakeMedia)({ ...config, videoPath });
86
+ this.mediaPaths.push(ret);
87
+ }
88
+ }
89
+ // Network throttle.
90
+ if (config.throttleConfig) {
91
+ await (0, throttler_1.startThrottle)(config.throttleConfig);
92
+ }
93
+ // Download browser if necessary.
94
+ if (!config.chromiumUrl && !config.chromiumPath) {
95
+ await (0, utils_1.checkChromeExecutable)();
96
+ }
97
+ // Start the local sessions.
98
+ if (config.randomAudioPeriod) {
99
+ (0, utils_1.startRandomActivateAudio)(this.stats.sessions, config.randomAudioPeriod, config.randomAudioProbability, config.randomAudioRange);
100
+ }
101
+ const spawnPeriod = 1000 / config.spawnRate;
102
+ log.debug(`Starting ${config.sessions} sessions (spawnPeriod: ${spawnPeriod}ms)`);
103
+ const startTime = Date.now();
104
+ for (let i = 0; i < config.sessions; i += 1) {
105
+ const id = this.stats.consumeSessionId(config.tabsPerSession);
106
+ await this.startSession(id, spawnPeriod);
107
+ // If not the last session, sleep.
108
+ if (i < config.sessions - 1) {
109
+ await (0, utils_1.sleep)(spawnPeriod);
110
+ }
111
+ }
112
+ const elapsed = Math.round((Date.now() - startTime) / 1000);
113
+ const spawnRate = (config.sessions * config.tabsPerSession) / elapsed;
114
+ log.debug(`${config.sessions * config.tabsPerSession} pages started in ${elapsed}s (${spawnRate.toFixed(2)}/s)`);
97
115
  }
98
- // Download browser if necessary.
99
- if (!config.chromiumUrl && !config.chromiumPath) {
100
- await (0, utils_1.checkChromeExecutable)();
116
+ if (config.runDuration || config.vmafPath || config.visqolPath) {
117
+ setTimeout(() => this.stop(), config.runDuration * 1000);
101
118
  }
102
- // Start session function.
103
- const startLocalSession = async (id, spawnPeriod) => {
104
- const throttleIndex = (0, throttler_1.getSessionThrottleIndex)(id);
105
- const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined;
106
- const session = new session_1.Session({
107
- ...config,
108
- mediaPath,
109
- spawnPeriod,
110
- id,
111
- throttleIndex,
112
- });
113
- session.once('stop', () => {
114
- console.warn(`Session ${id} stopped, reloading...`);
115
- setTimeout(startLocalSession, spawnPeriod, id);
116
- });
117
- stats.addSession(session);
118
- await session.start();
119
- };
120
- // Start the local sessions.
121
- if (config.randomAudioPeriod) {
122
- (0, utils_1.startRandomActivateAudio)(stats.sessions, config.randomAudioPeriod, config.randomAudioProbability, config.randomAudioRange);
119
+ }
120
+ async startSession(id, spawnPeriod) {
121
+ log.debug(`startSession ${id}`);
122
+ const throttleIndex = (0, throttler_1.getSessionThrottleIndex)(id);
123
+ const mediaPath = this.mediaPaths.length ? this.mediaPaths[id % this.mediaPaths.length] : undefined;
124
+ const session = new session_1.Session({
125
+ ...this.config,
126
+ mediaPath,
127
+ spawnPeriod,
128
+ id,
129
+ throttleIndex,
130
+ });
131
+ session.once('stop', () => {
132
+ console.warn(`Session ${id} stopped, reloading...`);
133
+ setTimeout(() => this.startSession(id, spawnPeriod), spawnPeriod);
134
+ });
135
+ this.stats.addSession(session);
136
+ await session.start();
137
+ }
138
+ async postTest() {
139
+ log.debug('postTest');
140
+ // vmaf score.
141
+ if (this.config.vmafPath) {
142
+ console.log('Calculating VMAF score...');
143
+ try {
144
+ await (0, vmaf_1.calculateVmafScore)(this.config);
145
+ }
146
+ catch (err) {
147
+ log.error(`vmaf score error: ${err.stack}`);
148
+ }
123
149
  }
124
- const spawnPeriod = 1000 / config.spawnRate;
125
- log.debug(`Starting ${config.sessions} sessions (spawnPeriod: ${spawnPeriod}ms)`);
126
- const startTime = Date.now();
127
- for (let i = 0; i < config.sessions; i += 1) {
128
- const id = stats.consumeSessionId(config.tabsPerSession);
129
- await startLocalSession(id, spawnPeriod);
130
- // If not the last session, sleep
131
- if (i < config.sessions - 1) {
132
- await (0, utils_1.sleep)(spawnPeriod);
150
+ // visqol score
151
+ if (this.config.visqolPath) {
152
+ console.log('Calculating Visqol score...');
153
+ try {
154
+ await (0, visqol_1.calculateVisqolScore)(this.config);
155
+ }
156
+ catch (err) {
157
+ log.error(`visqol score error: ${err.stack}`);
133
158
  }
134
159
  }
135
- const elapsed = Math.round((Date.now() - startTime) / 1000);
136
- const spawnRate = (config.sessions * config.tabsPerSession) / elapsed;
137
- log.debug(`${config.sessions * config.tabsPerSession} pages started in ${elapsed}s (${spawnRate.toFixed(2)}/s)`);
138
160
  }
139
- return {
140
- stats,
141
- stop: async () => {
142
- log.debug('Stopping');
143
- (0, utils_1.stopRandomActivateAudio)();
144
- await stats.stop();
145
- if (config.throttleConfig) {
146
- await (0, throttler_1.stopThrottle)();
161
+ async stop(canceled = false) {
162
+ log.debug(`stop (canceled: ${canceled})`);
163
+ (0, utils_1.stopRandomActivateAudio)();
164
+ await this.stats.stop();
165
+ if (this.config.throttleConfig) {
166
+ await (0, throttler_1.stopThrottle)();
167
+ }
168
+ (0, utils_1.stopTimers)();
169
+ await this.postTest();
170
+ // Copy docker logs to data directory.
171
+ if (this.config.pageLogPath) {
172
+ try {
173
+ const logPath = await (0, utils_1.getDockerLogsPath)();
174
+ const dataDir = path_1.default.dirname(this.config.pageLogPath);
175
+ await fs_1.default.promises.cp(logPath, path_1.default.resolve(dataDir, 'docker.log'));
147
176
  }
148
- (0, utils_1.stopTimers)();
149
- await postTest(config);
150
- // Copy docker logs to data directory.
151
- if (config.pageLogPath) {
152
- try {
153
- const logPath = await (0, utils_1.getDockerLogsPath)();
154
- const dataDir = path_1.default.dirname(config.pageLogPath);
155
- await fs_1.default.promises.cp(logPath, path_1.default.resolve(dataDir, 'docker.log'));
156
- }
157
- catch (err) {
158
- log.debug(`docker logs not found: ${err.message}`);
159
- }
177
+ catch (err) {
178
+ log.debug(`docker logs not found: ${err.message}`);
160
179
  }
161
- server?.stop();
162
- log.debug('Stopped');
163
- },
164
- };
180
+ }
181
+ this.server?.stop();
182
+ this.emit('stop', canceled);
183
+ }
165
184
  }
185
+ exports.Application = Application;
166
186
  /**
167
187
  * Main function
168
188
  */
169
189
  async function main() {
170
190
  showHelpOrVersion();
171
- let config;
191
+ let configs;
172
192
  if (process.argv.slice(2).includes('--prompt')) {
173
193
  const params = await (0, config_1.loadConfigFromPrompt)(process.argv
174
194
  .slice(2)
@@ -178,28 +198,34 @@ async function main() {
178
198
  console.log(json5_1.default.stringify(params, null, 2));
179
199
  process.exit(0);
180
200
  }
181
- config = await (0, config_1.loadConfig)(undefined, params);
201
+ configs = await (0, config_1.loadConfig)(undefined, params);
182
202
  }
183
203
  else {
184
- config = await (0, config_1.loadConfig)(process.argv[2]);
204
+ configs = await (0, config_1.loadConfig)(process.argv[2]);
185
205
  }
186
- if (config.vmafPrepareVideo) {
187
- await (0, vmaf_1.prepareVideo)(config, true);
188
- process.exit(0);
189
- }
190
- if (config.vmafProcessVideo) {
191
- await (0, vmaf_1.convertToIvf)(config.vmafProcessVideo, config.vmafVideoCrop, config.vmafKeepSourceFiles, config.vmafSkipDuplicated);
192
- process.exit(0);
193
- }
194
- const { stop: stopApplication } = await setupApplication(config);
206
+ if (!configs.length)
207
+ throw new Error('No configuration found');
208
+ let application;
209
+ const runNext = () => {
210
+ const config = configs.splice(0, 1)[0];
211
+ application = new Application(config);
212
+ application.once('stop', canceled => {
213
+ if (!canceled && configs.length) {
214
+ log.info(`Application stopped, running next (${configs.length} left)...`);
215
+ runNext();
216
+ }
217
+ else {
218
+ process.exit(0);
219
+ }
220
+ });
221
+ return application.start();
222
+ };
195
223
  const stop = async () => {
196
224
  console.log('Exiting...');
197
- await stopApplication();
198
- process.exit(0);
225
+ await application.stop(true);
199
226
  };
200
227
  (0, utils_1.registerExitHandler)(() => stop());
201
- // Stop after a configured duration.
202
- setTimeout(stop, config.runDuration * 1000);
228
+ await runNext();
203
229
  // Command line interface.
204
230
  if (process.stdin && process.stdin.setRawMode) {
205
231
  console.log('Press [q] to quit or [x] to exit immediately');
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"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","sourcesContent":["import { getSessionThrottleIndex, startThrottle, stopThrottle } from '@vpalmisano/throttler'\nimport { paramCase } from 'change-case'\nimport fs from 'fs'\nimport json5 from 'json5'\n\nimport { Config, getConfigDocs, loadConfig, loadConfigFromPrompt } from './config'\nimport { MediaPath, prepareFakeMedia } from './media'\nimport { Server } from './server'\nimport { Session } from './session'\nimport { Stats } from './stats'\nimport {\n checkChromeExecutable,\n getDockerLogsPath,\n logger,\n registerExitHandler,\n resolvePackagePath,\n sleep,\n startRandomActivateAudio,\n stopRandomActivateAudio,\n stopTimers,\n} from './utils'\nimport { calculateVisqolScore } from './visqol'\nimport { calculateVmafScore, convertToIvf, prepareVideo } from './vmaf'\nimport path from 'path'\nimport { markedTerminal } from 'marked-terminal'\n\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst { marked } = require('marked')\nmarked.use(markedTerminal({ reflowText: true, tab: 2 }))\n\nconst log = logger('webrtcperf')\n\nfunction showHelpOrVersion(): void {\n if (process.argv.includes('--help') || process.argv.includes('-h')) {\n const docs = getConfigDocs()\n let out = marked.parse(`**Webrtcperf parameters**\n\n\\`--version\\` It shows the package version.\n`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Object.entries(docs).forEach(([name, value]: [string, any]) => {\n out += marked.parse(\n `\n\\`--${paramCase(name)}\\`\n${value.doc}\nDefault value: \\`${value.default}\\`\n`,\n )\n })\n console.log(out)\n process.exit(0)\n } else if (process.argv.includes('--version') || process.argv.includes('-v')) {\n const version = json5.parse(fs.readFileSync(resolvePackagePath('package.json')).toString()).version\n console.log(version)\n process.exit(0)\n }\n}\n\nasync function postTest(config: Config): Promise<void> {\n // vmaf score.\n if (config.vmafPath) {\n console.log('Calculating VMAF score...')\n try {\n await calculateVmafScore(config)\n } catch (err: unknown) {\n log.error(`vmaf score error: ${(err as Error).stack}`)\n }\n }\n\n // visqol score\n if (config.visqolPath) {\n console.log('Calculating Visqol score...')\n try {\n await calculateVisqolScore(config)\n } catch (err: unknown) {\n log.error(`visqol score error: ${(err as Error).stack}`)\n }\n }\n}\n\nexport async function setupApplication(config: Config): Promise<{ stats: Stats; stop: () => Promise<void> }> {\n if (!config.startTimestamp) {\n config.startTimestamp = Date.now()\n }\n\n // Stats.\n const stats = new Stats(config)\n await stats.start()\n\n // Control server.\n let server: Server | undefined\n if (config.serverPort) {\n server = new Server(config, stats)\n await server.start()\n }\n\n // If sessions are set, prepare fake video/audio and start sessions.\n if (config.sessions > 0) {\n // Prepare fake video and audio.\n const mediaPaths: MediaPath[] = []\n if (config.videoPath) {\n for (const videoPath of config.videoPath.split(',')) {\n const ret = await prepareFakeMedia({ ...config, videoPath })\n mediaPaths.push(ret)\n }\n }\n\n // Network throttle.\n if (config.throttleConfig) {\n await startThrottle(config.throttleConfig)\n }\n\n // Download browser if necessary.\n if (!config.chromiumUrl && !config.chromiumPath) {\n await checkChromeExecutable()\n }\n\n // Start session function.\n const startLocalSession = async (id: number, spawnPeriod: number): Promise<void> => {\n const throttleIndex = getSessionThrottleIndex(id)\n const mediaPath = mediaPaths.length ? mediaPaths[id % mediaPaths.length] : undefined\n const session = new Session({\n ...config,\n mediaPath,\n spawnPeriod,\n id,\n throttleIndex,\n })\n session.once('stop', () => {\n console.warn(`Session ${id} stopped, reloading...`)\n setTimeout(startLocalSession, spawnPeriod, id)\n })\n stats.addSession(session)\n await session.start()\n }\n\n // Start the local sessions.\n if (config.randomAudioPeriod) {\n startRandomActivateAudio(\n stats.sessions,\n config.randomAudioPeriod,\n config.randomAudioProbability,\n config.randomAudioRange,\n )\n }\n const spawnPeriod = 1000 / config.spawnRate\n log.debug(`Starting ${config.sessions} sessions (spawnPeriod: ${spawnPeriod}ms)`)\n const startTime = Date.now()\n for (let i = 0; i < config.sessions; i += 1) {\n const id = stats.consumeSessionId(config.tabsPerSession)\n await startLocalSession(id, spawnPeriod)\n // If not the last session, sleep\n if (i < config.sessions - 1) {\n await sleep(spawnPeriod)\n }\n }\n const elapsed = Math.round((Date.now() - startTime) / 1000)\n const spawnRate = (config.sessions * config.tabsPerSession) / elapsed\n log.debug(`${config.sessions * config.tabsPerSession} pages started in ${elapsed}s (${spawnRate.toFixed(2)}/s)`)\n }\n\n return {\n stats,\n stop: async (): Promise<void> => {\n log.debug('Stopping')\n\n stopRandomActivateAudio()\n\n await stats.stop()\n\n if (config.throttleConfig) {\n await stopThrottle()\n }\n\n stopTimers()\n\n await postTest(config)\n\n // Copy docker logs to data directory.\n if (config.pageLogPath) {\n try {\n const logPath = await getDockerLogsPath()\n const dataDir = path.dirname(config.pageLogPath)\n await fs.promises.cp(logPath, path.resolve(dataDir, 'docker.log'))\n } catch (err: unknown) {\n log.debug(`docker logs not found: ${(err as Error).message}`)\n }\n }\n\n server?.stop()\n\n log.debug('Stopped')\n },\n }\n}\n\n/**\n * Main function\n */\nasync function main(): Promise<void> {\n showHelpOrVersion()\n\n let config: Config\n\n if (process.argv.slice(2).includes('--prompt')) {\n const params = await loadConfigFromPrompt(\n process.argv\n .slice(2)\n .filter(s => !['--prompt', '--dry-run'].includes(s))\n .join(' '),\n )\n if (process.argv.slice(2).includes('--dry-run')) {\n console.log(json5.stringify(params, null, 2))\n process.exit(0)\n }\n config = await loadConfig(undefined, params)\n } else {\n config = await loadConfig(process.argv[2])\n }\n\n if (config.vmafPrepareVideo) {\n await prepareVideo(config, true)\n process.exit(0)\n }\n\n if (config.vmafProcessVideo) {\n await convertToIvf(\n config.vmafProcessVideo,\n config.vmafVideoCrop,\n config.vmafKeepSourceFiles,\n config.vmafSkipDuplicated,\n )\n process.exit(0)\n }\n\n const { stop: stopApplication } = await setupApplication(config)\n\n const stop = async (): Promise<void> => {\n console.log('Exiting...')\n\n await stopApplication()\n\n process.exit(0)\n }\n registerExitHandler(() => stop())\n\n // Stop after a configured duration.\n setTimeout(stop, config.runDuration * 1000)\n\n // Command line interface.\n if (process.stdin && process.stdin.setRawMode) {\n console.log('Press [q] to quit or [x] to exit immediately')\n process.stdin.setRawMode(true)\n process.stdin.resume()\n process.stdin.on('data', async data => {\n log.debug('[stdin]', data[0])\n if (data[0] === 'q'.charCodeAt(0)) {\n try {\n await stop()\n } catch (err: unknown) {\n log.error(`stop error: ${(err as Error).stack}`)\n process.exit(1)\n }\n } else if (data[0] === 'x'.charCodeAt(0)) {\n process.exit(1)\n }\n })\n }\n}\n\nif (require.main === module) {\n main().catch(err => {\n console.error(err)\n process.exit(-1)\n })\n}\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"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","sourcesContent":["import { getSessionThrottleIndex, startThrottle, stopThrottle } from '@vpalmisano/throttler'\nimport { paramCase } from 'change-case'\nimport fs from 'fs'\nimport json5 from 'json5'\n\nimport { Config, getConfigDocs, loadConfig, loadConfigFromPrompt } from './config'\nimport { MediaPath, prepareFakeMedia } from './media'\nimport { Server } from './server'\nimport { Session } from './session'\nimport { Stats } from './stats'\nimport {\n checkChromeExecutable,\n getDockerLogsPath,\n logger,\n registerExitHandler,\n resolvePackagePath,\n sleep,\n startRandomActivateAudio,\n stopRandomActivateAudio,\n stopTimers,\n} from './utils'\nimport { calculateVisqolScore } from './visqol'\nimport { calculateVmafScore, convertToIvf, prepareVideo } from './vmaf'\nimport path from 'path'\nimport { markedTerminal } from 'marked-terminal'\nimport { EventEmitter } from 'events'\n\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst { marked } = require('marked')\nmarked.use(markedTerminal({ reflowText: true, tab: 2 }))\n\nconst log = logger('webrtcperf')\n\nfunction showHelpOrVersion(): void {\n if (process.argv.includes('--help') || process.argv.includes('-h')) {\n const docs = getConfigDocs()\n let out = marked.parse(`**Webrtcperf parameters**\n\n\\`--version\\` It shows the package version.\n`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Object.entries(docs).forEach(([name, value]: [string, any]) => {\n out += marked.parse(\n `\n\\`--${paramCase(name)}\\`\n${value.doc}\nDefault value: \\`${value.default}\\`\n`,\n )\n })\n console.log(out)\n process.exit(0)\n } else if (process.argv.includes('--version') || process.argv.includes('-v')) {\n const version = json5.parse(fs.readFileSync(resolvePackagePath('package.json')).toString()).version\n console.log(version)\n process.exit(0)\n }\n}\n\nexport class Application extends EventEmitter {\n readonly config: Config\n readonly stats: Stats\n readonly server?: Server\n private mediaPaths: MediaPath[] = []\n\n constructor(config: Config) {\n super()\n if (!config.startTimestamp) {\n config.startTimestamp = Date.now()\n }\n this.config = config\n this.stats = new Stats(config)\n if (config.serverPort) {\n this.server = new Server(config, this.stats)\n }\n }\n\n async start() {\n log.debug(`start (runDuration: ${this.config.runDuration})`)\n await this.stats.start()\n if (this.server) {\n await this.server.start()\n }\n const config = this.config\n\n // Handle vmaf commands.\n if (config.vmafPrepareVideo) {\n await prepareVideo(config, true)\n }\n if (config.vmafProcessVideo) {\n await convertToIvf(\n config.vmafProcessVideo,\n config.vmafVideoCrop,\n config.vmafKeepSourceFiles,\n config.vmafSkipDuplicated,\n )\n }\n\n // Handle sessions.\n if (config.sessions > 0) {\n // Prepare fake video and audio.\n if (config.videoPath && !this.mediaPaths.length) {\n for (const videoPath of config.videoPath.split(',')) {\n const ret = await prepareFakeMedia({ ...config, videoPath })\n this.mediaPaths.push(ret)\n }\n }\n\n // Network throttle.\n if (config.throttleConfig) {\n await startThrottle(config.throttleConfig)\n }\n\n // Download browser if necessary.\n if (!config.chromiumUrl && !config.chromiumPath) {\n await checkChromeExecutable()\n }\n\n // Start the local sessions.\n if (config.randomAudioPeriod) {\n startRandomActivateAudio(\n this.stats.sessions,\n config.randomAudioPeriod,\n config.randomAudioProbability,\n config.randomAudioRange,\n )\n }\n const spawnPeriod = 1000 / config.spawnRate\n log.debug(`Starting ${config.sessions} sessions (spawnPeriod: ${spawnPeriod}ms)`)\n const startTime = Date.now()\n for (let i = 0; i < config.sessions; i += 1) {\n const id = this.stats.consumeSessionId(config.tabsPerSession)\n await this.startSession(id, spawnPeriod)\n // If not the last session, sleep.\n if (i < config.sessions - 1) {\n await sleep(spawnPeriod)\n }\n }\n const elapsed = Math.round((Date.now() - startTime) / 1000)\n const spawnRate = (config.sessions * config.tabsPerSession) / elapsed\n log.debug(`${config.sessions * config.tabsPerSession} pages started in ${elapsed}s (${spawnRate.toFixed(2)}/s)`)\n }\n\n if (config.runDuration || config.vmafPath || config.visqolPath) {\n setTimeout(() => this.stop(), config.runDuration * 1000)\n }\n }\n\n private async startSession(id: number, spawnPeriod: number) {\n log.debug(`startSession ${id}`)\n const throttleIndex = getSessionThrottleIndex(id)\n const mediaPath = this.mediaPaths.length ? this.mediaPaths[id % this.mediaPaths.length] : undefined\n const session = new Session({\n ...this.config,\n mediaPath,\n spawnPeriod,\n id,\n throttleIndex,\n })\n session.once('stop', () => {\n console.warn(`Session ${id} stopped, reloading...`)\n setTimeout(() => this.startSession(id, spawnPeriod), spawnPeriod)\n })\n this.stats.addSession(session)\n await session.start()\n }\n\n private async postTest() {\n log.debug('postTest')\n\n // vmaf score.\n if (this.config.vmafPath) {\n console.log('Calculating VMAF score...')\n try {\n await calculateVmafScore(this.config)\n } catch (err: unknown) {\n log.error(`vmaf score error: ${(err as Error).stack}`)\n }\n }\n\n // visqol score\n if (this.config.visqolPath) {\n console.log('Calculating Visqol score...')\n try {\n await calculateVisqolScore(this.config)\n } catch (err: unknown) {\n log.error(`visqol score error: ${(err as Error).stack}`)\n }\n }\n }\n\n async stop(canceled = false) {\n log.debug(`stop (canceled: ${canceled})`)\n\n stopRandomActivateAudio()\n\n await this.stats.stop()\n\n if (this.config.throttleConfig) {\n await stopThrottle()\n }\n\n stopTimers()\n\n await this.postTest()\n\n // Copy docker logs to data directory.\n if (this.config.pageLogPath) {\n try {\n const logPath = await getDockerLogsPath()\n const dataDir = path.dirname(this.config.pageLogPath)\n await fs.promises.cp(logPath, path.resolve(dataDir, 'docker.log'))\n } catch (err: unknown) {\n log.debug(`docker logs not found: ${(err as Error).message}`)\n }\n }\n\n this.server?.stop()\n\n this.emit('stop', canceled)\n }\n}\n\n/**\n * Main function\n */\nasync function main(): Promise<void> {\n showHelpOrVersion()\n\n let configs: Config[]\n\n if (process.argv.slice(2).includes('--prompt')) {\n const params = await loadConfigFromPrompt(\n process.argv\n .slice(2)\n .filter(s => !['--prompt', '--dry-run'].includes(s))\n .join(' '),\n )\n if (process.argv.slice(2).includes('--dry-run')) {\n console.log(json5.stringify(params, null, 2))\n process.exit(0)\n }\n configs = await loadConfig(undefined, params)\n } else {\n configs = await loadConfig(process.argv[2])\n }\n\n if (!configs.length) throw new Error('No configuration found')\n\n let application: Application\n const runNext = () => {\n const config = configs.splice(0, 1)[0]\n\n application = new Application(config)\n application.once('stop', canceled => {\n if (!canceled && configs.length) {\n log.info(`Application stopped, running next (${configs.length} left)...`)\n runNext()\n } else {\n process.exit(0)\n }\n })\n return application.start()\n }\n\n const stop = async () => {\n console.log('Exiting...')\n await application.stop(true)\n }\n registerExitHandler(() => stop())\n\n await runNext()\n\n // Command line interface.\n if (process.stdin && process.stdin.setRawMode) {\n console.log('Press [q] to quit or [x] to exit immediately')\n process.stdin.setRawMode(true)\n process.stdin.resume()\n process.stdin.on('data', async data => {\n log.debug('[stdin]', data[0])\n if (data[0] === 'q'.charCodeAt(0)) {\n try {\n await stop()\n } catch (err: unknown) {\n log.error(`stop error: ${(err as Error).stack}`)\n process.exit(1)\n }\n } else if (data[0] === 'x'.charCodeAt(0)) {\n process.exit(1)\n }\n })\n }\n}\n\nif (require.main === module) {\n main().catch(err => {\n console.error(err)\n process.exit(-1)\n })\n}\n"]}
@@ -102,6 +102,6 @@ export type Config = typeof _schemaProperties;
102
102
  /**
103
103
  * Loads the config object.
104
104
  */
105
- export declare function loadConfig(filePath?: string, values?: any): Promise<Config>;
105
+ export declare function loadConfig(filePath?: string, values?: any): Promise<Config[]>;
106
106
  export declare function loadConfigFromPrompt(prompt: string): Promise<any>;
107
107
  export {};
@@ -47,6 +47,7 @@ const path_1 = __importStar(require("path"));
47
47
  const json5_1 = __importDefault(require("json5"));
48
48
  const yaml_1 = __importDefault(require("yaml"));
49
49
  const toml_1 = __importDefault(require("toml"));
50
+ const fs_2 = __importDefault(require("fs"));
50
51
  // eslint-disable-next-line @typescript-eslint/no-require-imports
51
52
  const puppeteer = require('puppeteer-core');
52
53
  const utils_1 = require("./utils");
@@ -96,8 +97,7 @@ convict_1.default.addParser([
96
97
  { extension: ['yml', 'yaml'], parse: yaml_1.default.parse },
97
98
  { extension: 'toml', parse: toml_1.default.parse },
98
99
  ]);
99
- // config schema
100
- const configSchema = (0, convict_1.default)({
100
+ const configSchema = {
101
101
  url: {
102
102
  doc: `The page url to load.`,
103
103
  format: String,
@@ -899,7 +899,7 @@ E.g. \`{ w: "iw-10", h: "ih-5", x: "10", y: '5' }\``,
899
899
  env: 'VISQOL_KEEP_SOURCE_FILES',
900
900
  arg: 'visqol-keep-source-files',
901
901
  },
902
- });
902
+ };
903
903
  /**
904
904
  * Formats the schema documentation, calling the same function recursively.
905
905
  * @param docs the documentation object to extend
@@ -929,14 +929,15 @@ schema) {
929
929
  * It returns the formatted configuration docs.
930
930
  */
931
931
  function getConfigDocs() {
932
- return formatDocs({}, null, configSchema.getSchema());
932
+ return formatDocs({}, null, (0, convict_1.default)(configSchema).getSchema());
933
933
  }
934
- const _schemaProperties = configSchema.getProperties();
934
+ const _schemaProperties = (0, convict_1.default)(configSchema).getProperties();
935
935
  /**
936
936
  * Loads the config object.
937
937
  */
938
938
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
939
939
  async function loadConfig(filePath, values) {
940
+ const configs = [];
940
941
  if (filePath) {
941
942
  if (filePath.startsWith('http')) {
942
943
  log.debug(`Loading config from url: ${filePath}`);
@@ -944,41 +945,46 @@ async function loadConfig(filePath, values) {
944
945
  if (!res?.data) {
945
946
  throw new Error(`Failed to download configuration from: ${filePath}`);
946
947
  }
947
- const values = res.contentType === 'application/x-yaml'
948
- ? yaml_1.default.parse(res.data)
949
- : res.contentType === 'application/toml'
950
- ? toml_1.default.parse(res.data)
951
- : json5_1.default.parse(res.data);
952
- configSchema.load(values);
948
+ values =
949
+ res.contentType === 'application/x-yaml'
950
+ ? yaml_1.default.parse(res.data)
951
+ : res.contentType === 'application/toml'
952
+ ? toml_1.default.parse(res.data)
953
+ : json5_1.default.parse(res.data);
953
954
  }
954
955
  else if ((0, fs_1.existsSync)(filePath)) {
955
956
  log.debug(`Loading config from local file: ${filePath}`);
956
957
  if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {
957
958
  const module = await import(/* webpackIgnore: true */ path_1.default.resolve(filePath));
958
- configSchema.load(await module.default());
959
+ values = await module.default();
959
960
  }
960
961
  else {
961
- configSchema.loadFile(filePath);
962
+ const data = String(await fs_2.default.promises.readFile(filePath));
963
+ values =
964
+ filePath.endsWith('.yml') || filePath.endsWith('.yaml')
965
+ ? yaml_1.default.parse(data)
966
+ : filePath.endsWith('.toml')
967
+ ? toml_1.default.parse(data)
968
+ : json5_1.default.parse(data);
962
969
  }
963
970
  }
964
971
  }
965
- else if (values) {
966
- log.debug('Loading config from values.');
967
- configSchema.load(values);
972
+ if (!Array.isArray(values)) {
973
+ values = [values || {}];
968
974
  }
969
- else {
970
- log.debug('Loading config from default values.');
971
- configSchema.load({});
975
+ for (const value of values) {
976
+ const schema = (0, convict_1.default)(configSchema);
977
+ schema.load(value || {});
978
+ schema.validate({ allowed: 'strict' });
979
+ configs.push(schema.getProperties());
972
980
  }
973
- configSchema.validate({ allowed: 'strict' });
974
- const config = configSchema.getProperties();
975
- log.debug('Using config:', config);
976
- return config;
981
+ log.debug('Using config:', configs);
982
+ return configs;
977
983
  }
978
984
  function getFunctionDeclaration() {
979
985
  const properties = {};
980
986
  const required = [];
981
- const schema = configSchema.getSchema();
987
+ const schema = (0, convict_1.default)(configSchema).getSchema();
982
988
  Object.entries(schema._cvtProperties).forEach(([name, value]) => {
983
989
  const { format, doc, nullable } = value;
984
990
  properties[name] = {