underpost 2.8.85 → 2.8.87
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.
- package/.env.development +7 -2
- package/.env.production +7 -2
- package/.env.test +7 -2
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/release.cd.yml +37 -0
- package/README.md +7 -24
- package/bin/build.js +1 -0
- package/bin/db.js +1 -3
- package/bin/deploy.js +43 -368
- package/bin/file.js +16 -3
- package/bin/util.js +1 -56
- package/cli.md +46 -21
- package/conf.js +3 -3
- package/manifests/deployment/{dd-template-development → dd-default-development}/deployment.yaml +16 -16
- package/manifests/deployment/{dd-template-development → dd-default-development}/proxy.yaml +3 -3
- package/manifests/deployment/mongo-express/deployment.yaml +12 -12
- package/manifests/grafana/deployment.yaml +57 -0
- package/manifests/grafana/kustomization.yaml +7 -0
- package/manifests/grafana/pvc.yaml +12 -0
- package/manifests/grafana/service.yaml +14 -0
- package/manifests/maas/nvim.sh +91 -0
- package/manifests/maas/ssh-cluster-info.sh +14 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/package.json +3 -12
- package/src/api/file/file.service.js +28 -8
- package/src/api/user/user.router.js +31 -5
- package/src/api/user/user.service.js +11 -38
- package/src/cli/cluster.js +45 -25
- package/src/cli/cron.js +12 -45
- package/src/cli/db.js +149 -19
- package/src/cli/deploy.js +41 -110
- package/src/cli/fs.js +1 -0
- package/src/cli/index.js +24 -7
- package/src/cli/monitor.js +1 -4
- package/src/cli/repository.js +15 -6
- package/src/cli/run.js +94 -16
- package/src/client/Default.index.js +0 -2
- package/src/client/components/core/Account.js +6 -2
- package/src/client/components/core/Content.js +11 -7
- package/src/client/components/core/Css.js +5 -1
- package/src/client/components/core/CssCore.js +12 -0
- package/src/client/components/core/FullScreen.js +19 -28
- package/src/client/components/core/Input.js +7 -1
- package/src/client/components/core/LogIn.js +3 -0
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Modal.js +32 -43
- package/src/client/components/core/ObjectLayerEngine.js +229 -4
- package/src/client/components/core/ObjectLayerEngineModal.js +441 -0
- package/src/client/components/core/Recover.js +5 -2
- package/src/client/components/core/Scroll.js +65 -120
- package/src/client/components/core/SignUp.js +1 -0
- package/src/client/components/core/ToggleSwitch.js +15 -1
- package/src/client/components/core/VanillaJs.js +48 -2
- package/src/client/components/default/MenuDefault.js +2 -2
- package/src/client/components/default/RoutesDefault.js +3 -3
- package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +37 -0
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build-live.js +1 -1
- package/src/server/client-build.js +4 -12
- package/src/server/client-dev-server.js +1 -1
- package/src/server/client-icons.js +6 -78
- package/src/server/conf.js +83 -408
- package/src/server/proxy.js +2 -3
- package/src/server/runtime.js +1 -2
- package/src/server/start.js +5 -5
- package/test/api.test.js +3 -2
- package/docker-compose.yml +0 -67
- package/prometheus.yml +0 -36
package/src/server/conf.js
CHANGED
|
@@ -9,17 +9,11 @@ import {
|
|
|
9
9
|
timer,
|
|
10
10
|
} from '../client/components/core/CommonJs.js';
|
|
11
11
|
import * as dir from 'path';
|
|
12
|
-
import cliProgress from 'cli-progress';
|
|
13
|
-
import cliSpinners from 'cli-spinners';
|
|
14
|
-
import logUpdate from 'log-update';
|
|
15
12
|
import colors from 'colors';
|
|
16
13
|
import { loggerFactory } from './logger.js';
|
|
17
14
|
import { shellExec } from './process.js';
|
|
18
15
|
import { DefaultConf } from '../../conf.js';
|
|
19
|
-
import read from 'read';
|
|
20
16
|
import splitFile from 'split-file';
|
|
21
|
-
import axios from 'axios';
|
|
22
|
-
import { ssrFactory } from './client-formatted.js';
|
|
23
17
|
|
|
24
18
|
colors.enable();
|
|
25
19
|
|
|
@@ -27,68 +21,84 @@ dotenv.config();
|
|
|
27
21
|
|
|
28
22
|
const logger = loggerFactory(import.meta);
|
|
29
23
|
|
|
30
|
-
// monitoring: https://app.pm2.io/
|
|
31
|
-
|
|
32
24
|
const Config = {
|
|
33
25
|
default: DefaultConf,
|
|
34
|
-
build: async function (
|
|
35
|
-
if (
|
|
26
|
+
build: async function (deployContext = 'dd-default', deployList, subConf) {
|
|
27
|
+
if (typeof process.argv[2] === 'string' && process.argv[2].startsWith('dd-')) deployContext = process.argv[2];
|
|
36
28
|
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
37
29
|
fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
38
|
-
if (fs.existsSync(`./engine-private/conf/${deployContext}`))
|
|
39
|
-
return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
40
30
|
if (fs.existsSync(`./engine-private/replica/${deployContext}`))
|
|
41
31
|
return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
32
|
+
else if (deployContext.startsWith('dd-')) return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
33
|
+
if (deployContext === 'proxy') Config.buildProxy(deployContext, deployList, subConf);
|
|
34
|
+
},
|
|
35
|
+
deployIdFactory: function (deployId = 'dd-default') {
|
|
36
|
+
if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
38
|
+
logger.info('Build deployId', deployId);
|
|
39
|
+
|
|
40
|
+
const folder = `./engine-private/conf/${deployId}`;
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
`${folder}/.env.production`,
|
|
45
|
+
fs.readFileSync('./.env.production', 'utf8').replaceAll('dd-default', deployId),
|
|
46
|
+
'utf8',
|
|
47
|
+
);
|
|
48
|
+
fs.writeFileSync(
|
|
49
|
+
`${folder}/.env.development`,
|
|
50
|
+
fs.readFileSync('./.env.development', 'utf8').replaceAll('dd-default', deployId),
|
|
51
|
+
'utf8',
|
|
52
|
+
);
|
|
53
|
+
fs.writeFileSync(
|
|
54
|
+
`${folder}/.env.test`,
|
|
55
|
+
fs.readFileSync('./.env.test', 'utf8').replaceAll('dd-default', deployId),
|
|
56
|
+
'utf8',
|
|
57
|
+
);
|
|
58
|
+
fs.writeFileSync(`${folder}/package.json`, fs.readFileSync('./package.json', 'utf8'), 'utf8');
|
|
59
|
+
|
|
60
|
+
this.buildTmpConf(folder);
|
|
61
|
+
|
|
62
|
+
return { deployIdFolder: folder, deployId };
|
|
63
|
+
},
|
|
64
|
+
buildTmpConf: function (folder = './conf') {
|
|
65
|
+
for (const confType of Object.keys(this.default))
|
|
66
|
+
fs.writeFileSync(`${folder}/conf.${confType}.json`, JSON.stringify(this.default[confType], null, 4), 'utf8');
|
|
67
|
+
},
|
|
68
|
+
buildProxy: function (deployContext = 'dd-default', deployList, subConf) {
|
|
69
|
+
if (!deployList) deployList = process.argv[3];
|
|
70
|
+
if (!subConf) subConf = process.argv[4];
|
|
71
|
+
this.default.server = {};
|
|
72
|
+
for (const deployId of deployList.split(',')) {
|
|
73
|
+
let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
74
|
+
const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
75
|
+
? `./engine-private/replica/${deployId}/conf.server.json`
|
|
76
|
+
: `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
|
|
77
|
+
const confDevPath = fs.existsSync(privateConfDevPath)
|
|
78
|
+
? privateConfDevPath
|
|
79
|
+
: `./engine-private/conf/${deployId}/conf.server.dev.json`;
|
|
80
|
+
|
|
81
|
+
if (process.env.NODE_ENV === 'development' && fs.existsSync(confDevPath)) confPath = confDevPath;
|
|
82
|
+
const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
|
|
83
|
+
|
|
84
|
+
for (const host of Object.keys(loadReplicas(serverConf, deployContext, subConf))) {
|
|
85
|
+
if (serverConf[host]['/'])
|
|
86
|
+
this.default.server[host] = {
|
|
87
|
+
...this.default.server[host],
|
|
88
|
+
...serverConf[host],
|
|
89
|
+
};
|
|
90
|
+
else
|
|
91
|
+
this.default.server[host] = {
|
|
92
|
+
...serverConf[host],
|
|
93
|
+
...this.default.server[host],
|
|
94
|
+
};
|
|
73
95
|
}
|
|
74
96
|
}
|
|
75
|
-
|
|
76
|
-
options = {
|
|
77
|
-
...options,
|
|
78
|
-
folder: `./conf`,
|
|
79
|
-
};
|
|
80
|
-
if (!fs.existsSync(options.folder)) fs.mkdirSync(options.folder, { recursive: true });
|
|
81
|
-
for (const confType of Object.keys(this.default)) {
|
|
82
|
-
fs.writeFileSync(
|
|
83
|
-
`${options.folder}/conf.${confType}.json`,
|
|
84
|
-
JSON.stringify(this.default[confType], null, 4),
|
|
85
|
-
'utf8',
|
|
86
|
-
);
|
|
87
|
-
}
|
|
97
|
+
this.buildTmpConf();
|
|
88
98
|
},
|
|
89
99
|
};
|
|
90
100
|
|
|
91
|
-
const loadConf = (deployId, envInput, subConf) => {
|
|
101
|
+
const loadConf = (deployId = 'dd-default', envInput, subConf) => {
|
|
92
102
|
if (deployId === 'current') {
|
|
93
103
|
console.log(process.env.DEPLOY_ID);
|
|
94
104
|
return;
|
|
@@ -107,18 +117,12 @@ const loadConf = (deployId, envInput, subConf) => {
|
|
|
107
117
|
const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
|
|
108
118
|
? `./engine-private/replica/${deployId}`
|
|
109
119
|
: `./engine-private/conf/${deployId}`;
|
|
120
|
+
if (!fs.existsSync(folder)) Config.deployIdFactory(deployId);
|
|
110
121
|
if (!fs.existsSync(`./conf`)) fs.mkdirSync(`./conf`);
|
|
111
|
-
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp
|
|
112
|
-
|
|
113
|
-
if (!isValidDeployId) {
|
|
114
|
-
logger.info(`Save new deploy conf: '${deployId}'`);
|
|
115
|
-
shellExec(`node bin/deploy save ${deployId}`);
|
|
116
|
-
return loadConf(deployId);
|
|
117
|
-
}
|
|
122
|
+
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`);
|
|
123
|
+
|
|
118
124
|
for (const typeConf of Object.keys(Config.default)) {
|
|
119
|
-
let srcConf =
|
|
120
|
-
? fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8')
|
|
121
|
-
: JSON.stringify(Config.default[typeConf]);
|
|
125
|
+
let srcConf = fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8');
|
|
122
126
|
if (process.env.NODE_ENV === 'development' && typeConf === 'server') {
|
|
123
127
|
if (!subConf) subConf = process.argv[3];
|
|
124
128
|
const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
|
|
@@ -493,15 +497,6 @@ const buildProxyRouter = () => {
|
|
|
493
497
|
}
|
|
494
498
|
}
|
|
495
499
|
}
|
|
496
|
-
if (process.argv.includes('maintenance'))
|
|
497
|
-
(async () => {
|
|
498
|
-
globalThis.defaultHtmlSrcMaintenance = (await ssrFactory())({
|
|
499
|
-
title: 'Site in maintenance',
|
|
500
|
-
ssrPath: '/',
|
|
501
|
-
ssrHeadComponents: '',
|
|
502
|
-
ssrBodyComponents: (await ssrFactory(`./src/client/ssr/offline/Maintenance.js`))(),
|
|
503
|
-
});
|
|
504
|
-
})();
|
|
505
500
|
|
|
506
501
|
return proxyRouter;
|
|
507
502
|
};
|
|
@@ -561,16 +556,24 @@ const buildPortProxyRouter = (port, proxyRouter) => {
|
|
|
561
556
|
// build router
|
|
562
557
|
Object.keys(hosts).map((hostKey) => {
|
|
563
558
|
let { host, path, target, proxy, peer } = hosts[hostKey];
|
|
564
|
-
if (process.
|
|
559
|
+
if (process.env.NODE_ENV === 'development') host = `localhost`;
|
|
560
|
+
|
|
561
|
+
if (!proxy.includes(port)) {
|
|
562
|
+
logger.warn('Proxy port not set on conf', { port, host, path, proxy, target });
|
|
563
|
+
if (process.env.NODE_ENV === 'production') {
|
|
564
|
+
logger.warn('Omitting host', { host, path, target });
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
565
568
|
|
|
566
|
-
if (!proxy.includes(port)) return;
|
|
567
569
|
const absoluteHost = [80, 443].includes(port)
|
|
568
570
|
? `${host}${path === '/' ? '' : path}`
|
|
569
571
|
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
570
572
|
|
|
571
|
-
if (
|
|
572
|
-
|
|
573
|
-
|
|
573
|
+
if (absoluteHost in router)
|
|
574
|
+
logger.warn('Overwrite: Absolute host already exists on router', { absoluteHost, target });
|
|
575
|
+
|
|
576
|
+
router[absoluteHost] = target;
|
|
574
577
|
}); // order router
|
|
575
578
|
|
|
576
579
|
if (Object.keys(router).length === 0) return router;
|
|
@@ -582,51 +585,6 @@ const buildPortProxyRouter = (port, proxyRouter) => {
|
|
|
582
585
|
return reOrderRouter;
|
|
583
586
|
};
|
|
584
587
|
|
|
585
|
-
const cliBar = async (time = 5000) => {
|
|
586
|
-
// create new progress bar
|
|
587
|
-
const b = new cliProgress.SingleBar({
|
|
588
|
-
format: 'Delay | {bar} | {percentage}% || {value}/{total} Chunks || Speed: {speed}',
|
|
589
|
-
barCompleteChar: '\u2588',
|
|
590
|
-
barIncompleteChar: '\u2591',
|
|
591
|
-
hideCursor: true,
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
const maxValueDisplay = 200;
|
|
595
|
-
const minValueDisplay = 0;
|
|
596
|
-
const steps = 10;
|
|
597
|
-
const incrementValue = 200 / steps;
|
|
598
|
-
const delayTime = time / steps;
|
|
599
|
-
// initialize the bar - defining payload token "speed" with the default value "N/A"
|
|
600
|
-
b.start(maxValueDisplay, minValueDisplay, {
|
|
601
|
-
speed: 'N/A',
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
// update values
|
|
605
|
-
// b1.increment();
|
|
606
|
-
// b1.update(20);
|
|
607
|
-
|
|
608
|
-
for (const step of range(1, steps)) {
|
|
609
|
-
b.increment(incrementValue);
|
|
610
|
-
await timer(delayTime);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// stop the bar
|
|
614
|
-
b.stop();
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
const cliSpinner = async (time = 5000, message0, message1, color, type = 'dots') => {
|
|
618
|
-
const { frames, interval } = cliSpinners[type];
|
|
619
|
-
const steps = parseInt(time / interval);
|
|
620
|
-
let index = 0;
|
|
621
|
-
for (const step of range(1, steps)) {
|
|
622
|
-
const msg = `${message0 ? message0 : ''}${frames[index]}${message1 ? message1 : ''}`;
|
|
623
|
-
logUpdate(color ? msg[color] : msg);
|
|
624
|
-
await timer(interval);
|
|
625
|
-
index++;
|
|
626
|
-
if (index === frames.length) index = 0;
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
|
-
|
|
630
588
|
const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
|
|
631
589
|
|
|
632
590
|
const getDataDeploy = (
|
|
@@ -635,7 +593,6 @@ const getDataDeploy = (
|
|
|
635
593
|
deployGroupId: '',
|
|
636
594
|
deployId: '',
|
|
637
595
|
disableSyncEnvPort: false,
|
|
638
|
-
deployIdConcat: [],
|
|
639
596
|
},
|
|
640
597
|
) => {
|
|
641
598
|
let dataDeploy =
|
|
@@ -648,8 +605,6 @@ const getDataDeploy = (
|
|
|
648
605
|
.map((deployId) => deployId.trim())
|
|
649
606
|
.filter((deployId) => deployId);
|
|
650
607
|
|
|
651
|
-
if (options.deployIdConcat) dataDeploy = dataDeploy.concat(options.deployIdConcat);
|
|
652
|
-
|
|
653
608
|
if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
|
|
654
609
|
|
|
655
610
|
dataDeploy = dataDeploy.map((deployId) => {
|
|
@@ -770,152 +725,16 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
770
725
|
return true;
|
|
771
726
|
};
|
|
772
727
|
|
|
773
|
-
const deployTest = async (dataDeploy = [{ deployId: 'default' }]) => {
|
|
774
|
-
const failed = [];
|
|
775
|
-
for (const deploy of dataDeploy) {
|
|
776
|
-
const deployServerConfPath = fs.existsSync(`./engine-private/replica/${deploy.deployId}/conf.server.json`)
|
|
777
|
-
? `./engine-private/replica/${deploy.deployId}/conf.server.json`
|
|
778
|
-
: `./engine-private/conf/${deploy.deployId}/conf.server.json`;
|
|
779
|
-
const serverConf = loadReplicas(JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8')));
|
|
780
|
-
let fail = false;
|
|
781
|
-
for (const host of Object.keys(serverConf))
|
|
782
|
-
for (const path of Object.keys(serverConf[host])) {
|
|
783
|
-
const { singleReplica } = serverConf[host][path];
|
|
784
|
-
if (singleReplica) continue;
|
|
785
|
-
const urlTest = `https://${host}${path}`;
|
|
786
|
-
try {
|
|
787
|
-
const result = await axios.get(urlTest, { timeout: 10000 });
|
|
788
|
-
const test = result.data.split('<title>');
|
|
789
|
-
if (test[1])
|
|
790
|
-
logger.info('Success deploy', {
|
|
791
|
-
...deploy,
|
|
792
|
-
result: test[1].split('</title>')[0],
|
|
793
|
-
urlTest,
|
|
794
|
-
});
|
|
795
|
-
else {
|
|
796
|
-
logger.error('Error deploy', {
|
|
797
|
-
...deploy,
|
|
798
|
-
result: result.data,
|
|
799
|
-
urlTest,
|
|
800
|
-
});
|
|
801
|
-
fail = true;
|
|
802
|
-
}
|
|
803
|
-
} catch (error) {
|
|
804
|
-
logger.error('Error deploy', {
|
|
805
|
-
...deploy,
|
|
806
|
-
message: error.message,
|
|
807
|
-
urlTest,
|
|
808
|
-
});
|
|
809
|
-
fail = true;
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
if (fail) failed.push(deploy);
|
|
813
|
-
}
|
|
814
|
-
return { failed };
|
|
815
|
-
};
|
|
816
|
-
|
|
817
728
|
const awaitDeployMonitor = async (init = false, deltaMs = 1000) => {
|
|
818
729
|
if (init) fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
819
730
|
await timer(deltaMs);
|
|
820
731
|
if (fs.existsSync(`./tmp/await-deploy`)) return await awaitDeployMonitor();
|
|
821
732
|
};
|
|
822
733
|
|
|
823
|
-
const getDeployGroupId = () => {
|
|
824
|
-
const deployGroupIndexArg = process.argv.findIndex((a) => a.match(`deploy-group:`));
|
|
825
|
-
if (deployGroupIndexArg > -1) return process.argv[deployGroupIndexArg].split(':')[1].trim();
|
|
826
|
-
return 'dd';
|
|
827
|
-
};
|
|
828
|
-
|
|
829
|
-
const getDeployId = () => {
|
|
830
|
-
const deployIndexArg = process.argv.findIndex((a) => a.match(`deploy-id:`));
|
|
831
|
-
if (deployIndexArg > -1) return process.argv[deployIndexArg].split(':')[1].trim();
|
|
832
|
-
for (const deployId of process.argv) {
|
|
833
|
-
if (fs.existsSync(`./engine-private/conf/${deployId}`)) return deployId;
|
|
834
|
-
else if (fs.existsSync(`./engine-private/replica/${deployId}`)) return deployId;
|
|
835
|
-
}
|
|
836
|
-
return 'default';
|
|
837
|
-
};
|
|
838
|
-
|
|
839
734
|
const getCronBackUpFolder = (host = '', path = '') => {
|
|
840
735
|
return `${host}${path.replace(/\\/g, '/').replace(`/`, '-')}`;
|
|
841
736
|
};
|
|
842
737
|
|
|
843
|
-
const execDeploy = async (options = { deployId: 'default' }, currentAttempt = 1) => {
|
|
844
|
-
const { deployId } = options;
|
|
845
|
-
shellExec(Cmd.delete(deployId));
|
|
846
|
-
shellExec(Cmd.conf(deployId));
|
|
847
|
-
shellExec(Cmd.run(deployId));
|
|
848
|
-
const maxTime = 1000 * 60;
|
|
849
|
-
const minTime = 20 * 1000;
|
|
850
|
-
const intervalTime = 1000;
|
|
851
|
-
return await new Promise(async (resolve) => {
|
|
852
|
-
let currentTime = 0;
|
|
853
|
-
const attempt = () => {
|
|
854
|
-
if (currentTime >= minTime && !fs.existsSync(`./tmp/await-deploy`)) {
|
|
855
|
-
clearInterval(processMonitor);
|
|
856
|
-
return resolve(true);
|
|
857
|
-
}
|
|
858
|
-
cliSpinner(
|
|
859
|
-
intervalTime,
|
|
860
|
-
`[deploy.js] `,
|
|
861
|
-
` Load instance | attempt:${currentAttempt} | elapsed time ${currentTime / 1000}s / ${maxTime / 1000}s`,
|
|
862
|
-
'yellow',
|
|
863
|
-
'material',
|
|
864
|
-
);
|
|
865
|
-
currentTime += intervalTime;
|
|
866
|
-
if (currentTime >= maxTime) {
|
|
867
|
-
clearInterval(processMonitor);
|
|
868
|
-
return resolve(false);
|
|
869
|
-
}
|
|
870
|
-
};
|
|
871
|
-
const processMonitor = setInterval(attempt, intervalTime);
|
|
872
|
-
});
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
const deployRun = async (dataDeploy, currentAttempt = 1) => {
|
|
876
|
-
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
877
|
-
await fixDependencies();
|
|
878
|
-
const maxAttempts = 3;
|
|
879
|
-
for (const deploy of dataDeploy) {
|
|
880
|
-
let currentAttempt = 1;
|
|
881
|
-
const attempt = async () => {
|
|
882
|
-
const success = await execDeploy(deploy, currentAttempt);
|
|
883
|
-
currentAttempt++;
|
|
884
|
-
if (!success && currentAttempt <= maxAttempts) await attempt();
|
|
885
|
-
};
|
|
886
|
-
await attempt();
|
|
887
|
-
}
|
|
888
|
-
const { failed } = await deployTest(dataDeploy);
|
|
889
|
-
if (failed.length > 0) {
|
|
890
|
-
for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
|
|
891
|
-
if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
|
|
892
|
-
await read({ prompt: 'Press enter to retry failed processes\n' });
|
|
893
|
-
currentAttempt++;
|
|
894
|
-
await deployRun(failed, currentAttempt);
|
|
895
|
-
} else logger.info(`Deploy process successfully`);
|
|
896
|
-
};
|
|
897
|
-
|
|
898
|
-
const restoreMacroDb = async (deployGroupId = '', deployId = null) => {
|
|
899
|
-
const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
|
|
900
|
-
for (const deployGroup of dataDeploy) {
|
|
901
|
-
if (deployId && deployGroup.deployId !== deployId) continue;
|
|
902
|
-
if (!deployGroup.replicaHost) {
|
|
903
|
-
const deployServerConfPath = `./engine-private/conf/${deployGroup.deployId}/conf.server.json`;
|
|
904
|
-
const serverConf = JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8'));
|
|
905
|
-
|
|
906
|
-
for (const host of Object.keys(serverConf)) {
|
|
907
|
-
for (const path of Object.keys(serverConf[host])) {
|
|
908
|
-
const { db, singleReplica } = serverConf[host][path];
|
|
909
|
-
if (db && !singleReplica) {
|
|
910
|
-
const cmd = `node bin/db ${host}${path} import ${deployGroup.deployId} cron`;
|
|
911
|
-
shellExec(cmd);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
};
|
|
918
|
-
|
|
919
738
|
const mergeFile = async (parts = [], outputFilePath) => {
|
|
920
739
|
await new Promise((resolve) => {
|
|
921
740
|
splitFile
|
|
@@ -977,99 +796,6 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
977
796
|
return { hosts };
|
|
978
797
|
};
|
|
979
798
|
|
|
980
|
-
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|
|
981
|
-
const { host, path, conf, deployId } = options;
|
|
982
|
-
const { runtime, db, git, directory } = conf[host][path];
|
|
983
|
-
const { provider, name, user, password = '', backupPath = '' } = db;
|
|
984
|
-
|
|
985
|
-
if (['xampp', 'lampp'].includes(runtime)) {
|
|
986
|
-
logger.info('Create database', `node bin/db ${host}${path} create ${deployId}`);
|
|
987
|
-
shellExec(`node bin/db ${host}${path} create ${deployId}`);
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
if (git) {
|
|
991
|
-
if (directory && !fs.existsSync(directory)) fs.mkdirSync(directory, { recursive: true });
|
|
992
|
-
|
|
993
|
-
shellExec(`git clone ${git}`);
|
|
994
|
-
|
|
995
|
-
// fs.mkdirSync(`./public/${host}${path}`, { recursive: true });
|
|
996
|
-
|
|
997
|
-
if (fs.existsSync(`./${git.split('/').pop()}`))
|
|
998
|
-
fs.moveSync(`./${git.split('/').pop()}`, directory ? directory : `./public/${host}${path}`, {
|
|
999
|
-
overwrite: true,
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
let cmd, currentBackupTimestamp, baseBackUpPath;
|
|
1004
|
-
|
|
1005
|
-
if (process.argv.includes('cron')) {
|
|
1006
|
-
baseBackUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
|
|
1007
|
-
|
|
1008
|
-
const files = await fs.readdir(baseBackUpPath, { withFileTypes: true });
|
|
1009
|
-
|
|
1010
|
-
currentBackupTimestamp = files
|
|
1011
|
-
.map((fileObj) => parseInt(fileObj.name))
|
|
1012
|
-
.sort((a, b) => a - b)
|
|
1013
|
-
.reverse()[0];
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
switch (provider) {
|
|
1017
|
-
case 'mariadb':
|
|
1018
|
-
{
|
|
1019
|
-
if (process.argv.includes('cron')) {
|
|
1020
|
-
cmd = `mysql -u ${user} -p${password} ${name} < ${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`;
|
|
1021
|
-
if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`)) {
|
|
1022
|
-
const names = JSON.parse(
|
|
1023
|
-
fs.readFileSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`, 'utf8'),
|
|
1024
|
-
).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
|
|
1025
|
-
|
|
1026
|
-
await mergeFile(names, `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`);
|
|
1027
|
-
}
|
|
1028
|
-
} else {
|
|
1029
|
-
cmd = `mysql -u ${user} -p${password} ${name} < ${
|
|
1030
|
-
backupPath ? backupPath : `./engine-private/sql-backups/${name}.sql`
|
|
1031
|
-
}`;
|
|
1032
|
-
if (
|
|
1033
|
-
fs.existsSync(
|
|
1034
|
-
`${
|
|
1035
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1036
|
-
}/${name}-parths.json`,
|
|
1037
|
-
)
|
|
1038
|
-
) {
|
|
1039
|
-
const names = JSON.parse(
|
|
1040
|
-
fs.readFileSync(
|
|
1041
|
-
`${
|
|
1042
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1043
|
-
}/${name}-parths.json`,
|
|
1044
|
-
'utf8',
|
|
1045
|
-
),
|
|
1046
|
-
).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
|
|
1047
|
-
|
|
1048
|
-
await mergeFile(
|
|
1049
|
-
names,
|
|
1050
|
-
`${
|
|
1051
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1052
|
-
}/${name}.sql`,
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
break;
|
|
1058
|
-
|
|
1059
|
-
case 'mongoose':
|
|
1060
|
-
{
|
|
1061
|
-
if (process.argv.includes('cron')) {
|
|
1062
|
-
cmd = `mongorestore -d ${name} ${baseBackUpPath}/${currentBackupTimestamp}/${name}`;
|
|
1063
|
-
} else cmd = `mongorestore -d ${name} ${backupPath ? backupPath : `./engine-private/mongodb-backup/${name}`}`;
|
|
1064
|
-
}
|
|
1065
|
-
break;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
// logger.info('Restore', cmd);
|
|
1069
|
-
|
|
1070
|
-
return cmd;
|
|
1071
|
-
};
|
|
1072
|
-
|
|
1073
799
|
const getPathsSSR = (conf) => {
|
|
1074
800
|
const paths = ['src/client/ssr/Render.js'];
|
|
1075
801
|
for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
|
|
@@ -1093,37 +819,6 @@ const Cmd = {
|
|
|
1093
819
|
}${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1094
820
|
};
|
|
1095
821
|
|
|
1096
|
-
const fixDependencies = async () => {
|
|
1097
|
-
return;
|
|
1098
|
-
// sed -i "$line_number s,.*,$new_text," "$file"
|
|
1099
|
-
// sed -i "$line_number c \\$new_text" "$file"
|
|
1100
|
-
const dep = fs.readFileSync(`./node_modules/peer/dist/module.mjs`, 'utf8');
|
|
1101
|
-
const errorLine = `import {WebSocketServer as $hSjDC$WebSocketServer} from "ws";`;
|
|
1102
|
-
|
|
1103
|
-
fs.writeFileSync(
|
|
1104
|
-
`./node_modules/peer/dist/module.mjs`,
|
|
1105
|
-
dep.replaceAll(
|
|
1106
|
-
errorLine,
|
|
1107
|
-
`import WebSocketServer from "ws";
|
|
1108
|
-
let $hSjDC$WebSocketServer = WebSocketServer.Server;`,
|
|
1109
|
-
),
|
|
1110
|
-
'utf8',
|
|
1111
|
-
);
|
|
1112
|
-
};
|
|
1113
|
-
|
|
1114
|
-
const maintenanceMiddleware = (req, res, port, proxyRouter) => {
|
|
1115
|
-
if (process.argv.includes('maintenance') && globalThis.defaultHtmlSrcMaintenance) {
|
|
1116
|
-
if (req.method.toUpperCase() === 'GET') {
|
|
1117
|
-
res.set('Content-Type', 'text/html');
|
|
1118
|
-
return res.status(503).send(globalThis.defaultHtmlSrcMaintenance);
|
|
1119
|
-
}
|
|
1120
|
-
return res.status(503).json({
|
|
1121
|
-
status: 'error',
|
|
1122
|
-
message: 'Server is under maintenance',
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
};
|
|
1126
|
-
|
|
1127
822
|
const splitFileFactory = async (name, _path) => {
|
|
1128
823
|
const stats = fs.statSync(_path);
|
|
1129
824
|
const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
|
|
@@ -1152,14 +847,6 @@ const splitFileFactory = async (name, _path) => {
|
|
|
1152
847
|
return false;
|
|
1153
848
|
};
|
|
1154
849
|
|
|
1155
|
-
const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
|
|
1156
|
-
shellExec(`pm2 kill`);
|
|
1157
|
-
shellExec(`node bin/deploy valkey-service`);
|
|
1158
|
-
const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
|
|
1159
|
-
shellExec(`node bin/deploy conf ${proxyDeployId} production`);
|
|
1160
|
-
shellExec(`npm start ${proxyDeployId} maintenance`);
|
|
1161
|
-
};
|
|
1162
|
-
|
|
1163
850
|
const getNpmRootPath = () =>
|
|
1164
851
|
shellExec(`npm root -g`, {
|
|
1165
852
|
stdout: true,
|
|
@@ -1253,22 +940,11 @@ export {
|
|
|
1253
940
|
buildWsSrc,
|
|
1254
941
|
cloneSrcComponents,
|
|
1255
942
|
buildProxyRouter,
|
|
1256
|
-
cliBar,
|
|
1257
|
-
cliSpinner,
|
|
1258
943
|
getDataDeploy,
|
|
1259
944
|
validateTemplatePath,
|
|
1260
945
|
buildReplicaId,
|
|
1261
|
-
restoreMacroDb,
|
|
1262
|
-
getDeployGroupId,
|
|
1263
|
-
execDeploy,
|
|
1264
|
-
deployRun,
|
|
1265
946
|
getCronBackUpFolder,
|
|
1266
|
-
getRestoreCronCmd,
|
|
1267
947
|
mergeFile,
|
|
1268
|
-
fixDependencies,
|
|
1269
|
-
getDeployId,
|
|
1270
|
-
maintenanceMiddleware,
|
|
1271
|
-
setUpProxyMaintenanceServer,
|
|
1272
948
|
getPathsSSR,
|
|
1273
949
|
buildKindPorts,
|
|
1274
950
|
buildPortProxyRouter,
|
|
@@ -1276,7 +952,6 @@ export {
|
|
|
1276
952
|
getNpmRootPath,
|
|
1277
953
|
getUnderpostRootPath,
|
|
1278
954
|
writeEnv,
|
|
1279
|
-
deployTest,
|
|
1280
955
|
pathPortAssignmentFactory,
|
|
1281
956
|
deployRangePortFactory,
|
|
1282
957
|
awaitDeployMonitor,
|
package/src/server/proxy.js
CHANGED
|
@@ -6,7 +6,7 @@ import dotenv from 'dotenv';
|
|
|
6
6
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
7
7
|
import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
8
8
|
import { createSslServer, sslRedirectMiddleware } from './ssl.js';
|
|
9
|
-
import { buildPortProxyRouter, buildProxyRouter
|
|
9
|
+
import { buildPortProxyRouter, buildProxyRouter } from './conf.js';
|
|
10
10
|
import UnderpostStartUp from './start.js';
|
|
11
11
|
|
|
12
12
|
dotenv.config();
|
|
@@ -48,7 +48,6 @@ const buildProxy = async () => {
|
|
|
48
48
|
onProxyReq: (proxyReq, req, res, options) => {
|
|
49
49
|
// https://wtools.io/check-http-status-code
|
|
50
50
|
// http://nexodev.org
|
|
51
|
-
maintenanceMiddleware(req, res, port, proxyRouter);
|
|
52
51
|
sslRedirectMiddleware(req, res, port, proxyRouter);
|
|
53
52
|
},
|
|
54
53
|
pathRewrite: {
|
|
@@ -56,7 +55,7 @@ const buildProxy = async () => {
|
|
|
56
55
|
// '^/target-path': '/',
|
|
57
56
|
},
|
|
58
57
|
};
|
|
59
|
-
|
|
58
|
+
options.router = buildPortProxyRouter(port, proxyRouter);
|
|
60
59
|
|
|
61
60
|
const filter = false
|
|
62
61
|
? (pathname, req) => {
|
package/src/server/runtime.js
CHANGED
|
@@ -18,7 +18,6 @@ import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
|
18
18
|
// import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
19
19
|
import { createPeerServer } from './peer.js';
|
|
20
20
|
import { Lampp } from '../runtime/lampp/Lampp.js';
|
|
21
|
-
import { getDeployId } from './conf.js';
|
|
22
21
|
import { JSONweb, ssrFactory } from './client-formatted.js';
|
|
23
22
|
import Underpost from '../index.js';
|
|
24
23
|
import { createValkeyConnection } from './valkey.js';
|
|
@@ -28,7 +27,7 @@ dotenv.config();
|
|
|
28
27
|
const logger = loggerFactory(import.meta);
|
|
29
28
|
|
|
30
29
|
const buildRuntime = async () => {
|
|
31
|
-
const deployId =
|
|
30
|
+
const deployId = process.env.DEPLOY_ID;
|
|
32
31
|
|
|
33
32
|
const collectDefaultMetrics = promClient.collectDefaultMetrics;
|
|
34
33
|
collectDefaultMetrics();
|