underpost 2.8.62 → 2.8.65
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/Dockerfile +9 -10
- package/bin/build.js +2 -2
- package/bin/deploy.js +40 -2
- package/bin/index.js +39 -18
- package/docker-compose.yml +1 -1
- package/package.json +2 -9
- package/src/api/default/default.service.js +1 -1
- package/src/api/user/user.service.js +14 -11
- package/src/cli/cluster.js +45 -2
- package/src/cli/cron.js +39 -8
- package/src/cli/db.js +18 -8
- package/src/cli/deploy.js +173 -80
- package/src/cli/fs.js +7 -6
- package/src/cli/image.js +39 -101
- package/src/cli/monitor.js +182 -0
- package/src/cli/repository.js +5 -2
- 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 -84
- package/src/client/components/core/CommonJs.js +2 -1
- package/src/client/components/core/Css.js +0 -1
- package/src/client/components/core/CssCore.js +10 -2
- package/src/client/components/core/Docs.js +1 -1
- package/src/client/components/core/EventsUI.js +3 -3
- package/src/client/components/core/FileExplorer.js +86 -78
- package/src/client/components/core/LoadingAnimation.js +1 -17
- 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 +12 -7
- package/src/client/components/core/Panel.js +19 -61
- package/src/client/components/core/PanelForm.js +13 -22
- 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/default/default.management.js +45 -38
- package/src/client/ssr/Render.js +2 -0
- package/src/index.js +18 -2
- package/src/mailer/MailerProvider.js +3 -0
- package/src/runtime/lampp/Dockerfile +65 -0
- package/src/server/conf.js +89 -1
- package/src/server/dns.js +9 -1
- 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 +22 -11
- package/src/server/start.js +123 -0
- package/src/server/valkey.js +25 -11
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loggerFactory } from '../core/Logger.js';
|
|
2
|
+
import { Modal } from '../core/Modal.js';
|
|
2
3
|
import { getProxyPath, s } from '../core/VanillaJs.js';
|
|
3
4
|
|
|
4
5
|
const logger = loggerFactory(import.meta);
|
|
@@ -10,10 +11,10 @@ const RoutesDefault = () => {
|
|
|
10
11
|
return {
|
|
11
12
|
'/': {
|
|
12
13
|
title: 'Home',
|
|
13
|
-
render: () =>
|
|
14
|
+
render: () => Modal.onHomeRouterEvent(),
|
|
14
15
|
upperCase: false,
|
|
15
16
|
},
|
|
16
|
-
'/home': { title: 'home', render: () =>
|
|
17
|
+
'/home': { title: 'home', render: () => Modal.onHomeRouterEvent() },
|
|
17
18
|
'/settings': { title: 'settings', render: () => s(`.main-btn-settings`).click(), translateTitle: true },
|
|
18
19
|
'/log-in': { title: 'log-in', render: () => s(`.main-btn-log-in`).click(), translateTitle: true },
|
|
19
20
|
'/sign-up': { title: 'sign-up', render: () => s(`.main-btn-sign-up`).click(), translateTitle: true },
|
|
@@ -80,36 +80,40 @@ const DefaultManagement = {
|
|
|
80
80
|
class: `in fll section-mp management-table-btn-mini management-table-btn-remove-${id}-${cellRenderId}`,
|
|
81
81
|
})}`;
|
|
82
82
|
setTimeout(() => {
|
|
83
|
-
EventsUI.onClick(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
83
|
+
EventsUI.onClick(
|
|
84
|
+
`.management-table-btn-remove-${id}-${cellRenderId}`,
|
|
85
|
+
async () => {
|
|
86
|
+
const confirmResult = await Modal.RenderConfirm({
|
|
87
|
+
html: async () => {
|
|
88
|
+
return html`
|
|
89
|
+
<div class="in section-mp" style="text-align: center">
|
|
90
|
+
${Translate.Render('confirm-delete-item')}
|
|
91
|
+
${Object.keys(params.data).length > 0
|
|
92
|
+
? html`<br />
|
|
93
|
+
"${options.defaultColKeyFocus
|
|
94
|
+
? getValueFromJoinString(params.data, options.defaultColKeyFocus)
|
|
95
|
+
: params.data[Object.keys(params.data)[0]]}"`
|
|
96
|
+
: ''}
|
|
97
|
+
</div>
|
|
98
|
+
`;
|
|
99
|
+
},
|
|
100
|
+
id: `delete-${params.data._id}`,
|
|
101
|
+
});
|
|
102
|
+
if (confirmResult.status !== 'confirm') return;
|
|
103
|
+
let result;
|
|
104
|
+
if (params.data._id) result = await ServiceProvider.delete({ id: params.data._id });
|
|
105
|
+
else result = { status: 'success' };
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
NotificationManager.Push({
|
|
108
|
+
html: result.status === 'error' ? result.message : Translate.Render('item-success-delete'),
|
|
109
|
+
status: result.status,
|
|
110
|
+
});
|
|
111
|
+
if (result.status === 'success') {
|
|
112
|
+
AgGrid.grids[gridId].applyTransaction({ remove: [params.data] });
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{ context: 'modal' },
|
|
116
|
+
);
|
|
113
117
|
});
|
|
114
118
|
}
|
|
115
119
|
|
|
@@ -220,16 +224,19 @@ const DefaultManagement = {
|
|
|
220
224
|
});
|
|
221
225
|
});
|
|
222
226
|
EventsUI.onClick(`.management-table-btn-clean-${id}`, async () => {
|
|
223
|
-
const confirmResult = await Modal.RenderConfirm(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
const confirmResult = await Modal.RenderConfirm(
|
|
228
|
+
{
|
|
229
|
+
html: async () => {
|
|
230
|
+
return html`
|
|
231
|
+
<div class="in section-mp" style="text-align: center;">
|
|
232
|
+
<strong>${Translate.Render('confirm-delete-all-data')}</strong>
|
|
233
|
+
</div>
|
|
234
|
+
`;
|
|
235
|
+
},
|
|
236
|
+
id: `clean-table-${id}`,
|
|
230
237
|
},
|
|
231
|
-
|
|
232
|
-
|
|
238
|
+
{ context: 'modal' },
|
|
239
|
+
);
|
|
233
240
|
if (confirmResult.status === 'cancelled') return;
|
|
234
241
|
const result = await ServiceProvider.delete();
|
|
235
242
|
NotificationManager.Push({
|
package/src/client/ssr/Render.js
CHANGED
|
@@ -133,6 +133,8 @@ SrrComponent = ({ title, ssrPath, buildId, ssrHeadComponents, ssrBodyComponents,
|
|
|
133
133
|
border: none;
|
|
134
134
|
padding-block: 0;
|
|
135
135
|
padding-inline: 0;
|
|
136
|
+
height: 30px;
|
|
137
|
+
line-height: 30px;
|
|
136
138
|
}
|
|
137
139
|
input::file-selector-button {
|
|
138
140
|
outline: none !important;
|
package/src/index.js
CHANGED
|
@@ -11,10 +11,12 @@ import UnderpostDeploy from './cli/deploy.js';
|
|
|
11
11
|
import UnderpostRootEnv from './cli/env.js';
|
|
12
12
|
import UnderpostFileStorage from './cli/fs.js';
|
|
13
13
|
import UnderpostImage from './cli/image.js';
|
|
14
|
+
import UnderpostMonitor from './cli/monitor.js';
|
|
14
15
|
import UnderpostRepository from './cli/repository.js';
|
|
15
16
|
import UnderpostScript from './cli/script.js';
|
|
16
17
|
import UnderpostSecret from './cli/secrets.js';
|
|
17
18
|
import UnderpostTest from './cli/test.js';
|
|
19
|
+
import UnderpostStartUp from './server/start.js';
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Underpost main module methods
|
|
@@ -28,7 +30,7 @@ class Underpost {
|
|
|
28
30
|
* @type {String}
|
|
29
31
|
* @memberof Underpost
|
|
30
32
|
*/
|
|
31
|
-
static version = 'v2.8.
|
|
33
|
+
static version = 'v2.8.65';
|
|
32
34
|
/**
|
|
33
35
|
* Repository cli API
|
|
34
36
|
* @static
|
|
@@ -50,6 +52,13 @@ class Underpost {
|
|
|
50
52
|
* @memberof Underpost
|
|
51
53
|
*/
|
|
52
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;
|
|
53
62
|
/**
|
|
54
63
|
* Cluster cli API
|
|
55
64
|
* @static
|
|
@@ -103,9 +112,16 @@ class Underpost {
|
|
|
103
112
|
* File Storage cli API
|
|
104
113
|
* @static
|
|
105
114
|
* @type {UnderpostFileStorage.API}
|
|
106
|
-
* @memberof
|
|
115
|
+
* @memberof Underpost
|
|
107
116
|
*/
|
|
108
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;
|
|
109
125
|
}
|
|
110
126
|
|
|
111
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/conf.js
CHANGED
|
@@ -499,6 +499,40 @@ const buildProxyRouter = () => {
|
|
|
499
499
|
return proxyRouter;
|
|
500
500
|
};
|
|
501
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
|
+
|
|
502
536
|
const buildKindPorts = (from, to) =>
|
|
503
537
|
range(parseInt(from), parseInt(to))
|
|
504
538
|
.map(
|
|
@@ -729,7 +763,7 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
729
763
|
return true;
|
|
730
764
|
};
|
|
731
765
|
|
|
732
|
-
const deployTest = async (dataDeploy) => {
|
|
766
|
+
const deployTest = async (dataDeploy = [{ deployId: 'default' }]) => {
|
|
733
767
|
const failed = [];
|
|
734
768
|
for (const deploy of dataDeploy) {
|
|
735
769
|
const deployServerConfPath = fs.existsSync(`./engine-private/replica/${deploy.deployId}/conf.server.json`)
|
|
@@ -773,6 +807,12 @@ const deployTest = async (dataDeploy) => {
|
|
|
773
807
|
return { failed };
|
|
774
808
|
};
|
|
775
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
|
+
|
|
776
816
|
const getDeployGroupId = () => {
|
|
777
817
|
const deployGroupIndexArg = process.argv.findIndex((a) => a.match(`deploy-group:`));
|
|
778
818
|
if (deployGroupIndexArg > -1) return process.argv[deployGroupIndexArg].split(':')[1].trim();
|
|
@@ -883,6 +923,49 @@ const mergeFile = async (parts = [], outputFilePath) => {
|
|
|
883
923
|
});
|
|
884
924
|
};
|
|
885
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
|
+
for (const host of Object.keys(confServer)) {
|
|
931
|
+
for (const path of Object.keys(confServer[host])) {
|
|
932
|
+
if (!confServer[host][path].db) continue;
|
|
933
|
+
const { singleReplica, replicas, db } = confServer[host][path];
|
|
934
|
+
const { provider } = db;
|
|
935
|
+
if (singleReplica) {
|
|
936
|
+
for (const replica of replicas) {
|
|
937
|
+
const deployIdReplica = buildReplicaId({ replica, deployId });
|
|
938
|
+
const confServerReplica = JSON.parse(
|
|
939
|
+
fs.readFileSync(`./engine-private/replica/${deployIdReplica}/conf.server.json`, 'utf8'),
|
|
940
|
+
);
|
|
941
|
+
for (const _host of Object.keys(confServerReplica)) {
|
|
942
|
+
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
943
|
+
confServerReplica[_host][_path].valkey = valkey;
|
|
944
|
+
switch (provider) {
|
|
945
|
+
case 'mongoose':
|
|
946
|
+
confServerReplica[_host][_path].db.host = mongo.host;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
fs.writeFileSync(
|
|
952
|
+
`./engine-private/replica/${deployIdReplica}/conf.server.json`,
|
|
953
|
+
JSON.stringify(confServerReplica, null, 4),
|
|
954
|
+
'utf8',
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
confServer[host][path].valkey = valkey;
|
|
959
|
+
switch (provider) {
|
|
960
|
+
case 'mongoose':
|
|
961
|
+
confServer[host][path].db.host = mongo.host;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
967
|
+
};
|
|
968
|
+
|
|
886
969
|
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|
|
887
970
|
const { host, path, conf, deployId } = options;
|
|
888
971
|
const { runtime, db, git, directory } = conf[host][path];
|
|
@@ -1122,4 +1205,9 @@ export {
|
|
|
1122
1205
|
getNpmRootPath,
|
|
1123
1206
|
getUnderpostRootPath,
|
|
1124
1207
|
writeEnv,
|
|
1208
|
+
deployTest,
|
|
1209
|
+
pathPortAssignmentFactory,
|
|
1210
|
+
deployRangePortFactory,
|
|
1211
|
+
awaitDeployMonitor,
|
|
1212
|
+
rebuildConfFactory,
|
|
1125
1213
|
};
|
package/src/server/dns.js
CHANGED
|
@@ -2,7 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import validator from 'validator';
|
|
5
|
-
import {
|
|
5
|
+
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
6
6
|
import { loggerFactory } from './logger.js';
|
|
7
7
|
import UnderpostRootEnv from '../cli/env.js';
|
|
8
8
|
|
|
@@ -10,6 +10,14 @@ dotenv.config();
|
|
|
10
10
|
|
|
11
11
|
const logger = loggerFactory(import.meta);
|
|
12
12
|
|
|
13
|
+
const ip = {
|
|
14
|
+
public: {
|
|
15
|
+
get: async () => await publicIp(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
16
|
+
ipv4: async () => await publicIpv4(), // => '46.5.21.123'
|
|
17
|
+
ipv6: async () => await publicIpv6(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
13
21
|
class Dns {
|
|
14
22
|
static callback = async function (deployList) {
|
|
15
23
|
// Network topology configuration:
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function isPlainObject(obj) {
|
|
2
|
+
return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const supportType = ['string', 'number', 'array', 'object', 'boolean', 'integer'];
|
|
6
|
+
|
|
7
|
+
function getType(type) {
|
|
8
|
+
if (!type) type = 'string';
|
|
9
|
+
if (supportType.indexOf(type) !== -1) {
|
|
10
|
+
return type;
|
|
11
|
+
}
|
|
12
|
+
return typeof type;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isSchema(object) {
|
|
16
|
+
if (supportType.indexOf(object.type) !== -1) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function handleSchema(json, schema) {
|
|
23
|
+
Object.assign(schema, json);
|
|
24
|
+
if (schema.type === 'object') {
|
|
25
|
+
delete schema.properties;
|
|
26
|
+
parse(json.properties, schema);
|
|
27
|
+
}
|
|
28
|
+
if (schema.type === 'array') {
|
|
29
|
+
delete schema.items;
|
|
30
|
+
schema.items = {};
|
|
31
|
+
parse(json.items, schema.items);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleArray(arr, schema) {
|
|
36
|
+
schema.type = 'array';
|
|
37
|
+
let props = (schema.items = {});
|
|
38
|
+
parse(arr[0], props);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function handleObject(json, schema) {
|
|
42
|
+
if (isSchema(json)) {
|
|
43
|
+
return handleSchema(json, schema);
|
|
44
|
+
}
|
|
45
|
+
schema.type = 'object';
|
|
46
|
+
schema.required = [];
|
|
47
|
+
let props = (schema.properties = {});
|
|
48
|
+
for (let key in json) {
|
|
49
|
+
let item = json[key];
|
|
50
|
+
let curSchema = (props[key] = {});
|
|
51
|
+
if (key[0] === '*') {
|
|
52
|
+
delete props[key];
|
|
53
|
+
key = key.substr(1);
|
|
54
|
+
schema.required.push(key);
|
|
55
|
+
curSchema = props[key] = {};
|
|
56
|
+
}
|
|
57
|
+
parse(item, curSchema);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parse(json, schema) {
|
|
62
|
+
if (Array.isArray(json)) {
|
|
63
|
+
handleArray(json, schema);
|
|
64
|
+
} else if (isPlainObject(json)) {
|
|
65
|
+
handleObject(json, schema);
|
|
66
|
+
} else {
|
|
67
|
+
schema.type = getType(json);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function ejs(data) {
|
|
72
|
+
let JsonSchema = {};
|
|
73
|
+
parse(data, JsonSchema);
|
|
74
|
+
return JsonSchema;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { ejs };
|
package/src/server/network.js
CHANGED
|
@@ -1,123 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
1
|
+
import Underpost from '../index.js';
|
|
4
2
|
import { actionInitLog, loggerFactory } from './logger.js';
|
|
5
|
-
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
6
|
-
import { getDeployId } from './conf.js';
|
|
7
|
-
|
|
8
|
-
// Network Address Translation Management
|
|
9
|
-
|
|
10
|
-
// import dotenv from 'dotenv';
|
|
11
|
-
// dotenv.config();
|
|
12
3
|
|
|
13
4
|
const logger = loggerFactory(import.meta);
|
|
14
5
|
|
|
15
|
-
const ip = {
|
|
16
|
-
public: {
|
|
17
|
-
get: async () => await publicIp(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
18
|
-
ipv4: async () => await publicIpv4(), // => '46.5.21.123'
|
|
19
|
-
ipv6: async () => await publicIpv6(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
let ipInstance = '';
|
|
24
|
-
const networkRouter = {};
|
|
25
|
-
|
|
26
6
|
const logRuntimeRouter = () => {
|
|
27
7
|
const displayLog = {};
|
|
28
8
|
|
|
29
|
-
for (const host of Object.keys(
|
|
30
|
-
for (const path of Object.keys(
|
|
31
|
-
displayLog[
|
|
9
|
+
for (const host of Object.keys(Underpost.deployNetwork))
|
|
10
|
+
for (const path of Object.keys(Underpost.deployNetwork[host]))
|
|
11
|
+
displayLog[Underpost.deployNetwork[host][path].publicHost] = Underpost.deployNetwork[host][path].local;
|
|
32
12
|
|
|
33
13
|
logger.info('Runtime network', displayLog);
|
|
34
14
|
};
|
|
35
15
|
|
|
36
|
-
const saveRuntimeRouter = async () => {
|
|
37
|
-
try {
|
|
38
|
-
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
39
|
-
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
40
|
-
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
41
|
-
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
42
|
-
if (!deployId || !host || !path || !fs.existsSync(confServerPath)) {
|
|
43
|
-
// logger.warn('default deploy instance not found');
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
47
|
-
const { db } = confServer[host][path];
|
|
48
|
-
|
|
49
|
-
let closeConn;
|
|
50
|
-
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
51
|
-
await DataBaseProvider.load({ apis: ['instance'], host, path, db });
|
|
52
|
-
closeConn = true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** @type {import('../api/instance/instance.model.js').InstanceModel} */
|
|
56
|
-
const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
|
|
57
|
-
|
|
58
|
-
for (const _host of Object.keys(networkRouter)) {
|
|
59
|
-
for (const _path of Object.keys(networkRouter[_host])) {
|
|
60
|
-
const body = {
|
|
61
|
-
host: _host,
|
|
62
|
-
path: _path,
|
|
63
|
-
deployId: getDeployId(),
|
|
64
|
-
client: networkRouter[_host][_path].client,
|
|
65
|
-
runtime: networkRouter[_host][_path].runtime,
|
|
66
|
-
port: networkRouter[_host][_path].port,
|
|
67
|
-
apis: networkRouter[_host][_path].apis,
|
|
68
|
-
};
|
|
69
|
-
const instance = await Instance.findOne({ deployId: body.deployId, host: _host, path: _path });
|
|
70
|
-
if (instance) {
|
|
71
|
-
await Instance.findByIdAndUpdate(instance._id, body);
|
|
72
|
-
} else {
|
|
73
|
-
await new Instance(body).save();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
79
|
-
} catch (error) {
|
|
80
|
-
logger.error(error, error.stack);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const netWorkCron = [];
|
|
85
|
-
|
|
86
|
-
const saveRuntimeCron = async () => {
|
|
87
|
-
try {
|
|
88
|
-
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
89
|
-
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
90
|
-
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
91
|
-
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
92
|
-
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
93
|
-
const { db } = confServer[host][path];
|
|
94
|
-
|
|
95
|
-
let closeConn;
|
|
96
|
-
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
97
|
-
await DataBaseProvider.load({ apis: ['cron'], host, path, db });
|
|
98
|
-
closeConn = true;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** @type {import('../api/cron/cron.model.js').CronModel} */
|
|
102
|
-
const Cron = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Cron;
|
|
103
|
-
|
|
104
|
-
// await Cron.insertMany(netWorkCron);
|
|
105
|
-
|
|
106
|
-
for (const cronInstance of netWorkCron) {
|
|
107
|
-
const cron = await Cron.findOne({ deployId: cronInstance.deployId, jobId: cronInstance.jobId });
|
|
108
|
-
if (cron) {
|
|
109
|
-
await Cron.findByIdAndUpdate(cron._id, cronInstance);
|
|
110
|
-
} else {
|
|
111
|
-
await new Cron(cronInstance).save();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
116
|
-
} catch (error) {
|
|
117
|
-
logger.error(error, error.stack);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
16
|
const listenServerFactory = (logic = async () => {}) => {
|
|
122
17
|
return {
|
|
123
18
|
listen: async (...args) => (
|
|
@@ -150,13 +45,12 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
150
45
|
if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
|
|
151
46
|
|
|
152
47
|
server.listen(port, () => {
|
|
153
|
-
if (!
|
|
154
|
-
|
|
48
|
+
if (!Underpost.deployNetwork[host]) Underpost.deployNetwork[host] = {};
|
|
49
|
+
Underpost.deployNetwork[host][path] = {
|
|
155
50
|
meta,
|
|
156
51
|
client,
|
|
157
52
|
runtime,
|
|
158
53
|
port,
|
|
159
|
-
public: `http://${ipInstance}:${port}${path}`,
|
|
160
54
|
publicHost:
|
|
161
55
|
port === 80
|
|
162
56
|
? `http://${host}${path}`
|
|
@@ -175,13 +69,4 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
175
69
|
}
|
|
176
70
|
});
|
|
177
71
|
|
|
178
|
-
export {
|
|
179
|
-
ip,
|
|
180
|
-
listenPortController,
|
|
181
|
-
networkRouter,
|
|
182
|
-
netWorkCron,
|
|
183
|
-
saveRuntimeRouter,
|
|
184
|
-
logRuntimeRouter,
|
|
185
|
-
listenServerFactory,
|
|
186
|
-
saveRuntimeCron,
|
|
187
|
-
};
|
|
72
|
+
export { listenPortController, logRuntimeRouter, listenServerFactory };
|
package/src/server/peer.js
CHANGED
|
@@ -2,7 +2,7 @@ import { PeerServer } from 'peer';
|
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import { loggerFactory } from './logger.js';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
-
import
|
|
5
|
+
import UnderpostStartUp from './start.js';
|
|
6
6
|
|
|
7
7
|
dotenv.config();
|
|
8
8
|
|
|
@@ -25,7 +25,7 @@ const createPeerServer = async ({ port, devPort, origins, host, path }) => {
|
|
|
25
25
|
// cert: fs.readFileSync(''),
|
|
26
26
|
// ca: fs.readFileSync(''),
|
|
27
27
|
};
|
|
28
|
-
const peerServer = listenServerFactory(() => PeerServer(options));
|
|
28
|
+
const peerServer = UnderpostStartUp.API.listenServerFactory(() => PeerServer(options));
|
|
29
29
|
|
|
30
30
|
return { options, peerServer, meta: import.meta };
|
|
31
31
|
};
|