underpost 2.8.84 → 2.8.86
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 +1 -0
- package/.env.production +1 -0
- package/.env.test +1 -0
- package/.github/workflows/{ghpkg.yml → ghpkg.ci.yml} +1 -1
- package/.github/workflows/{npmpkg.yml → npmpkg.ci.yml} +1 -1
- package/.github/workflows/{publish.yml → publish.ci.yml} +1 -1
- package/.github/workflows/{pwa-microservices-template.page.yml → pwa-microservices-template-page.cd.yml} +2 -2
- package/.github/workflows/{pwa-microservices-template.test.yml → pwa-microservices-template-test.ci.yml} +1 -1
- package/.github/workflows/release.cd.yml +37 -0
- package/.vscode/settings.json +0 -1
- package/README.md +16 -10
- package/bin/build.js +15 -5
- package/bin/cyberia0.js +78 -0
- package/bin/db.js +1 -3
- package/bin/deploy.js +29 -431
- package/bin/file.js +26 -9
- package/cli.md +102 -61
- package/conf.js +1 -1
- 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/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/gpu-diag.sh +1 -1
- package/manifests/maas/ssh-cluster-info.sh +14 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/package.json +4 -7
- package/src/api/user/user.router.js +24 -1
- package/src/api/user/user.service.js +9 -38
- package/src/cli/cluster.js +83 -29
- package/src/cli/cron.js +12 -45
- package/src/cli/db.js +149 -0
- package/src/cli/deploy.js +40 -81
- package/src/cli/index.js +29 -6
- package/src/cli/monitor.js +9 -16
- package/src/cli/repository.js +12 -5
- package/src/cli/run.js +175 -7
- package/src/cli/ssh.js +32 -0
- package/src/client/Default.index.js +7 -5
- package/src/client/components/core/Account.js +7 -3
- package/src/client/components/core/Chat.js +1 -1
- package/src/client/components/core/CommonJs.js +24 -22
- package/src/client/components/core/Content.js +12 -12
- package/src/client/components/core/Css.js +262 -18
- package/src/client/components/core/CssCore.js +8 -8
- package/src/client/components/core/Docs.js +14 -61
- package/src/client/components/core/DropDown.js +137 -82
- package/src/client/components/core/EventsUI.js +92 -5
- package/src/client/components/core/Input.js +6 -1
- package/src/client/components/core/LoadingAnimation.js +8 -15
- 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 +601 -137
- package/src/client/components/core/NotificationManager.js +2 -2
- package/src/client/components/core/ObjectLayerEngine.js +638 -0
- package/src/client/components/core/Panel.js +158 -34
- package/src/client/components/core/PanelForm.js +12 -3
- package/src/client/components/core/Recover.js +6 -3
- package/src/client/components/core/Router.js +77 -17
- package/src/client/components/core/Scroll.js +65 -120
- package/src/client/components/core/SignUp.js +1 -0
- package/src/client/components/core/SocketIo.js +3 -3
- package/src/client/components/core/Translate.js +6 -2
- package/src/client/components/core/VanillaJs.js +48 -5
- package/src/client/components/core/Worker.js +3 -1
- package/src/client/components/default/CssDefault.js +17 -3
- package/src/client/components/default/MenuDefault.js +266 -47
- package/src/client/components/default/RoutesDefault.js +8 -14
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/dark.svg +557 -0
- package/src/client/public/default/assets/logo/base-icon.png +0 -0
- package/src/client/public/default/assets/logo/underpost.gif +0 -0
- package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/safari-pinned-tab.svg +24 -0
- package/src/client/ssr/body/DefaultSplashScreen.js +2 -2
- package/src/index.js +9 -1
- package/src/mailer/MailerProvider.js +37 -0
- package/src/monitor.js +24 -0
- package/src/runtime/lampp/Dockerfile +30 -39
- package/src/runtime/lampp/Lampp.js +11 -2
- package/src/server/client-build-docs.js +205 -0
- package/src/server/client-build-live.js +1 -1
- package/src/server/client-build.js +16 -166
- package/src/server/client-dev-server.js +1 -1
- package/src/server/conf.js +14 -277
- package/src/server/proxy.js +1 -2
- package/src/server/start.js +3 -3
- package/src/server/valkey.js +102 -41
- package/docker-compose.yml +0 -67
- package/prometheus.yml +0 -36
|
@@ -17,11 +17,11 @@ import dotenv from 'dotenv';
|
|
|
17
17
|
import AdmZip from 'adm-zip';
|
|
18
18
|
import * as dir from 'path';
|
|
19
19
|
import { shellExec } from './process.js';
|
|
20
|
-
import swaggerAutoGen from 'swagger-autogen';
|
|
21
20
|
import { SitemapStream, streamToPromise } from 'sitemap';
|
|
22
21
|
import { Readable } from 'stream';
|
|
23
22
|
import { buildIcons, buildTextImg, getBufferPngText } from './client-icons.js';
|
|
24
23
|
import Underpost from '../index.js';
|
|
24
|
+
import { buildDocs } from './client-build-docs.js';
|
|
25
25
|
|
|
26
26
|
dotenv.config();
|
|
27
27
|
|
|
@@ -333,14 +333,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
333
333
|
minifyBuild || process.env.NODE_ENV === 'production' ? UglifyJS.minify(jsSrc).code : jsSrc,
|
|
334
334
|
'utf8',
|
|
335
335
|
);
|
|
336
|
-
|
|
337
|
-
// const title = `${metadata && metadata.title ? metadata.title : cap(client)}${
|
|
338
|
-
// view.title ? ` | ${view.title}` : view.path !== '/' ? ` | ${titleFormatted(view.path)}` : ''
|
|
339
|
-
// }`;
|
|
340
|
-
|
|
341
|
-
const title = `${
|
|
342
|
-
view.title ? `${view.title} | ` : view.path !== '/' ? `${titleFormatted(view.path)} | ` : ''
|
|
343
|
-
}${metadata && metadata.title ? metadata.title : cap(client)}`;
|
|
336
|
+
const title = metadata.title ? metadata.title : title;
|
|
344
337
|
|
|
345
338
|
const canonicalURL = `https://${host}${path}${
|
|
346
339
|
view.path === '/' ? (path === '/' ? '' : '/') : path === '/' ? `${view.path.slice(1)}/` : `${view.path}/`
|
|
@@ -441,27 +434,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
441
434
|
case 'CyberiaDefaultSplashScreen':
|
|
442
435
|
case 'NexodevSplashScreen':
|
|
443
436
|
case 'DefaultSplashScreen':
|
|
444
|
-
if (backgroundImage)
|
|
437
|
+
if (backgroundImage)
|
|
445
438
|
ssrHeadComponents += SrrComponent({
|
|
439
|
+
...metadata,
|
|
446
440
|
backgroundImage: (path === '/' ? path : `${path}/`) + backgroundImage,
|
|
447
441
|
});
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// .toString('base64')}`,
|
|
451
|
-
break;
|
|
452
|
-
} else {
|
|
453
|
-
ssrHeadComponents += SrrComponent({ metadata });
|
|
454
|
-
break;
|
|
455
|
-
const bufferBackgroundImage = await getBufferPngText({
|
|
456
|
-
text: ' ',
|
|
457
|
-
textColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
|
|
458
|
-
size: '100x100',
|
|
459
|
-
bgColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
|
|
460
|
-
});
|
|
461
|
-
ssrHeadComponents += SrrComponent({
|
|
462
|
-
backgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
|
|
463
|
-
});
|
|
464
|
-
}
|
|
442
|
+
else ssrHeadComponents += SrrComponent({ metadata });
|
|
443
|
+
break;
|
|
465
444
|
|
|
466
445
|
case 'CyberiaSplashScreenLore': {
|
|
467
446
|
ssrBodyComponents += SrrComponent({
|
|
@@ -557,145 +536,16 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
557
536
|
}
|
|
558
537
|
|
|
559
538
|
if (!enableLiveRebuild && !process.argv.includes('l') && !process.argv.includes('deploy') && docsBuild) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
shellExec(`npm run docs`, { silent: true });
|
|
571
|
-
|
|
572
|
-
// coverage
|
|
573
|
-
if (!fs.existsSync(`./coverage`)) {
|
|
574
|
-
shellExec(`npm test`);
|
|
575
|
-
}
|
|
576
|
-
const coverageBuildPath = `${jsDocsConfig.opts.destination}/coverage`;
|
|
577
|
-
fs.mkdirSync(coverageBuildPath, { recursive: true });
|
|
578
|
-
fs.copySync(`./coverage`, coverageBuildPath);
|
|
579
|
-
|
|
580
|
-
// uml
|
|
581
|
-
// shellExec(`node bin/deploy uml ${host} ${path}`);
|
|
582
|
-
|
|
583
|
-
// https://swagger-autogen.github.io/docs/
|
|
584
|
-
|
|
585
|
-
const basePath = path === '/' ? `${process.env.BASE_API}` : `/${process.env.BASE_API}`;
|
|
586
|
-
|
|
587
|
-
const doc = {
|
|
588
|
-
info: {
|
|
589
|
-
version: packageData.version, // by default: '1.0.0'
|
|
590
|
-
title: metadata?.title ? `${metadata.title}` : 'REST API', // by default: 'REST API'
|
|
591
|
-
description: metadata?.description ? metadata.description : '', // by default: ''
|
|
592
|
-
},
|
|
593
|
-
servers: [
|
|
594
|
-
{
|
|
595
|
-
url:
|
|
596
|
-
process.env.NODE_ENV === 'development'
|
|
597
|
-
? `http://localhost:${port}${path}${basePath}`
|
|
598
|
-
: `https://${host}${path}${basePath}`, // by default: 'http://localhost:3000'
|
|
599
|
-
description: `${process.env.NODE_ENV} server`, // by default: ''
|
|
600
|
-
},
|
|
601
|
-
],
|
|
602
|
-
tags: [
|
|
603
|
-
// by default: empty Array
|
|
604
|
-
{
|
|
605
|
-
name: 'user', // Tag name
|
|
606
|
-
description: 'User API operations', // Tag description
|
|
607
|
-
},
|
|
608
|
-
],
|
|
609
|
-
components: {
|
|
610
|
-
schemas: {
|
|
611
|
-
userRequest: {
|
|
612
|
-
username: 'user123',
|
|
613
|
-
password: 'Password123',
|
|
614
|
-
email: 'user@example.com',
|
|
615
|
-
},
|
|
616
|
-
userResponse: {
|
|
617
|
-
status: 'success',
|
|
618
|
-
data: {
|
|
619
|
-
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7Il9pZCI6IjY2YzM3N2Y1N2Y5OWU1OTY5YjgxZG...',
|
|
620
|
-
user: {
|
|
621
|
-
_id: '66c377f57f99e5969b81de89',
|
|
622
|
-
email: 'user@example.com',
|
|
623
|
-
emailConfirmed: false,
|
|
624
|
-
username: 'user123',
|
|
625
|
-
role: 'user',
|
|
626
|
-
profileImageId: '66c377f57f99e5969b81de87',
|
|
627
|
-
},
|
|
628
|
-
},
|
|
629
|
-
},
|
|
630
|
-
userUpdateResponse: {
|
|
631
|
-
status: 'success',
|
|
632
|
-
data: {
|
|
633
|
-
_id: '66c377f57f99e5969b81de89',
|
|
634
|
-
email: 'user@example.com',
|
|
635
|
-
emailConfirmed: false,
|
|
636
|
-
username: 'user123222',
|
|
637
|
-
role: 'user',
|
|
638
|
-
profileImageId: '66c377f57f99e5969b81de87',
|
|
639
|
-
},
|
|
640
|
-
},
|
|
641
|
-
userGetResponse: {
|
|
642
|
-
status: 'success',
|
|
643
|
-
data: {
|
|
644
|
-
_id: '66c377f57f99e5969b81de89',
|
|
645
|
-
email: 'user@example.com',
|
|
646
|
-
emailConfirmed: false,
|
|
647
|
-
username: 'user123222',
|
|
648
|
-
role: 'user',
|
|
649
|
-
profileImageId: '66c377f57f99e5969b81de87',
|
|
650
|
-
},
|
|
651
|
-
},
|
|
652
|
-
userLogInRequest: {
|
|
653
|
-
email: 'user@example.com',
|
|
654
|
-
password: 'Password123',
|
|
655
|
-
},
|
|
656
|
-
userBadRequestResponse: {
|
|
657
|
-
status: 'error',
|
|
658
|
-
message: 'Bad request. Please check your inputs, and try again',
|
|
659
|
-
},
|
|
660
|
-
},
|
|
661
|
-
securitySchemes: {
|
|
662
|
-
bearerAuth: {
|
|
663
|
-
type: 'http',
|
|
664
|
-
scheme: 'bearer',
|
|
665
|
-
},
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
// plantuml
|
|
671
|
-
logger.info('copy plantuml', `${rootClientPath}/docs/plantuml`);
|
|
672
|
-
fs.copySync(`./src/client/public/default/plantuml`, `${rootClientPath}/docs/plantuml`);
|
|
673
|
-
|
|
674
|
-
logger.warn('build swagger api docs', doc.info);
|
|
675
|
-
|
|
676
|
-
const outputFile = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
|
|
677
|
-
const routes = [];
|
|
678
|
-
for (const api of apis) {
|
|
679
|
-
if (['user'].includes(api)) routes.push(`./src/api/${api}/${api}.router.js`);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
/* NOTE: If you are using the express Router, you must pass in the 'routes' only the
|
|
683
|
-
root file where the route starts, such as index.js, app.js, routes.js, etc ... */
|
|
684
|
-
|
|
685
|
-
await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
|
|
686
|
-
|
|
687
|
-
const htmlFiles = await fs.readdir(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}`);
|
|
688
|
-
for (const htmlFile of htmlFiles) {
|
|
689
|
-
if (htmlFile.match('.html')) {
|
|
690
|
-
fs.writeFileSync(
|
|
691
|
-
`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`,
|
|
692
|
-
fs
|
|
693
|
-
.readFileSync(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`, 'utf8')
|
|
694
|
-
.replaceAll('Tutorials', 'References'),
|
|
695
|
-
'utf8',
|
|
696
|
-
);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
539
|
+
await buildDocs({
|
|
540
|
+
host,
|
|
541
|
+
path,
|
|
542
|
+
port,
|
|
543
|
+
metadata,
|
|
544
|
+
apis,
|
|
545
|
+
publicClientId,
|
|
546
|
+
rootClientPath,
|
|
547
|
+
packageData,
|
|
548
|
+
});
|
|
699
549
|
}
|
|
700
550
|
|
|
701
551
|
if (client) {
|
|
@@ -7,7 +7,7 @@ const logger = loggerFactory(import.meta);
|
|
|
7
7
|
|
|
8
8
|
const createClientDevServer = () => {
|
|
9
9
|
// process.argv.slice(2).join(' ')
|
|
10
|
-
shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}
|
|
10
|
+
shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}`);
|
|
11
11
|
shellExec(
|
|
12
12
|
`env-cmd -f .env.development node src/api ${process.argv[2]}${process.argv[5] ? ` ${process.argv[5]}` : ''}${
|
|
13
13
|
process.argv.includes('static') ? ' static' : ''
|
package/src/server/conf.js
CHANGED
|
@@ -89,14 +89,22 @@ const Config = {
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
const loadConf = (deployId, envInput, subConf) => {
|
|
92
|
+
if (deployId === 'current') {
|
|
93
|
+
console.log(process.env.DEPLOY_ID);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
92
96
|
if (deployId === 'clean') {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
shellExec(`git checkout
|
|
96
|
-
shellExec(`git checkout
|
|
97
|
-
shellExec(`git checkout
|
|
97
|
+
const path = envInput ?? '.';
|
|
98
|
+
fs.removeSync(`${path}/.env`);
|
|
99
|
+
shellExec(`git checkout ${path}/.env.production`);
|
|
100
|
+
shellExec(`git checkout ${path}/.env.development`);
|
|
101
|
+
shellExec(`git checkout ${path}/.env.test`);
|
|
102
|
+
if (fs.existsSync(`${path}/jsdoc.json`)) shellExec(`git checkout ${path}/jsdoc.json`);
|
|
103
|
+
shellExec(`git checkout ${path}/package.json`);
|
|
104
|
+
shellExec(`git checkout ${path}/package-lock.json`);
|
|
98
105
|
return;
|
|
99
106
|
}
|
|
107
|
+
if (!deployId.startsWith('dd-')) deployId = 'dd-default';
|
|
100
108
|
const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
|
|
101
109
|
? `./engine-private/replica/${deployId}`
|
|
102
110
|
: `./engine-private/conf/${deployId}`;
|
|
@@ -763,152 +771,22 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
763
771
|
return true;
|
|
764
772
|
};
|
|
765
773
|
|
|
766
|
-
const deployTest = async (dataDeploy = [{ deployId: 'default' }]) => {
|
|
767
|
-
const failed = [];
|
|
768
|
-
for (const deploy of dataDeploy) {
|
|
769
|
-
const deployServerConfPath = fs.existsSync(`./engine-private/replica/${deploy.deployId}/conf.server.json`)
|
|
770
|
-
? `./engine-private/replica/${deploy.deployId}/conf.server.json`
|
|
771
|
-
: `./engine-private/conf/${deploy.deployId}/conf.server.json`;
|
|
772
|
-
const serverConf = loadReplicas(JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8')));
|
|
773
|
-
let fail = false;
|
|
774
|
-
for (const host of Object.keys(serverConf))
|
|
775
|
-
for (const path of Object.keys(serverConf[host])) {
|
|
776
|
-
const { singleReplica } = serverConf[host][path];
|
|
777
|
-
if (singleReplica) continue;
|
|
778
|
-
const urlTest = `https://${host}${path}`;
|
|
779
|
-
try {
|
|
780
|
-
const result = await axios.get(urlTest, { timeout: 10000 });
|
|
781
|
-
const test = result.data.split('<title>');
|
|
782
|
-
if (test[1])
|
|
783
|
-
logger.info('Success deploy', {
|
|
784
|
-
...deploy,
|
|
785
|
-
result: test[1].split('</title>')[0],
|
|
786
|
-
urlTest,
|
|
787
|
-
});
|
|
788
|
-
else {
|
|
789
|
-
logger.error('Error deploy', {
|
|
790
|
-
...deploy,
|
|
791
|
-
result: result.data,
|
|
792
|
-
urlTest,
|
|
793
|
-
});
|
|
794
|
-
fail = true;
|
|
795
|
-
}
|
|
796
|
-
} catch (error) {
|
|
797
|
-
logger.error('Error deploy', {
|
|
798
|
-
...deploy,
|
|
799
|
-
message: error.message,
|
|
800
|
-
urlTest,
|
|
801
|
-
});
|
|
802
|
-
fail = true;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
if (fail) failed.push(deploy);
|
|
806
|
-
}
|
|
807
|
-
return { failed };
|
|
808
|
-
};
|
|
809
|
-
|
|
810
774
|
const awaitDeployMonitor = async (init = false, deltaMs = 1000) => {
|
|
811
775
|
if (init) fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
812
776
|
await timer(deltaMs);
|
|
813
777
|
if (fs.existsSync(`./tmp/await-deploy`)) return await awaitDeployMonitor();
|
|
814
778
|
};
|
|
815
779
|
|
|
816
|
-
const getDeployGroupId = () => {
|
|
817
|
-
const deployGroupIndexArg = process.argv.findIndex((a) => a.match(`deploy-group:`));
|
|
818
|
-
if (deployGroupIndexArg > -1) return process.argv[deployGroupIndexArg].split(':')[1].trim();
|
|
819
|
-
return 'dd';
|
|
820
|
-
};
|
|
821
|
-
|
|
822
780
|
const getDeployId = () => {
|
|
823
781
|
const deployIndexArg = process.argv.findIndex((a) => a.match(`deploy-id:`));
|
|
824
782
|
if (deployIndexArg > -1) return process.argv[deployIndexArg].split(':')[1].trim();
|
|
825
|
-
|
|
826
|
-
if (fs.existsSync(`./engine-private/conf/${deployId}`)) return deployId;
|
|
827
|
-
else if (fs.existsSync(`./engine-private/replica/${deployId}`)) return deployId;
|
|
828
|
-
}
|
|
829
|
-
return 'default';
|
|
783
|
+
return 'dd-default';
|
|
830
784
|
};
|
|
831
785
|
|
|
832
786
|
const getCronBackUpFolder = (host = '', path = '') => {
|
|
833
787
|
return `${host}${path.replace(/\\/g, '/').replace(`/`, '-')}`;
|
|
834
788
|
};
|
|
835
789
|
|
|
836
|
-
const execDeploy = async (options = { deployId: 'default' }, currentAttempt = 1) => {
|
|
837
|
-
const { deployId } = options;
|
|
838
|
-
shellExec(Cmd.delete(deployId));
|
|
839
|
-
shellExec(Cmd.conf(deployId));
|
|
840
|
-
shellExec(Cmd.run(deployId));
|
|
841
|
-
const maxTime = 1000 * 60;
|
|
842
|
-
const minTime = 20 * 1000;
|
|
843
|
-
const intervalTime = 1000;
|
|
844
|
-
return await new Promise(async (resolve) => {
|
|
845
|
-
let currentTime = 0;
|
|
846
|
-
const attempt = () => {
|
|
847
|
-
if (currentTime >= minTime && !fs.existsSync(`./tmp/await-deploy`)) {
|
|
848
|
-
clearInterval(processMonitor);
|
|
849
|
-
return resolve(true);
|
|
850
|
-
}
|
|
851
|
-
cliSpinner(
|
|
852
|
-
intervalTime,
|
|
853
|
-
`[deploy.js] `,
|
|
854
|
-
` Load instance | attempt:${currentAttempt} | elapsed time ${currentTime / 1000}s / ${maxTime / 1000}s`,
|
|
855
|
-
'yellow',
|
|
856
|
-
'material',
|
|
857
|
-
);
|
|
858
|
-
currentTime += intervalTime;
|
|
859
|
-
if (currentTime >= maxTime) {
|
|
860
|
-
clearInterval(processMonitor);
|
|
861
|
-
return resolve(false);
|
|
862
|
-
}
|
|
863
|
-
};
|
|
864
|
-
const processMonitor = setInterval(attempt, intervalTime);
|
|
865
|
-
});
|
|
866
|
-
};
|
|
867
|
-
|
|
868
|
-
const deployRun = async (dataDeploy, currentAttempt = 1) => {
|
|
869
|
-
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
870
|
-
await fixDependencies();
|
|
871
|
-
const maxAttempts = 3;
|
|
872
|
-
for (const deploy of dataDeploy) {
|
|
873
|
-
let currentAttempt = 1;
|
|
874
|
-
const attempt = async () => {
|
|
875
|
-
const success = await execDeploy(deploy, currentAttempt);
|
|
876
|
-
currentAttempt++;
|
|
877
|
-
if (!success && currentAttempt <= maxAttempts) await attempt();
|
|
878
|
-
};
|
|
879
|
-
await attempt();
|
|
880
|
-
}
|
|
881
|
-
const { failed } = await deployTest(dataDeploy);
|
|
882
|
-
if (failed.length > 0) {
|
|
883
|
-
for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
|
|
884
|
-
if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
|
|
885
|
-
await read({ prompt: 'Press enter to retry failed processes\n' });
|
|
886
|
-
currentAttempt++;
|
|
887
|
-
await deployRun(failed, currentAttempt);
|
|
888
|
-
} else logger.info(`Deploy process successfully`);
|
|
889
|
-
};
|
|
890
|
-
|
|
891
|
-
const restoreMacroDb = async (deployGroupId = '', deployId = null) => {
|
|
892
|
-
const dataDeploy = await getDataDeploy({ deployGroupId, buildSingleReplica: false });
|
|
893
|
-
for (const deployGroup of dataDeploy) {
|
|
894
|
-
if (deployId && deployGroup.deployId !== deployId) continue;
|
|
895
|
-
if (!deployGroup.replicaHost) {
|
|
896
|
-
const deployServerConfPath = `./engine-private/conf/${deployGroup.deployId}/conf.server.json`;
|
|
897
|
-
const serverConf = JSON.parse(fs.readFileSync(deployServerConfPath, 'utf8'));
|
|
898
|
-
|
|
899
|
-
for (const host of Object.keys(serverConf)) {
|
|
900
|
-
for (const path of Object.keys(serverConf[host])) {
|
|
901
|
-
const { db, singleReplica } = serverConf[host][path];
|
|
902
|
-
if (db && !singleReplica) {
|
|
903
|
-
const cmd = `node bin/db ${host}${path} import ${deployGroup.deployId} cron`;
|
|
904
|
-
shellExec(cmd);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
};
|
|
911
|
-
|
|
912
790
|
const mergeFile = async (parts = [], outputFilePath) => {
|
|
913
791
|
await new Promise((resolve) => {
|
|
914
792
|
splitFile
|
|
@@ -970,99 +848,6 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
|
970
848
|
return { hosts };
|
|
971
849
|
};
|
|
972
850
|
|
|
973
|
-
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|
|
974
|
-
const { host, path, conf, deployId } = options;
|
|
975
|
-
const { runtime, db, git, directory } = conf[host][path];
|
|
976
|
-
const { provider, name, user, password = '', backupPath = '' } = db;
|
|
977
|
-
|
|
978
|
-
if (['xampp', 'lampp'].includes(runtime)) {
|
|
979
|
-
logger.info('Create database', `node bin/db ${host}${path} create ${deployId}`);
|
|
980
|
-
shellExec(`node bin/db ${host}${path} create ${deployId}`);
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
if (git) {
|
|
984
|
-
if (directory && !fs.existsSync(directory)) fs.mkdirSync(directory, { recursive: true });
|
|
985
|
-
|
|
986
|
-
shellExec(`git clone ${git}`);
|
|
987
|
-
|
|
988
|
-
// fs.mkdirSync(`./public/${host}${path}`, { recursive: true });
|
|
989
|
-
|
|
990
|
-
if (fs.existsSync(`./${git.split('/').pop()}`))
|
|
991
|
-
fs.moveSync(`./${git.split('/').pop()}`, directory ? directory : `./public/${host}${path}`, {
|
|
992
|
-
overwrite: true,
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
let cmd, currentBackupTimestamp, baseBackUpPath;
|
|
997
|
-
|
|
998
|
-
if (process.argv.includes('cron')) {
|
|
999
|
-
baseBackUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
|
|
1000
|
-
|
|
1001
|
-
const files = await fs.readdir(baseBackUpPath, { withFileTypes: true });
|
|
1002
|
-
|
|
1003
|
-
currentBackupTimestamp = files
|
|
1004
|
-
.map((fileObj) => parseInt(fileObj.name))
|
|
1005
|
-
.sort((a, b) => a - b)
|
|
1006
|
-
.reverse()[0];
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
switch (provider) {
|
|
1010
|
-
case 'mariadb':
|
|
1011
|
-
{
|
|
1012
|
-
if (process.argv.includes('cron')) {
|
|
1013
|
-
cmd = `mysql -u ${user} -p${password} ${name} < ${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`;
|
|
1014
|
-
if (fs.existsSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`)) {
|
|
1015
|
-
const names = JSON.parse(
|
|
1016
|
-
fs.readFileSync(`${baseBackUpPath}/${currentBackupTimestamp}/${name}-parths.json`, 'utf8'),
|
|
1017
|
-
).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
|
|
1018
|
-
|
|
1019
|
-
await mergeFile(names, `${baseBackUpPath}/${currentBackupTimestamp}/${name}.sql`);
|
|
1020
|
-
}
|
|
1021
|
-
} else {
|
|
1022
|
-
cmd = `mysql -u ${user} -p${password} ${name} < ${
|
|
1023
|
-
backupPath ? backupPath : `./engine-private/sql-backups/${name}.sql`
|
|
1024
|
-
}`;
|
|
1025
|
-
if (
|
|
1026
|
-
fs.existsSync(
|
|
1027
|
-
`${
|
|
1028
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1029
|
-
}/${name}-parths.json`,
|
|
1030
|
-
)
|
|
1031
|
-
) {
|
|
1032
|
-
const names = JSON.parse(
|
|
1033
|
-
fs.readFileSync(
|
|
1034
|
-
`${
|
|
1035
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1036
|
-
}/${name}-parths.json`,
|
|
1037
|
-
'utf8',
|
|
1038
|
-
),
|
|
1039
|
-
).map((p) => p.replaceAll(`\\`, '/').replaceAll('C:/', '/').replaceAll('c:/', '/'));
|
|
1040
|
-
|
|
1041
|
-
await mergeFile(
|
|
1042
|
-
names,
|
|
1043
|
-
`${
|
|
1044
|
-
backupPath ? backupPath.split('/').slice(0, -1).join('/') : `./engine-private/sql-backups`
|
|
1045
|
-
}/${name}.sql`,
|
|
1046
|
-
);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
break;
|
|
1051
|
-
|
|
1052
|
-
case 'mongoose':
|
|
1053
|
-
{
|
|
1054
|
-
if (process.argv.includes('cron')) {
|
|
1055
|
-
cmd = `mongorestore -d ${name} ${baseBackUpPath}/${currentBackupTimestamp}/${name}`;
|
|
1056
|
-
} else cmd = `mongorestore -d ${name} ${backupPath ? backupPath : `./engine-private/mongodb-backup/${name}`}`;
|
|
1057
|
-
}
|
|
1058
|
-
break;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
// logger.info('Restore', cmd);
|
|
1062
|
-
|
|
1063
|
-
return cmd;
|
|
1064
|
-
};
|
|
1065
|
-
|
|
1066
851
|
const getPathsSSR = (conf) => {
|
|
1067
852
|
const paths = ['src/client/ssr/Render.js'];
|
|
1068
853
|
for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
|
|
@@ -1086,37 +871,6 @@ const Cmd = {
|
|
|
1086
871
|
}${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1087
872
|
};
|
|
1088
873
|
|
|
1089
|
-
const fixDependencies = async () => {
|
|
1090
|
-
return;
|
|
1091
|
-
// sed -i "$line_number s,.*,$new_text," "$file"
|
|
1092
|
-
// sed -i "$line_number c \\$new_text" "$file"
|
|
1093
|
-
const dep = fs.readFileSync(`./node_modules/peer/dist/module.mjs`, 'utf8');
|
|
1094
|
-
const errorLine = `import {WebSocketServer as $hSjDC$WebSocketServer} from "ws";`;
|
|
1095
|
-
|
|
1096
|
-
fs.writeFileSync(
|
|
1097
|
-
`./node_modules/peer/dist/module.mjs`,
|
|
1098
|
-
dep.replaceAll(
|
|
1099
|
-
errorLine,
|
|
1100
|
-
`import WebSocketServer from "ws";
|
|
1101
|
-
let $hSjDC$WebSocketServer = WebSocketServer.Server;`,
|
|
1102
|
-
),
|
|
1103
|
-
'utf8',
|
|
1104
|
-
);
|
|
1105
|
-
};
|
|
1106
|
-
|
|
1107
|
-
const maintenanceMiddleware = (req, res, port, proxyRouter) => {
|
|
1108
|
-
if (process.argv.includes('maintenance') && globalThis.defaultHtmlSrcMaintenance) {
|
|
1109
|
-
if (req.method.toUpperCase() === 'GET') {
|
|
1110
|
-
res.set('Content-Type', 'text/html');
|
|
1111
|
-
return res.status(503).send(globalThis.defaultHtmlSrcMaintenance);
|
|
1112
|
-
}
|
|
1113
|
-
return res.status(503).json({
|
|
1114
|
-
status: 'error',
|
|
1115
|
-
message: 'Server is under maintenance',
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
};
|
|
1119
|
-
|
|
1120
874
|
const splitFileFactory = async (name, _path) => {
|
|
1121
875
|
const stats = fs.statSync(_path);
|
|
1122
876
|
const maxSizeInBytes = 1024 * 1024 * 50; // 50 mb
|
|
@@ -1145,14 +899,6 @@ const splitFileFactory = async (name, _path) => {
|
|
|
1145
899
|
return false;
|
|
1146
900
|
};
|
|
1147
901
|
|
|
1148
|
-
const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
|
|
1149
|
-
shellExec(`pm2 kill`);
|
|
1150
|
-
shellExec(`node bin/deploy valkey-service`);
|
|
1151
|
-
const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
|
|
1152
|
-
shellExec(`node bin/deploy conf ${proxyDeployId} production`);
|
|
1153
|
-
shellExec(`npm start ${proxyDeployId} maintenance`);
|
|
1154
|
-
};
|
|
1155
|
-
|
|
1156
902
|
const getNpmRootPath = () =>
|
|
1157
903
|
shellExec(`npm root -g`, {
|
|
1158
904
|
stdout: true,
|
|
@@ -1251,17 +997,9 @@ export {
|
|
|
1251
997
|
getDataDeploy,
|
|
1252
998
|
validateTemplatePath,
|
|
1253
999
|
buildReplicaId,
|
|
1254
|
-
restoreMacroDb,
|
|
1255
|
-
getDeployGroupId,
|
|
1256
|
-
execDeploy,
|
|
1257
|
-
deployRun,
|
|
1258
1000
|
getCronBackUpFolder,
|
|
1259
|
-
getRestoreCronCmd,
|
|
1260
1001
|
mergeFile,
|
|
1261
|
-
fixDependencies,
|
|
1262
1002
|
getDeployId,
|
|
1263
|
-
maintenanceMiddleware,
|
|
1264
|
-
setUpProxyMaintenanceServer,
|
|
1265
1003
|
getPathsSSR,
|
|
1266
1004
|
buildKindPorts,
|
|
1267
1005
|
buildPortProxyRouter,
|
|
@@ -1269,7 +1007,6 @@ export {
|
|
|
1269
1007
|
getNpmRootPath,
|
|
1270
1008
|
getUnderpostRootPath,
|
|
1271
1009
|
writeEnv,
|
|
1272
|
-
deployTest,
|
|
1273
1010
|
pathPortAssignmentFactory,
|
|
1274
1011
|
deployRangePortFactory,
|
|
1275
1012
|
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: {
|
package/src/server/start.js
CHANGED
|
@@ -79,11 +79,11 @@ class UnderpostStartUp {
|
|
|
79
79
|
}
|
|
80
80
|
}),
|
|
81
81
|
|
|
82
|
-
async callback(deployId = 'default', env = 'development', options = { build: false, run: false }) {
|
|
82
|
+
async callback(deployId = 'dd-default', env = 'development', options = { build: false, run: false }) {
|
|
83
83
|
if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
|
|
84
84
|
if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
|
|
85
85
|
},
|
|
86
|
-
async build(deployId = 'default', env = 'development') {
|
|
86
|
+
async build(deployId = 'dd-default', env = 'development') {
|
|
87
87
|
const buildBasePath = `/home/dd`;
|
|
88
88
|
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
89
89
|
shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
|
|
@@ -100,7 +100,7 @@ class UnderpostStartUp {
|
|
|
100
100
|
}
|
|
101
101
|
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
102
102
|
},
|
|
103
|
-
async run(deployId = 'default', env = 'development') {
|
|
103
|
+
async run(deployId = 'dd-default', env = 'development') {
|
|
104
104
|
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
105
105
|
if (fs.existsSync(`./engine-private/replica`)) {
|
|
106
106
|
const replicas = await fs.readdir(`./engine-private/replica`);
|