@underpostnet/underpost 2.8.5 → 2.8.7
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/.github/workflows/ghpkg.yml +1 -1
- package/.github/workflows/npmpkg.yml +1 -1
- package/.github/workflows/pwa-microservices-template.page.yml +1 -1
- package/.vscode/extensions.json +3 -2
- package/.vscode/settings.json +6 -0
- package/CHANGELOG.md +44 -0
- package/Dockerfile +9 -10
- package/README.md +39 -2
- package/bin/build.js +31 -6
- package/bin/deploy.js +1404 -202
- package/bin/file.js +8 -0
- package/bin/hwt.js +0 -10
- package/bin/index.js +1 -187
- package/bin/util.js +0 -7
- package/bin/vs.js +1 -0
- package/cli.md +451 -0
- package/conf.js +0 -2
- package/docker-compose.yml +1 -1
- package/jsdoc.json +1 -1
- package/manifests/calico-custom-resources.yaml +25 -0
- package/manifests/deployment/adminer/deployment.yaml +32 -0
- package/manifests/deployment/adminer/kustomization.yaml +7 -0
- package/manifests/deployment/adminer/service.yaml +13 -0
- package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
- package/manifests/deployment/fastapi/backend-service.yml +19 -0
- package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
- package/manifests/deployment/fastapi/frontend-service.yml +15 -0
- package/manifests/deployment/kafka/deployment.yaml +69 -0
- package/manifests/kind-config-dev.yaml +12 -0
- package/manifests/kubeadm-calico-config.yaml +119 -0
- package/manifests/mongodb/kustomization.yaml +2 -2
- package/manifests/mongodb-4.4/kustomization.yaml +7 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +63 -0
- package/manifests/postgresql/configmap.yaml +9 -0
- package/manifests/postgresql/kustomization.yaml +10 -0
- package/manifests/postgresql/pv.yaml +15 -0
- package/manifests/postgresql/pvc.yaml +13 -0
- package/manifests/{core/underpost-engine-headless-service.yaml → postgresql/service.yaml} +3 -3
- package/manifests/postgresql/statefulset.yaml +37 -0
- package/manifests/valkey/statefulset.yaml +6 -4
- package/package.json +10 -14
- package/src/api/default/default.service.js +1 -1
- package/src/api/user/user.service.js +14 -11
- package/src/cli/cluster.js +298 -63
- package/src/cli/cron.js +39 -8
- package/src/cli/db.js +118 -44
- package/src/cli/deploy.js +312 -102
- package/src/cli/env.js +9 -3
- package/src/cli/fs.js +161 -0
- package/src/cli/image.js +45 -104
- package/src/cli/index.js +312 -0
- package/src/cli/monitor.js +236 -0
- package/src/cli/repository.js +26 -2
- package/src/cli/script.js +25 -1
- package/src/cli/test.js +39 -4
- package/src/client/components/core/Account.js +28 -24
- package/src/client/components/core/Blockchain.js +1 -1
- package/src/client/components/core/CalendarCore.js +14 -73
- package/src/client/components/core/CommonJs.js +54 -2
- package/src/client/components/core/Css.js +0 -1
- package/src/client/components/core/CssCore.js +10 -4
- package/src/client/components/core/Docs.js +1 -2
- package/src/client/components/core/EventsUI.js +3 -3
- package/src/client/components/core/FileExplorer.js +86 -78
- package/src/client/components/core/Input.js +4 -2
- package/src/client/components/core/JoyStick.js +2 -2
- package/src/client/components/core/LoadingAnimation.js +3 -12
- package/src/client/components/core/LogIn.js +3 -3
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Modal.js +44 -14
- package/src/client/components/core/Panel.js +26 -66
- package/src/client/components/core/PanelForm.js +22 -15
- package/src/client/components/core/Recover.js +3 -3
- package/src/client/components/core/RichText.js +1 -11
- package/src/client/components/core/Router.js +3 -1
- package/src/client/components/core/SignUp.js +2 -2
- package/src/client/components/default/RoutesDefault.js +3 -2
- package/src/client/services/core/core.service.js +15 -10
- package/src/client/services/default/default.management.js +45 -38
- package/src/client/ssr/Render.js +6 -1
- package/src/client/ssr/body/CacheControl.js +2 -3
- package/src/client/sw/default.sw.js +3 -3
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/index.js +25 -1
- package/src/mailer/MailerProvider.js +3 -0
- package/src/runtime/lampp/Dockerfile +65 -0
- package/src/server/backup.js +3 -3
- package/src/server/client-build.js +45 -23
- package/src/server/client-formatted.js +2 -1
- package/src/server/conf.js +110 -16
- package/src/server/dns.js +74 -43
- package/src/server/downloader.js +0 -8
- package/src/server/json-schema.js +77 -0
- package/src/server/network.js +7 -122
- package/src/server/peer.js +2 -2
- package/src/server/proxy.js +4 -4
- package/src/server/runtime.js +40 -12
- package/src/server/start.js +122 -0
- package/src/server/valkey.js +25 -11
- package/test/api.test.js +0 -8
- package/manifests/core/kustomization.yaml +0 -11
- package/manifests/core/underpost-engine-backup-access.yaml +0 -16
- package/manifests/core/underpost-engine-backup-pv-pvc.yaml +0 -22
- package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +0 -40
- package/manifests/core/underpost-engine-mongodb-configmap.yaml +0 -26
- package/manifests/core/underpost-engine-statefulset.yaml +0 -91
- package/manifests/valkey/underpost-engine-valkey-service.yaml +0 -17
- package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +0 -39
- /package/manifests/{core/underpost-engine-pv-pvc.yaml → mongodb-4.4/pv-pvc.yaml} +0 -0
package/src/index.js
CHANGED
|
@@ -9,11 +9,14 @@ import UnderpostCron from './cli/cron.js';
|
|
|
9
9
|
import UnderpostDB from './cli/db.js';
|
|
10
10
|
import UnderpostDeploy from './cli/deploy.js';
|
|
11
11
|
import UnderpostRootEnv from './cli/env.js';
|
|
12
|
+
import UnderpostFileStorage from './cli/fs.js';
|
|
12
13
|
import UnderpostImage from './cli/image.js';
|
|
14
|
+
import UnderpostMonitor from './cli/monitor.js';
|
|
13
15
|
import UnderpostRepository from './cli/repository.js';
|
|
14
16
|
import UnderpostScript from './cli/script.js';
|
|
15
17
|
import UnderpostSecret from './cli/secrets.js';
|
|
16
18
|
import UnderpostTest from './cli/test.js';
|
|
19
|
+
import UnderpostStartUp from './server/start.js';
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* Underpost main module methods
|
|
@@ -27,7 +30,7 @@ class Underpost {
|
|
|
27
30
|
* @type {String}
|
|
28
31
|
* @memberof Underpost
|
|
29
32
|
*/
|
|
30
|
-
static version = 'v2.8.
|
|
33
|
+
static version = 'v2.8.7';
|
|
31
34
|
/**
|
|
32
35
|
* Repository cli API
|
|
33
36
|
* @static
|
|
@@ -49,6 +52,13 @@ class Underpost {
|
|
|
49
52
|
* @memberof Underpost
|
|
50
53
|
*/
|
|
51
54
|
static test = UnderpostTest.API;
|
|
55
|
+
/**
|
|
56
|
+
* Underpost Start Up cli API
|
|
57
|
+
* @static
|
|
58
|
+
* @type {UnderpostStartUp.API}
|
|
59
|
+
* @memberof Underpost
|
|
60
|
+
*/
|
|
61
|
+
static start = UnderpostStartUp.API;
|
|
52
62
|
/**
|
|
53
63
|
* Cluster cli API
|
|
54
64
|
* @static
|
|
@@ -98,6 +108,20 @@ class Underpost {
|
|
|
98
108
|
* @memberof Underpost
|
|
99
109
|
*/
|
|
100
110
|
static cron = UnderpostCron.API;
|
|
111
|
+
/**
|
|
112
|
+
* File Storage cli API
|
|
113
|
+
* @static
|
|
114
|
+
* @type {UnderpostFileStorage.API}
|
|
115
|
+
* @memberof Underpost
|
|
116
|
+
*/
|
|
117
|
+
static fs = UnderpostFileStorage.API;
|
|
118
|
+
/**
|
|
119
|
+
* Monitor cli API
|
|
120
|
+
* @static
|
|
121
|
+
* @type {UnderpostMonitor.API}
|
|
122
|
+
* @memberof Underpost
|
|
123
|
+
*/
|
|
124
|
+
static monitor = UnderpostMonitor.API;
|
|
101
125
|
}
|
|
102
126
|
|
|
103
127
|
const up = Underpost;
|
|
@@ -32,6 +32,9 @@ const MailerProvider = {
|
|
|
32
32
|
},
|
|
33
33
|
) {
|
|
34
34
|
try {
|
|
35
|
+
options.transport.tls = {
|
|
36
|
+
rejectUnauthorized: false,
|
|
37
|
+
};
|
|
35
38
|
const { id } = options;
|
|
36
39
|
// Generate test SMTP service account from ethereal.email
|
|
37
40
|
// Only needed if you don't have a real mail account for testing
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
ARG BASE_DEBIAN=buster
|
|
2
|
+
|
|
3
|
+
USER root
|
|
4
|
+
|
|
5
|
+
FROM debian:${BASE_DEBIAN}
|
|
6
|
+
|
|
7
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
8
|
+
|
|
9
|
+
# Set root password to root, format is 'user:password'.
|
|
10
|
+
RUN echo 'root:root' | chpasswd
|
|
11
|
+
|
|
12
|
+
RUN apt-get update --fix-missing
|
|
13
|
+
RUN apt-get upgrade -y
|
|
14
|
+
# install sudo
|
|
15
|
+
RUN apt-get -y install sudo
|
|
16
|
+
# net-tools provides netstat commands
|
|
17
|
+
RUN apt-get -y install curl net-tools
|
|
18
|
+
RUN apt-get -yq install openssh-server supervisor
|
|
19
|
+
# Few handy utilities which are nice to have
|
|
20
|
+
RUN apt-get -y install nano vim less --no-install-recommends
|
|
21
|
+
RUN apt-get clean
|
|
22
|
+
|
|
23
|
+
# install ssh
|
|
24
|
+
RUN mkdir -p /var/run/sshd
|
|
25
|
+
# Allow root login via password
|
|
26
|
+
RUN sed -ri 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
|
|
27
|
+
|
|
28
|
+
# install open ssl git and others tools
|
|
29
|
+
RUN apt-get install -yq --no-install-recommends libssl-dev curl wget git gnupg
|
|
30
|
+
|
|
31
|
+
# install lampp
|
|
32
|
+
RUN curl -Lo xampp-linux-installer.run https://sourceforge.net/projects/xampp/files/XAMPP%20Linux/7.4.33/xampp-linux-x64-7.4.33-0-installer.run?from_af=true
|
|
33
|
+
RUN chmod +x xampp-linux-installer.run
|
|
34
|
+
RUN bash -c './xampp-linux-installer.run'
|
|
35
|
+
RUN ln -sf /opt/lampp/lampp /usr/bin/lampp
|
|
36
|
+
# Enable XAMPP web interface(remove security checks)
|
|
37
|
+
RUN sed -i.bak s'/Require local/Require all granted/g' /opt/lampp/etc/extra/httpd-xampp.conf
|
|
38
|
+
# Enable error display in php
|
|
39
|
+
RUN sed -i.bak s'/display_errors=Off/display_errors=On/g' /opt/lampp/etc/php.ini
|
|
40
|
+
# Enable includes of several configuration files
|
|
41
|
+
RUN mkdir /opt/lampp/apache2/conf.d
|
|
42
|
+
RUN echo "IncludeOptional /opt/lampp/apache2/conf.d/*.conf" >>/opt/lampp/etc/httpd.conf
|
|
43
|
+
# Create a /www folder and a symbolic link to it in /opt/lampp/htdocs. It'll be accessible via http://localhost:[port]/www/
|
|
44
|
+
# This is convenient because it doesn't interfere with xampp, phpmyadmin or other tools in /opt/lampp/htdocs
|
|
45
|
+
# /opt/lampp/etc/httpd.conf
|
|
46
|
+
RUN mkdir /www
|
|
47
|
+
RUN ln -s /www /opt/lampp/htdocs
|
|
48
|
+
|
|
49
|
+
# install nodejs https://github.com/nodesource/distributions/blob/master/README.md#deb
|
|
50
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash -
|
|
51
|
+
RUN apt-get install -y nodejs build-essential
|
|
52
|
+
RUN node --version
|
|
53
|
+
RUN npm --version
|
|
54
|
+
|
|
55
|
+
WORKDIR /home/dd
|
|
56
|
+
|
|
57
|
+
EXPOSE 22
|
|
58
|
+
|
|
59
|
+
EXPOSE 80
|
|
60
|
+
|
|
61
|
+
EXPOSE 443
|
|
62
|
+
|
|
63
|
+
EXPOSE 3000-3100
|
|
64
|
+
|
|
65
|
+
EXPOSE 4000-4100
|
package/src/server/backup.js
CHANGED
|
@@ -9,7 +9,7 @@ dotenv.config();
|
|
|
9
9
|
const logger = loggerFactory(import.meta);
|
|
10
10
|
|
|
11
11
|
class BackUp {
|
|
12
|
-
static callback = async function (deployList, options = {
|
|
12
|
+
static callback = async function (deployList, options = { itc: false, git: false }) {
|
|
13
13
|
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
14
14
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
15
15
|
|
|
@@ -25,8 +25,8 @@ class BackUp {
|
|
|
25
25
|
const deployId = _deployId.trim();
|
|
26
26
|
if (!deployId) continue;
|
|
27
27
|
|
|
28
|
-
if (options.
|
|
29
|
-
shellExec(`
|
|
28
|
+
if (!(options.itc === true)) {
|
|
29
|
+
shellExec(`node bin db ${options.git ? '--git ' : ''}--export ${deployId}`);
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -21,6 +21,7 @@ import swaggerAutoGen from 'swagger-autogen';
|
|
|
21
21
|
import { SitemapStream, streamToPromise } from 'sitemap';
|
|
22
22
|
import { Readable } from 'stream';
|
|
23
23
|
import { buildIcons, buildTextImg, getBufferPngText } from './client-icons.js';
|
|
24
|
+
import Underpost from '../index.js';
|
|
24
25
|
|
|
25
26
|
dotenv.config();
|
|
26
27
|
|
|
@@ -250,20 +251,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
250
251
|
'services',
|
|
251
252
|
baseHost,
|
|
252
253
|
);
|
|
253
|
-
if (module === 'core' && (process.env.NODE_ENV === 'production' || process.argv.includes('static'))) {
|
|
254
|
-
if (apiBaseHost)
|
|
255
|
-
jsSrc = jsSrc.replace(
|
|
256
|
-
'const getBaseHost = () => location.host;',
|
|
257
|
-
`const getBaseHost = () => '${apiBaseHost}';`,
|
|
258
|
-
);
|
|
259
|
-
if (apiBaseProxyPath) {
|
|
260
|
-
jsSrc = jsSrc.replace('${getProxyPath()}api/', `${apiBaseProxyPath}${process.env.BASE_API}/`);
|
|
261
|
-
jsSrc = jsSrc.replace(
|
|
262
|
-
"const getWsBasePath = () => (getProxyPath() !== '/' ? `${getProxyPath()}socket.io/` : undefined);",
|
|
263
|
-
`const getWsBasePath = () => '${apiBaseProxyPath}socket.io/';`,
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
254
|
fs.writeFileSync(
|
|
268
255
|
jsPublicPath,
|
|
269
256
|
minifyBuild || process.env.NODE_ENV === 'production' ? UglifyJS.minify(jsSrc).code : jsSrc,
|
|
@@ -487,7 +474,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
487
474
|
}
|
|
488
475
|
|
|
489
476
|
default:
|
|
490
|
-
ssrBodyComponents += SrrComponent({
|
|
477
|
+
ssrBodyComponents += SrrComponent({
|
|
478
|
+
ssrPath,
|
|
479
|
+
host,
|
|
480
|
+
path,
|
|
481
|
+
ttiLoadTimeLimit,
|
|
482
|
+
version: Underpost.version,
|
|
483
|
+
});
|
|
491
484
|
break;
|
|
492
485
|
}
|
|
493
486
|
}
|
|
@@ -507,6 +500,15 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
507
500
|
ssrPath,
|
|
508
501
|
ssrHeadComponents,
|
|
509
502
|
ssrBodyComponents,
|
|
503
|
+
renderPayload: {
|
|
504
|
+
apiBaseProxyPath,
|
|
505
|
+
apiBaseHost,
|
|
506
|
+
apiBasePath: process.env.BASE_API,
|
|
507
|
+
version: Underpost.version,
|
|
508
|
+
},
|
|
509
|
+
renderApi: {
|
|
510
|
+
JSONweb,
|
|
511
|
+
},
|
|
510
512
|
});
|
|
511
513
|
|
|
512
514
|
fs.writeFileSync(
|
|
@@ -681,6 +683,19 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
681
683
|
root file where the route starts, such as index.js, app.js, routes.js, etc ... */
|
|
682
684
|
|
|
683
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
|
+
}
|
|
684
699
|
}
|
|
685
700
|
|
|
686
701
|
if (client) {
|
|
@@ -707,6 +722,15 @@ root file where the route starts, such as index.js, app.js, routes.js, etc ... *
|
|
|
707
722
|
ssrPath,
|
|
708
723
|
ssrHeadComponents: '',
|
|
709
724
|
ssrBodyComponents: SsrComponent(),
|
|
725
|
+
renderPayload: {
|
|
726
|
+
apiBaseProxyPath,
|
|
727
|
+
apiBaseHost,
|
|
728
|
+
apiBasePath: process.env.BASE_API,
|
|
729
|
+
version: Underpost.version,
|
|
730
|
+
},
|
|
731
|
+
renderApi: {
|
|
732
|
+
JSONweb,
|
|
733
|
+
},
|
|
710
734
|
});
|
|
711
735
|
|
|
712
736
|
const buildPath = `${
|
|
@@ -739,16 +763,14 @@ root file where the route starts, such as index.js, app.js, routes.js, etc ... *
|
|
|
739
763
|
}
|
|
740
764
|
|
|
741
765
|
{
|
|
742
|
-
const
|
|
743
|
-
|
|
766
|
+
const renderPayload = {
|
|
767
|
+
PRE_CACHED_RESOURCES: uniqueArray(PRE_CACHED_RESOURCES),
|
|
768
|
+
PROXY_PATH: path,
|
|
769
|
+
};
|
|
744
770
|
fs.writeFileSync(
|
|
745
771
|
`${rootClientPath}/sw.js`,
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
.replaceAll(`PRE_CACHED_RESOURCES = []`, PRE_CACHED_JSON)
|
|
749
|
-
.replaceAll(`PRE_CACHED_RESOURCES=[]`, PRE_CACHED_JSON)
|
|
750
|
-
.replaceAll(`PROXY_PATH = '/'`, PROXY_PATH)
|
|
751
|
-
.replaceAll(`PROXY_PATH='/'`, PROXY_PATH),
|
|
772
|
+
`self.renderPayload = ${JSONweb(renderPayload)};
|
|
773
|
+
${fs.readFileSync(`${rootClientPath}/sw.js`, 'utf8')}`,
|
|
752
774
|
'utf8',
|
|
753
775
|
);
|
|
754
776
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import fs from 'fs-extra';
|
|
4
4
|
import vm from 'node:vm';
|
|
5
|
+
import Underpost from '../index.js';
|
|
5
6
|
|
|
6
7
|
const srcFormatted = (src) =>
|
|
7
8
|
src
|
|
@@ -49,7 +50,7 @@ const viewFormatted = (src, dists, proxyPath, baseHost = '') => {
|
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
const ssrFactory = async (componentPath = `./src/client/ssr/Render.js`) => {
|
|
52
|
-
const context = { SrrComponent: () => {}, npm_package_version:
|
|
53
|
+
const context = { SrrComponent: () => {}, npm_package_version: Underpost.version };
|
|
53
54
|
vm.createContext(context);
|
|
54
55
|
vm.runInContext(await srcFormatted(fs.readFileSync(componentPath, 'utf8')), context);
|
|
55
56
|
return context.SrrComponent;
|
package/src/server/conf.js
CHANGED
|
@@ -19,17 +19,8 @@ import { DefaultConf } from '../../conf.js';
|
|
|
19
19
|
import read from 'read';
|
|
20
20
|
import splitFile from 'split-file';
|
|
21
21
|
import axios from 'axios';
|
|
22
|
-
import https from 'https';
|
|
23
22
|
import { ssrFactory } from './client-formatted.js';
|
|
24
23
|
|
|
25
|
-
// axios.defaults.baseURL = BASE_URL;
|
|
26
|
-
|
|
27
|
-
// const httpsAgent = new https.Agent({
|
|
28
|
-
// rejectUnauthorized: false,
|
|
29
|
-
// });
|
|
30
|
-
|
|
31
|
-
// axios.defaults.httpsAgent = httpsAgent;
|
|
32
|
-
|
|
33
24
|
colors.enable();
|
|
34
25
|
|
|
35
26
|
dotenv.config();
|
|
@@ -508,6 +499,40 @@ const buildProxyRouter = () => {
|
|
|
508
499
|
return proxyRouter;
|
|
509
500
|
};
|
|
510
501
|
|
|
502
|
+
const pathPortAssignmentFactory = (router, confServer) => {
|
|
503
|
+
const pathPortAssignmentData = {};
|
|
504
|
+
for (const host of Object.keys(confServer)) {
|
|
505
|
+
const pathPortAssignment = [];
|
|
506
|
+
for (const path of Object.keys(confServer[host])) {
|
|
507
|
+
const { peer } = confServer[host][path];
|
|
508
|
+
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
509
|
+
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
510
|
+
// logger.info('', { host, port, path });
|
|
511
|
+
pathPortAssignment.push({
|
|
512
|
+
port,
|
|
513
|
+
path,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
if (peer) {
|
|
517
|
+
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
518
|
+
pathPortAssignment.push({
|
|
519
|
+
port: port + 1,
|
|
520
|
+
path: '/peer',
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
pathPortAssignmentData[host] = pathPortAssignment;
|
|
525
|
+
}
|
|
526
|
+
return pathPortAssignmentData;
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const deployRangePortFactory = (router) => {
|
|
530
|
+
const ports = Object.values(router).map((p) => parseInt(p.split(':')[2]));
|
|
531
|
+
const fromPort = Math.min(...ports);
|
|
532
|
+
const toPort = Math.max(...ports);
|
|
533
|
+
return { ports, fromPort, toPort };
|
|
534
|
+
};
|
|
535
|
+
|
|
511
536
|
const buildKindPorts = (from, to) =>
|
|
512
537
|
range(parseInt(from), parseInt(to))
|
|
513
538
|
.map(
|
|
@@ -598,7 +623,13 @@ const cliSpinner = async (time = 5000, message0, message1, color, type = 'dots')
|
|
|
598
623
|
const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
|
|
599
624
|
|
|
600
625
|
const getDataDeploy = (
|
|
601
|
-
options = {
|
|
626
|
+
options = {
|
|
627
|
+
buildSingleReplica: false,
|
|
628
|
+
deployGroupId: '',
|
|
629
|
+
deployId: '',
|
|
630
|
+
disableSyncEnvPort: false,
|
|
631
|
+
deployIdConcat: [],
|
|
632
|
+
},
|
|
602
633
|
) => {
|
|
603
634
|
let dataDeploy =
|
|
604
635
|
options.deployGroupId === 'dd'
|
|
@@ -610,6 +641,8 @@ const getDataDeploy = (
|
|
|
610
641
|
.map((deployId) => deployId.trim())
|
|
611
642
|
.filter((deployId) => deployId);
|
|
612
643
|
|
|
644
|
+
if (options.deployIdConcat) dataDeploy = dataDeploy.concat(options.deployIdConcat);
|
|
645
|
+
|
|
613
646
|
if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
|
|
614
647
|
|
|
615
648
|
dataDeploy = dataDeploy.map((deployId) => {
|
|
@@ -730,7 +763,7 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
730
763
|
return true;
|
|
731
764
|
};
|
|
732
765
|
|
|
733
|
-
const deployTest = async (dataDeploy) => {
|
|
766
|
+
const deployTest = async (dataDeploy = [{ deployId: 'default' }]) => {
|
|
734
767
|
const failed = [];
|
|
735
768
|
for (const deploy of dataDeploy) {
|
|
736
769
|
const deployServerConfPath = fs.existsSync(`./engine-private/replica/${deploy.deployId}/conf.server.json`)
|
|
@@ -774,6 +807,12 @@ const deployTest = async (dataDeploy) => {
|
|
|
774
807
|
return { failed };
|
|
775
808
|
};
|
|
776
809
|
|
|
810
|
+
const awaitDeployMonitor = async (init = false, deltaMs = 1000) => {
|
|
811
|
+
if (init) fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
812
|
+
await timer(deltaMs);
|
|
813
|
+
if (fs.existsSync(`./tmp/await-deploy`)) return await awaitDeployMonitor();
|
|
814
|
+
};
|
|
815
|
+
|
|
777
816
|
const getDeployGroupId = () => {
|
|
778
817
|
const deployGroupIndexArg = process.argv.findIndex((a) => a.match(`deploy-group:`));
|
|
779
818
|
if (deployGroupIndexArg > -1) return process.argv[deployGroupIndexArg].split(':')[1].trim();
|
|
@@ -843,7 +882,7 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
|
|
|
843
882
|
if (failed.length > 0) {
|
|
844
883
|
for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
|
|
845
884
|
if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
|
|
846
|
-
|
|
885
|
+
await read({ prompt: 'Press enter to retry failed processes\n' });
|
|
847
886
|
currentAttempt++;
|
|
848
887
|
await deployRun(failed, currentAttempt);
|
|
849
888
|
} else logger.info(`Deploy process successfully`);
|
|
@@ -884,6 +923,53 @@ const mergeFile = async (parts = [], outputFilePath) => {
|
|
|
884
923
|
});
|
|
885
924
|
};
|
|
886
925
|
|
|
926
|
+
const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
927
|
+
const confServer = loadReplicas(
|
|
928
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
929
|
+
);
|
|
930
|
+
const hosts = {};
|
|
931
|
+
for (const host of Object.keys(confServer)) {
|
|
932
|
+
hosts[host] = {};
|
|
933
|
+
for (const path of Object.keys(confServer[host])) {
|
|
934
|
+
if (!confServer[host][path].db) continue;
|
|
935
|
+
const { singleReplica, replicas, db } = confServer[host][path];
|
|
936
|
+
const { provider } = db;
|
|
937
|
+
if (singleReplica) {
|
|
938
|
+
for (const replica of replicas) {
|
|
939
|
+
const deployIdReplica = buildReplicaId({ replica, deployId });
|
|
940
|
+
const confServerReplica = JSON.parse(
|
|
941
|
+
fs.readFileSync(`./engine-private/replica/${deployIdReplica}/conf.server.json`, 'utf8'),
|
|
942
|
+
);
|
|
943
|
+
for (const _host of Object.keys(confServerReplica)) {
|
|
944
|
+
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
945
|
+
hosts[host][_path] = { replica: { host, path } };
|
|
946
|
+
confServerReplica[_host][_path].valkey = valkey;
|
|
947
|
+
switch (provider) {
|
|
948
|
+
case 'mongoose':
|
|
949
|
+
confServerReplica[_host][_path].db.host = mongo.host;
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
fs.writeFileSync(
|
|
955
|
+
`./engine-private/replica/${deployIdReplica}/conf.server.json`,
|
|
956
|
+
JSON.stringify(confServerReplica, null, 4),
|
|
957
|
+
'utf8',
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
} else hosts[host][path] = {};
|
|
961
|
+
confServer[host][path].valkey = valkey;
|
|
962
|
+
switch (provider) {
|
|
963
|
+
case 'mongoose':
|
|
964
|
+
confServer[host][path].db.host = mongo.host;
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
970
|
+
return { hosts };
|
|
971
|
+
};
|
|
972
|
+
|
|
887
973
|
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|
|
888
974
|
const { host, path, conf, deployId } = options;
|
|
889
975
|
const { runtime, db, git, directory } = conf[host][path];
|
|
@@ -989,15 +1075,15 @@ const getPathsSSR = (conf) => {
|
|
|
989
1075
|
|
|
990
1076
|
const Cmd = {
|
|
991
1077
|
delete: (deployId) => `pm2 delete ${deployId}`,
|
|
992
|
-
run: (
|
|
1078
|
+
run: () => `npm start`,
|
|
993
1079
|
build: (deployId) => `node bin/deploy build-full-client ${deployId}${process.argv.includes('l') ? ' l' : ''}`,
|
|
994
1080
|
conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
|
|
995
1081
|
replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
|
|
996
1082
|
syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
|
|
997
1083
|
cron: (deployList, jobList, name, expression, options) =>
|
|
998
1084
|
`pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
|
|
999
|
-
options?.
|
|
1000
|
-
}${deployList} ${jobList}`,
|
|
1085
|
+
options?.itc ? `--itc ` : ''
|
|
1086
|
+
}${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1001
1087
|
};
|
|
1002
1088
|
|
|
1003
1089
|
const fixDependencies = async () => {
|
|
@@ -1064,7 +1150,7 @@ const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
|
|
|
1064
1150
|
shellExec(`node bin/deploy valkey-service`);
|
|
1065
1151
|
const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
|
|
1066
1152
|
shellExec(`node bin/deploy conf ${proxyDeployId} production`);
|
|
1067
|
-
shellExec(`
|
|
1153
|
+
shellExec(`npm start ${proxyDeployId} maintenance`);
|
|
1068
1154
|
};
|
|
1069
1155
|
|
|
1070
1156
|
const getNpmRootPath = () =>
|
|
@@ -1074,6 +1160,8 @@ const getNpmRootPath = () =>
|
|
|
1074
1160
|
silent: true,
|
|
1075
1161
|
}).trim();
|
|
1076
1162
|
|
|
1163
|
+
const getUnderpostRootPath = () => `${getNpmRootPath()}/underpost`;
|
|
1164
|
+
|
|
1077
1165
|
const writeEnv = (envPath, envObj) =>
|
|
1078
1166
|
fs.writeFileSync(
|
|
1079
1167
|
envPath,
|
|
@@ -1119,5 +1207,11 @@ export {
|
|
|
1119
1207
|
buildPortProxyRouter,
|
|
1120
1208
|
splitFileFactory,
|
|
1121
1209
|
getNpmRootPath,
|
|
1210
|
+
getUnderpostRootPath,
|
|
1122
1211
|
writeEnv,
|
|
1212
|
+
deployTest,
|
|
1213
|
+
pathPortAssignmentFactory,
|
|
1214
|
+
deployRangePortFactory,
|
|
1215
|
+
awaitDeployMonitor,
|
|
1216
|
+
rebuildConfFactory,
|
|
1123
1217
|
};
|
package/src/server/dns.js
CHANGED
|
@@ -1,38 +1,59 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
-
import https from 'https';
|
|
5
4
|
import validator from 'validator';
|
|
6
|
-
import {
|
|
5
|
+
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
7
6
|
import { loggerFactory } from './logger.js';
|
|
7
|
+
import UnderpostRootEnv from '../cli/env.js';
|
|
8
|
+
import dns from 'node:dns';
|
|
9
|
+
import os from 'node:os';
|
|
8
10
|
import { shellExec } from './process.js';
|
|
9
11
|
|
|
10
|
-
const httpsAgent = new https.Agent({
|
|
11
|
-
rejectUnauthorized: false,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
axios.defaults.httpsAgent = httpsAgent;
|
|
15
|
-
|
|
16
12
|
dotenv.config();
|
|
17
13
|
|
|
18
14
|
const logger = loggerFactory(import.meta);
|
|
19
15
|
|
|
16
|
+
const ip = {
|
|
17
|
+
public: {
|
|
18
|
+
get: async () => await publicIp(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
19
|
+
ipv4: async () => await publicIpv4(), // => '46.5.21.123'
|
|
20
|
+
ipv6: async () => await publicIpv6(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const isInternetConnection = (domain = 'google.com') =>
|
|
25
|
+
new Promise((resolve) => dns.lookup(domain, {}, (err) => resolve(err ? false : true)));
|
|
26
|
+
|
|
27
|
+
// export INTERFACE=$(ip route | grep default | cut -d ' ' -f 5)
|
|
28
|
+
// export IP_ADDRESS=$(ip -4 addr show dev $INTERFACE | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
|
|
29
|
+
const getLocalIPv4Address = () =>
|
|
30
|
+
os.networkInterfaces()[
|
|
31
|
+
shellExec(`ip route | grep default | cut -d ' ' -f 5`, {
|
|
32
|
+
stdout: true,
|
|
33
|
+
silent: true,
|
|
34
|
+
disableLog: true,
|
|
35
|
+
}).trim()
|
|
36
|
+
].find((i) => i.family === 'IPv4').address;
|
|
37
|
+
|
|
20
38
|
class Dns {
|
|
21
39
|
static callback = async function (deployList) {
|
|
22
|
-
//
|
|
23
|
-
// LAN
|
|
40
|
+
// Network topology configuration:
|
|
41
|
+
// LAN -> [NAT-VPS](modem/router device) -> WAN
|
|
24
42
|
// enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
|
|
25
|
-
|
|
43
|
+
|
|
44
|
+
// Enabling DHCP
|
|
45
|
+
// Navigate to Subnets > VLAN > Configure DHCP.
|
|
46
|
+
// Select the appropriate DHCP options (Managed or Relay).
|
|
47
|
+
// Save and apply changes.
|
|
48
|
+
|
|
26
49
|
// verify inet ip proxy server address
|
|
27
50
|
// DHCP (Dynamic Host Configuration Protocol) LAN reserver IP -> MAC ID
|
|
28
51
|
// LAN server or device's local servers port -> 3000-3100 (2999-3101)
|
|
29
52
|
// DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
|
|
30
53
|
// Forward the router's TCP/UDP ports to the LAN device's IP address
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
|
|
35
|
-
const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
|
|
54
|
+
const isOnline = await isInternetConnection();
|
|
55
|
+
|
|
56
|
+
if (!isOnline) return;
|
|
36
57
|
|
|
37
58
|
let testIp;
|
|
38
59
|
|
|
@@ -41,36 +62,44 @@ class Dns {
|
|
|
41
62
|
} catch (error) {
|
|
42
63
|
logger.error(error, { testIp, stack: error.stack });
|
|
43
64
|
}
|
|
44
|
-
const ipFileName = `${deployId}.ip`;
|
|
45
|
-
const currentIp = fs.existsSync(`./engine-private/deploy/${ipFileName}`)
|
|
46
|
-
? fs.readFileSync(`./engine-private/deploy/${ipFileName}`, 'utf8')
|
|
47
|
-
: undefined;
|
|
48
65
|
|
|
49
|
-
|
|
66
|
+
const currentIp = UnderpostRootEnv.API.get('ip');
|
|
67
|
+
|
|
68
|
+
if (validator.isIP(testIp) && currentIp !== testIp) {
|
|
50
69
|
logger.info(`new ip`, testIp);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
UnderpostRootEnv.API.set('monitor-input', 'pause');
|
|
71
|
+
|
|
72
|
+
for (const _deployId of deployList.split(',')) {
|
|
73
|
+
const deployId = _deployId.trim();
|
|
74
|
+
const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
|
|
75
|
+
const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
|
|
76
|
+
const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
|
|
77
|
+
for (const recordType of Object.keys(confCronData.records)) {
|
|
78
|
+
switch (recordType) {
|
|
79
|
+
case 'A':
|
|
80
|
+
for (const dnsProvider of confCronData.records[recordType]) {
|
|
81
|
+
if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
|
|
82
|
+
await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
|
|
86
|
+
default:
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
62
89
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
90
|
+
try {
|
|
91
|
+
const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
|
|
92
|
+
const response = await axios.get(ipUrlTest);
|
|
93
|
+
const verifyIp = response.request.socket.remoteAddress;
|
|
94
|
+
logger.info(ipUrlTest + ' verify ip', verifyIp);
|
|
95
|
+
if (verifyIp === testIp) {
|
|
96
|
+
logger.info('ip updated successfully', testIp);
|
|
97
|
+
UnderpostRootEnv.API.set('ip', testIp);
|
|
98
|
+
UnderpostRootEnv.API.delete('monitor-input');
|
|
99
|
+
} else logger.error('ip not updated', testIp);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.error(error, error.stack);
|
|
102
|
+
logger.error('ip not updated', testIp);
|
|
74
103
|
}
|
|
75
104
|
}
|
|
76
105
|
}
|
|
@@ -101,3 +130,5 @@ class Dns {
|
|
|
101
130
|
}
|
|
102
131
|
|
|
103
132
|
export default Dns;
|
|
133
|
+
|
|
134
|
+
export { Dns, ip, isInternetConnection, getLocalIPv4Address };
|
package/src/server/downloader.js
CHANGED
|
@@ -2,16 +2,8 @@ import axios from 'axios';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { loggerFactory } from './logger.js';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
|
-
import https from 'https';
|
|
6
|
-
|
|
7
5
|
dotenv.config();
|
|
8
6
|
|
|
9
|
-
const httpsAgent = new https.Agent({
|
|
10
|
-
rejectUnauthorized: false,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
axios.defaults.httpsAgent = httpsAgent;
|
|
14
|
-
|
|
15
7
|
const logger = loggerFactory(import.meta);
|
|
16
8
|
|
|
17
9
|
const Downloader = (url, fullPath, options = { method: 'get', responseType: 'stream' }) =>
|