1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const crypto = require("crypto");
|
4 | const _ = require("underscore");
|
5 | const os = require("os");
|
6 | const path = require("path");
|
7 | const request = require("request-promise");
|
8 | const docker_cli_js_1 = require("docker-cli-js");
|
9 | const cron_1 = require("cron");
|
10 | const uuid = require("uuid/v5");
|
11 | const sbase = require("@nodeswork/sbase");
|
12 | const logger = require("@nodeswork/logger");
|
13 | const utils_1 = require("@nodeswork/utils");
|
14 | const applet = require("@nodeswork/applet");
|
15 | const errors = require("./errors");
|
16 | const utils_2 = require("./utils");
|
17 | const server_1 = require("./server");
|
18 | const socket_1 = require("./socket");
|
19 | const paths_1 = require("./paths");
|
20 | const env = require("./env");
|
21 | const compareVersion = require("compare-version");
|
22 | const latestVersion = require('latest-version');
|
23 | const LOG = logger.getLogger();
|
24 | const APPLET_MANAGER_KEY = 'appletManager';
|
25 | const containerVersion = require('../package.json').version;
|
26 | const isRunning = require('is-running');
|
27 | const machineId = require('node-machine-id').machineIdSync;
|
28 | const UUID_NAMESPACE = '5daabcd8-f17e-568c-aa6f-da9d92c7032c';
|
29 | const NAME_REGEX = /^na-(\w+)-([0-9.]+)-([\w-]+)_([0-9.]+)-(\w+)$/;
|
30 | class AppletManager {
|
31 | constructor(options) {
|
32 | this.options = options;
|
33 | this.docker = new docker_cli_js_1.Docker();
|
34 | this.cronJobs = [];
|
35 | if (this.options.debug) {
|
36 | LOG.level = 'debug';
|
37 | }
|
38 | const configPath = path.join(options.appPath, 'config.json');
|
39 | LOG.debug('Load configuration from configPath', configPath);
|
40 | this.ls = utils_2.localStorage(configPath);
|
41 | let amOptions = this.ls.getItemSync(APPLET_MANAGER_KEY);
|
42 | let running = false;
|
43 | if (amOptions == null) {
|
44 | amOptions = this.options;
|
45 | LOG.debug('Initialize Applet Manager Options to local:', amOptions);
|
46 | this.ls.setItemSync(APPLET_MANAGER_KEY, amOptions);
|
47 | }
|
48 | else {
|
49 | LOG.debug('Got Applet Manager Options from local:', amOptions);
|
50 | if (amOptions.pid) {
|
51 | running = isRunning(amOptions.pid);
|
52 | }
|
53 | this.options.token = amOptions.token;
|
54 | }
|
55 | if (running && (this.options.appPath !== amOptions.appPath ||
|
56 | this.options.nodesworkServer !== amOptions.nodesworkServer ||
|
57 | this.options.port !== amOptions.port)) {
|
58 | throw new utils_1.NodesworkError('Configuration does not match with existing Applet Manager', {
|
59 | newOption: this.options,
|
60 | runningOption: _.pick(amOptions, 'appPath', 'nodesworkServer', 'port'),
|
61 | });
|
62 | }
|
63 | if (running) {
|
64 | this.options.pid = amOptions.pid;
|
65 | this.options.token = amOptions.token;
|
66 | }
|
67 | else {
|
68 | this.options.pid = null;
|
69 | }
|
70 | this.serverApi = request.defaults({
|
71 | headers: {
|
72 | 'device-token': this.options.token,
|
73 | },
|
74 | baseUrl: this.options.nodesworkServer,
|
75 | json: true,
|
76 | jar: true,
|
77 | });
|
78 | }
|
79 | authenticated() {
|
80 | return this.options.token != null;
|
81 | }
|
82 | |
83 |
|
84 |
|
85 |
|
86 |
|
87 | async authenticate(options) {
|
88 | try {
|
89 | const resp = await request.post({
|
90 | baseUrl: this.options.nodesworkServer,
|
91 | uri: '/v1/u/user/login',
|
92 | body: {
|
93 | email: options.email,
|
94 | password: options.password,
|
95 | },
|
96 | json: true,
|
97 | jar: true,
|
98 | });
|
99 | LOG.debug('Login successfully');
|
100 | }
|
101 | catch (e) {
|
102 | if (e.name === 'RequestError') {
|
103 | throw new utils_1.NodesworkError('Server is not available', {
|
104 | path: this.options.nodesworkServer + '/v1/u/user/login',
|
105 | }, e);
|
106 | }
|
107 | else if (e.statusCode === 401) {
|
108 | throw new utils_1.NodesworkError('Wrong password');
|
109 | }
|
110 | else if (e.statusCode === 422) {
|
111 | throw new utils_1.NodesworkError('Wrong email');
|
112 | }
|
113 | else {
|
114 | throw e;
|
115 | }
|
116 | }
|
117 | try {
|
118 | const mid = machineId();
|
119 | LOG.debug('Got machine id:', mid);
|
120 | const deviceIdentifier = crypto.createHash('md5')
|
121 | .update(mid)
|
122 | .update(options.email)
|
123 | .digest('hex');
|
124 | let operatingSystem = {
|
125 | Darwin: 'MacOS',
|
126 | Windows_NT: 'Windows',
|
127 | Linux: 'Linux',
|
128 | }[os.type()];
|
129 | const device = {
|
130 | deviceType: 'UserDevice',
|
131 | deviceIdentifier,
|
132 | os: operatingSystem,
|
133 | osVersion: os.release(),
|
134 | containerVersion,
|
135 | name: options.deviceName,
|
136 | };
|
137 | LOG.debug('Collected device information:', device);
|
138 | const resp = await request.post({
|
139 | baseUrl: this.options.nodesworkServer,
|
140 | uri: '/v1/u/devices',
|
141 | body: device,
|
142 | json: true,
|
143 | jar: true,
|
144 | });
|
145 | LOG.debug('Device registered successfully', resp);
|
146 | this.options.token = resp.token;
|
147 | this.ls.setItemSync(APPLET_MANAGER_KEY, this.options);
|
148 | LOG.debug('Save token to local', this.options);
|
149 | await this.updateDevice();
|
150 | }
|
151 | catch (e) {
|
152 | if (e.name === 'RequestError') {
|
153 | throw new utils_1.NodesworkError('Server is not available', {
|
154 | path: this.options.nodesworkServer + '/v1/u/user/login',
|
155 | }, e);
|
156 | }
|
157 | else {
|
158 | throw e;
|
159 | }
|
160 | }
|
161 | return;
|
162 | }
|
163 | isStarted() {
|
164 | return this.options.pid != null;
|
165 | }
|
166 | |
167 |
|
168 |
|
169 |
|
170 |
|
171 | async startServer() {
|
172 | if (this.options.pid != null) {
|
173 | console.log('daemon has already started');
|
174 | return;
|
175 | }
|
176 | if (this.options.token == null) {
|
177 | throw errors.UNAUTHENTICATED_ERROR;
|
178 | }
|
179 | await this.checkEnvironment();
|
180 |
|
181 | this.options.pid = process.pid;
|
182 | this.ls.setItemSync(APPLET_MANAGER_KEY, this.options);
|
183 | server_1.app.appletManager = this;
|
184 | server_1.server.listen(this.options.port);
|
185 | socket_1.connectSocket(this.options.nodesworkServer, this.options.token, this);
|
186 | LOG.info(`Server is started at http://localhost:${this.options.port}`);
|
187 | await this.updateDevice();
|
188 | }
|
189 | |
190 |
|
191 |
|
192 |
|
193 |
|
194 | async stopServer() {
|
195 |
|
196 | if (this.options.pid) {
|
197 | process.kill(this.options.pid);
|
198 | this.options.pid = null;
|
199 | await utils_2.sleep(1000);
|
200 | }
|
201 | }
|
202 | async install(options) {
|
203 | const docker = new docker_cli_js_1.Docker();
|
204 | const cmd = `build -t ${imageName(options)} ` +
|
205 | `--build-arg base=${env.DOCKER_NODE_REPO} ` +
|
206 | `--build-arg package=${options.packageName} ` +
|
207 | `--build-arg version=${options.version} ` +
|
208 | `docker/${options.naType}/${options.naVersion}`;
|
209 | LOG.debug('Execute command to install applet', { cmd });
|
210 | try {
|
211 | const result = await docker.command(cmd);
|
212 | LOG.debug('Execute build command log', result);
|
213 | await this.updateDevice();
|
214 | }
|
215 | catch (e) {
|
216 | throw e;
|
217 | }
|
218 | }
|
219 | async images() {
|
220 | const docker = new docker_cli_js_1.Docker();
|
221 | const images = await docker.command('images');
|
222 | return _.chain(images.images)
|
223 | .filter((image) => {
|
224 | const [na, naType, naVersion, ...others] = image.repository.split('-');
|
225 | return na === 'na' && (naType === 'npm') && env.SUPPORTED_NA_NPM_VERSIONS.indexOf(naVersion) >= 0;
|
226 | })
|
227 | .map((image) => {
|
228 | const [na, naType, naVersion, ...others] = image.repository.split('-');
|
229 | return {
|
230 | naType,
|
231 | naVersion,
|
232 | packageName: others.join('-'),
|
233 | version: image.tag,
|
234 | };
|
235 | })
|
236 | .value();
|
237 | }
|
238 | async run(options) {
|
239 | await this.checkEnvironment();
|
240 | const uniqueName = this.name(options);
|
241 | const rmCmd = `rm ${uniqueName}`;
|
242 | LOG.debug('Execute command to rm applet', { cmd: rmCmd });
|
243 | try {
|
244 | const docker = new docker_cli_js_1.Docker();
|
245 | const result = await docker.command(rmCmd);
|
246 | LOG.debug('Execute build command log', result);
|
247 | }
|
248 | catch (e) {
|
249 | LOG.debug('Container does not exist');
|
250 | }
|
251 | const image = imageName(options);
|
252 | const cmd = `run --name ${uniqueName} --network nodeswork -d -e ${applet.constants.environmentKeys.APPLET_ID}=${options.appletId} -e ${applet.constants.environmentKeys.APPLET_TOKEN}=${options.appletToken} ${image}`;
|
253 | LOG.debug('Execute command to run applet', { cmd });
|
254 | try {
|
255 | const docker = new docker_cli_js_1.Docker();
|
256 | const result = await docker.command(cmd);
|
257 | LOG.debug('Execute run command result', result);
|
258 | await this.updateDevice();
|
259 | }
|
260 | catch (e) {
|
261 | LOG.error('Execute run command failed', e);
|
262 | throw e;
|
263 | }
|
264 | }
|
265 | async kill(options) {
|
266 | const uniqueName = this.name(options);
|
267 | const cmd = `stop ${uniqueName}`;
|
268 | LOG.debug('Execute command to run applet', { cmd });
|
269 | try {
|
270 | const docker = new docker_cli_js_1.Docker();
|
271 | const result = await docker.command(cmd);
|
272 | LOG.debug('Execute build command log', result);
|
273 | await this.updateDevice();
|
274 | }
|
275 | catch (e) {
|
276 | throw e;
|
277 | }
|
278 | }
|
279 | async ps() {
|
280 |
|
281 | const psResult = await this.docker.command('ps');
|
282 | const psApplets = _.chain(psResult.containerList)
|
283 | .map((container) => {
|
284 | const image = parseAppletImage(container.names);
|
285 | if (image == null) {
|
286 | return null;
|
287 | }
|
288 | const port = parseMappingPort(container.ports) || 28900;
|
289 | return _.extend(image, { port, status: container.status });
|
290 | })
|
291 | .filter(_.identity)
|
292 | .value();
|
293 | const networkResults = Object.values((await this.docker.command('network inspect nodeswork')).object[0].Containers);
|
294 | return _.filter(psApplets, (psApplet) => {
|
295 | const appletName = this.name(psApplet);
|
296 | const networkResult = _.find(networkResults, (result) => {
|
297 | return result.Name === appletName;
|
298 | });
|
299 | if (networkResult == null) {
|
300 | LOG.warn(`Applet ${appletName} is running but not in the correct network`);
|
301 | return false;
|
302 | }
|
303 | psApplet.ip = networkResult.IPv4Address.split('/')[0];
|
304 | return true;
|
305 | });
|
306 | }
|
307 | async refreshWorkerCrons() {
|
308 | const self = this;
|
309 | try {
|
310 | const userApplets = await this.serverApi.get({
|
311 | uri: '/v1/d/user-applets',
|
312 | });
|
313 | const newJobs = _
|
314 | .chain(userApplets)
|
315 | .map((ua) => {
|
316 | const appletConfig = ua.config.appletConfig;
|
317 | const image = {
|
318 | naType: appletConfig.naType,
|
319 | naVersion: appletConfig.naVersion,
|
320 | packageName: appletConfig.packageName,
|
321 | version: appletConfig.version,
|
322 | };
|
323 | return _.map(appletConfig.workers, (workerConfig) => {
|
324 | const worker = {
|
325 | handler: workerConfig.handler,
|
326 | name: workerConfig.name,
|
327 | };
|
328 | return {
|
329 | jobUUID: uuid([
|
330 | ua.applet._id,
|
331 | ua._id,
|
332 | image.naType,
|
333 | image.naVersion,
|
334 | image.packageName,
|
335 | image.version,
|
336 | worker.handler,
|
337 | worker.name,
|
338 | ].join(':'), UUID_NAMESPACE),
|
339 | appletId: ua.applet._id,
|
340 | userApplet: ua._id,
|
341 | image,
|
342 | worker,
|
343 | schedule: workerConfig.schedule,
|
344 | };
|
345 | });
|
346 | })
|
347 | .flatten()
|
348 | .filter((x) => x.schedule != null)
|
349 | .value();
|
350 | LOG.debug('Fetch applets for current device successfully', newJobs);
|
351 | for (const cron of this.cronJobs) {
|
352 | const u = _.find(newJobs, (newJob) => newJob.jobUUID === cron.jobUUID);
|
353 | if (u == null) {
|
354 | cron.cronJob.stop();
|
355 | LOG.info('Stop cron job successfully', _.omit(cron, 'cronJob'));
|
356 | }
|
357 | }
|
358 | for (const newJob of newJobs) {
|
359 | const cron = _.find(this.cronJobs, (c) => newJob.jobUUID === c.jobUUID);
|
360 | if (cron == null) {
|
361 | const cronJob = (function (c) {
|
362 | try {
|
363 | c.cronJob = new cron_1.CronJob({
|
364 | cronTime: c.schedule,
|
365 | onTick: async () => {
|
366 | LOG.debug('Run cron job', _.omit(c, 'cronJob'));
|
367 | try {
|
368 | await self.executeCronJob(c);
|
369 | LOG.info('Run cron job successfully', _.omit(c, 'cronJob'));
|
370 | }
|
371 | catch (e) {
|
372 | LOG.error('Run cron job failed', _.pick(e, 'name', 'statusCode', 'error', 'message'), _.omit(c, 'cronJob'));
|
373 | }
|
374 | },
|
375 | start: true,
|
376 | });
|
377 | }
|
378 | catch (e) {
|
379 | LOG.error('Create cron job failed', _.omit(c, 'cronJob'));
|
380 | }
|
381 | LOG.info('Create cron job successfully', _.omit(c, 'cronJob'));
|
382 | return c;
|
383 | })(newJob);
|
384 | this.cronJobs.push(cronJob);
|
385 | }
|
386 | }
|
387 | this.cronJobs = _.filter(this.cronJobs, (cronJob) => {
|
388 | return cronJob.cronJob.running;
|
389 | });
|
390 | }
|
391 | catch (e) {
|
392 | throw e;
|
393 | }
|
394 | }
|
395 | async executeCronJob(job) {
|
396 | try {
|
397 | const accounts = await this.serverApi.get({
|
398 | uri: `/v1/d/user-applets/${job.userApplet}/accounts`,
|
399 | });
|
400 | LOG.debug('Fetch accounts successfully', accounts);
|
401 | const payload = {
|
402 | accounts,
|
403 | };
|
404 | const result = await this.work({
|
405 | userApplet: job.userApplet,
|
406 | route: {
|
407 | appletId: job.appletId,
|
408 | naType: job.image.naType,
|
409 | naVersion: job.image.naVersion,
|
410 | packageName: job.image.packageName,
|
411 | version: job.image.version,
|
412 | },
|
413 | worker: job.worker,
|
414 | payload,
|
415 | });
|
416 | LOG.info('Execute cron job successfully.', {
|
417 | job: _.omit(job, 'cronJob'),
|
418 | result,
|
419 | });
|
420 | }
|
421 | catch (e) {
|
422 | throw e;
|
423 | }
|
424 | }
|
425 | async updateExecutionMetrics(executionId, options) {
|
426 | return await this.serverApi.post({
|
427 | uri: `/v1/d/executions/${executionId}/metrics`,
|
428 | body: {
|
429 | dimensions: options.dimensions,
|
430 | name: options.name,
|
431 | value: options.value,
|
432 | },
|
433 | });
|
434 | }
|
435 | async work(options) {
|
436 | LOG.debug('Get work request', options);
|
437 | const execution = await this.serverApi.post({
|
438 | uri: `/v1/d/user-applets/${options.userApplet}/execute`,
|
439 | body: {
|
440 | worker: options.worker,
|
441 | },
|
442 | });
|
443 | const headers = {};
|
444 | headers[applet.constants.headers.request.EXECUTION_ID] = execution._id;
|
445 | const requestOptions = {
|
446 | appletId: options.route.appletId,
|
447 | naType: options.route.naType,
|
448 | naVersion: options.route.naVersion,
|
449 | packageName: options.route.packageName,
|
450 | version: options.route.version,
|
451 | uri: `/workers/${options.worker.handler}/${options.worker.name}`,
|
452 | method: 'POST',
|
453 | body: options.payload,
|
454 | headers,
|
455 | };
|
456 | try {
|
457 | const result = await this.request(requestOptions);
|
458 | this.updateExecutionMetrics(execution._id, {
|
459 | dimensions: {
|
460 | status: 'SUCCESS',
|
461 | },
|
462 | name: 'result',
|
463 | value: utils_1.metrics.Count(1),
|
464 | });
|
465 | return result;
|
466 | }
|
467 | catch (e) {
|
468 | this.updateExecutionMetrics(execution._id, {
|
469 | dimensions: {
|
470 | status: 'ERROR',
|
471 | },
|
472 | name: 'result',
|
473 | value: utils_1.metrics.Count(1),
|
474 | });
|
475 | throw e;
|
476 | }
|
477 | }
|
478 | async request(options) {
|
479 | LOG.info('Get request', { options });
|
480 | const routeAddress = await this.route(options);
|
481 | if (routeAddress == null) {
|
482 | throw new utils_1.NodesworkError('Applet is not running');
|
483 | }
|
484 | const headers = _.extend({}, options.headers);
|
485 | headers[sbase.constants.headers.request.NODESWORK_FORWARDED_TO] = (routeAddress.route);
|
486 | const requestOptions = {
|
487 | uri: routeAddress.target + options.uri,
|
488 | method: options.method,
|
489 | proxy: routeAddress.target,
|
490 | body: options.body,
|
491 | headers,
|
492 | json: true,
|
493 | };
|
494 | LOG.debug('Request options', requestOptions);
|
495 | const resp = await request(requestOptions);
|
496 | LOG.debug('Request response', resp);
|
497 | return resp;
|
498 | }
|
499 | async operateAccount(options) {
|
500 | const requestOptions = {
|
501 | uri: `/v1/d/applets/${options.appletId}/accounts/${options.accountId}/operate`,
|
502 | body: options.body,
|
503 | };
|
504 | return await this.serverApi.post(requestOptions);
|
505 | }
|
506 | async route(options) {
|
507 | if (this.options.dev) {
|
508 | try {
|
509 | const devServer = await request({
|
510 | uri: 'http://localhost:28900/sstats',
|
511 | json: true,
|
512 | });
|
513 | if (devServer.applet &&
|
514 | devServer.applet.packageName === options.packageName &&
|
515 | compareVersion(devServer.applet.packageVersion, options.version) >= 0) {
|
516 | return {
|
517 | route: 'localhost:28900',
|
518 | target: 'http://localhost:28900',
|
519 | };
|
520 | }
|
521 | }
|
522 | catch (e) {
|
523 |
|
524 | }
|
525 | }
|
526 | return {
|
527 | route: `${this.name(options)}:28900`,
|
528 | target: paths_1.containerProxyUrl,
|
529 | };
|
530 | }
|
531 | async updateDevice() {
|
532 | if (this.options.token == null) {
|
533 | throw errors.UNAUTHENTICATED_ERROR;
|
534 | }
|
535 | const installedApplets = await this.images();
|
536 | const runningApplets = await this.ps();
|
537 | try {
|
538 | const resp = await this.serverApi.post({
|
539 | uri: '/v1/d/devices',
|
540 | body: {
|
541 | installedApplets,
|
542 | runningApplets,
|
543 | },
|
544 | });
|
545 | LOG.debug('Update device successfully');
|
546 | }
|
547 | catch (e) {
|
548 | throw e;
|
549 | }
|
550 | await this.refreshWorkerCrons();
|
551 | }
|
552 | async checkEnvironment() {
|
553 |
|
554 | const networks = await this.docker.command('network ls');
|
555 | const targetNetwork = _.find(networks.network, (c) => c.name === 'nodeswork');
|
556 | if (targetNetwork == null) {
|
557 | LOG.debug('network is not setup, creating');
|
558 | await this.docker.command('network create nodeswork');
|
559 | }
|
560 | const inspect = await this.docker.command('network inspect nodeswork');
|
561 | LOG.debug('inspecting network', inspect.object[0]);
|
562 | const IPAMConfig = inspect.object[0].IPAM.Config[0];
|
563 | this.network = {
|
564 | subnet: IPAMConfig.Subnet,
|
565 | gateway: IPAMConfig.Gateway,
|
566 | containers: inspect.object[0].Containers,
|
567 | };
|
568 | LOG.debug('Network configuration', this.network);
|
569 |
|
570 |
|
571 | const containers = await this.docker.command('ps');
|
572 | const proxyContainer = _.find(containers.containerList, (container) => container.names === 'nodeswork-container-proxy');
|
573 | if (proxyContainer == null) {
|
574 | LOG.debug('Container proxy is not running, starting');
|
575 | await this.installContainerProxy();
|
576 | }
|
577 | else {
|
578 | const version = proxyContainer.image.split(':')[1];
|
579 | const lVersion = await latestVersion('@nodeswork/container-proxy');
|
580 | this.containerProxy = {
|
581 | version,
|
582 | latestVersion: lVersion,
|
583 | };
|
584 | }
|
585 | const proxyInNetwork = _.find(this.network.containers, (container) => {
|
586 | return container.Name === 'nodeswork-container-proxy';
|
587 | });
|
588 | if (proxyInNetwork == null) {
|
589 | LOG.debug('Proxy container is not in network');
|
590 | await this.docker.command(`network connect nodeswork nodeswork-container-proxy`);
|
591 | }
|
592 | LOG.debug('Container Proxy configuration', this.containerProxy);
|
593 |
|
594 | LOG.debug('Environment setup correctly');
|
595 | }
|
596 | async ensureMongo(options) {
|
597 | LOG.debug('Ensure mongo', options);
|
598 | const name = `${options.prefix}-mongo`;
|
599 | let containers = await this.docker.command('ps');
|
600 | let container = _.find(containers.containerList, (c) => {
|
601 | return c.names === name;
|
602 | });
|
603 | if (container != null) {
|
604 | LOG.debug('Mongo is already running');
|
605 | return options.port;
|
606 | }
|
607 | LOG.debug('Mongo is not running');
|
608 | containers = await this.docker.command('ps -a');
|
609 | container = _.find(containers.containerList, (c) => {
|
610 | return c.names === name;
|
611 | });
|
612 | if (container != null) {
|
613 | LOG.debug('Mongo is stopped, starting');
|
614 | await this.docker.command(`start ${name}`);
|
615 | return options.port;
|
616 | }
|
617 | LOG.debug('Start Mongo instance');
|
618 | await this.docker.command(`run --name ${name} -p ${options.port}:27017 -d mongo`);
|
619 | LOG.debug('Mongo is running');
|
620 | return options.port;
|
621 | }
|
622 | name(options) {
|
623 | return `na-${options.naType}-${options.naVersion}-${options.packageName}_${options.version}-${options.appletId}`;
|
624 | }
|
625 | async installContainerProxy() {
|
626 | const version = await latestVersion('@nodeswork/container-proxy');
|
627 | LOG.debug('Fetched latest version container-proxy', { version });
|
628 | const output = await this.docker.command(`build -t nodeswork-container-proxy:${version} docker/container-proxy --build-arg version=${version} --build-arg base=${env.DOCKER_NODE_REPO}`);
|
629 | LOG.debug('Building container proxy', output);
|
630 | try {
|
631 | await this.docker.command(`rm nodeswork-container-proxy`);
|
632 | }
|
633 | catch (e) {
|
634 | LOG.debug('Remove container proxy error', e);
|
635 | }
|
636 | try {
|
637 |
|
638 | await this.docker.command(`run --name nodeswork-container-proxy -d -e NAM_HOST=172.16.222.111:28310 -e SUB_NET=${this.network.subnet} -p 28320:28320 nodeswork-container-proxy:${version}`);
|
639 | }
|
640 | catch (e) {
|
641 | LOG.debug('Remove container proxy error', e);
|
642 | }
|
643 | this.containerProxy = { version, latestVersion: version };
|
644 | }
|
645 | }
|
646 | exports.AppletManager = AppletManager;
|
647 | function imageName(image) {
|
648 | return `na-${image.naType}-${image.naVersion}-${image.packageName}\
|
649 | :${image.version}`;
|
650 | }
|
651 | function parseAppletImage(name) {
|
652 | const result = NAME_REGEX.exec(name);
|
653 | if (result == null) {
|
654 | return null;
|
655 | }
|
656 | return {
|
657 | naType: result[1],
|
658 | naVersion: result[2],
|
659 | packageName: result[3],
|
660 | version: result[4],
|
661 | appletId: result[5],
|
662 | };
|
663 | }
|
664 | function parseMappingPort(ports) {
|
665 | return parseInt(ports.split(':')[1]);
|
666 | }
|
667 |
|
668 |
|