underpost 2.8.1 → 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/.dockerignore +1 -0
- package/.github/workflows/ghpkg.yml +19 -49
- package/.github/workflows/npmpkg.yml +67 -0
- package/.github/workflows/publish.yml +5 -5
- package/.github/workflows/pwa-microservices-template.page.yml +12 -4
- package/.github/workflows/pwa-microservices-template.test.yml +2 -2
- package/.vscode/extensions.json +18 -71
- package/.vscode/settings.json +20 -3
- package/AUTHORS.md +16 -5
- package/CHANGELOG.md +123 -3
- package/Dockerfile +27 -70
- package/README.md +39 -29
- package/bin/build.js +186 -0
- package/bin/db.js +2 -24
- package/bin/deploy.js +1467 -236
- package/bin/file.js +67 -16
- package/bin/hwt.js +0 -10
- package/bin/index.js +1 -77
- package/bin/ssl.js +19 -11
- package/bin/util.js +9 -104
- package/bin/vs.js +26 -2
- package/cli.md +451 -0
- package/conf.js +29 -138
- 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/deployment/mongo-express/deployment.yaml +60 -0
- package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
- package/manifests/kind-config-dev.yaml +12 -0
- package/manifests/kind-config.yaml +12 -0
- package/manifests/kubeadm-calico-config.yaml +119 -0
- package/manifests/letsencrypt-prod.yaml +15 -0
- package/manifests/mariadb/config.yaml +10 -0
- package/manifests/mariadb/kustomization.yaml +9 -0
- package/manifests/mariadb/pv.yaml +12 -0
- package/manifests/mariadb/pvc.yaml +10 -0
- package/manifests/mariadb/secret.yaml +8 -0
- package/manifests/mariadb/service.yaml +10 -0
- package/manifests/mariadb/statefulset.yaml +55 -0
- package/manifests/mongodb/backup-access.yaml +16 -0
- package/manifests/mongodb/backup-cronjob.yaml +42 -0
- package/manifests/mongodb/backup-pv-pvc.yaml +22 -0
- package/manifests/mongodb/configmap.yaml +26 -0
- package/manifests/mongodb/headless-service.yaml +10 -0
- package/manifests/mongodb/kustomization.yaml +11 -0
- package/manifests/mongodb/pv-pvc.yaml +23 -0
- package/manifests/mongodb/statefulset.yaml +125 -0
- package/manifests/mongodb-4.4/kustomization.yaml +7 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +23 -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/postgresql/service.yaml +10 -0
- package/manifests/postgresql/statefulset.yaml +37 -0
- package/manifests/valkey/kustomization.yaml +7 -0
- package/manifests/valkey/service.yaml +17 -0
- package/manifests/valkey/statefulset.yaml +41 -0
- package/package.json +127 -136
- package/src/api/core/core.service.js +1 -1
- package/src/api/default/default.service.js +1 -1
- package/src/api/user/user.model.js +16 -3
- package/src/api/user/user.service.js +15 -12
- package/src/cli/cluster.js +389 -0
- package/src/cli/cron.js +121 -0
- package/src/cli/db.js +222 -0
- package/src/cli/deploy.js +487 -0
- package/src/cli/env.js +58 -0
- package/src/cli/fs.js +161 -0
- package/src/cli/image.js +66 -0
- package/src/cli/index.js +312 -0
- package/src/cli/monitor.js +236 -0
- package/src/cli/repository.js +128 -0
- package/src/cli/script.js +53 -0
- package/src/cli/secrets.js +37 -0
- package/src/cli/test.js +118 -0
- package/src/client/components/core/Account.js +28 -24
- package/src/client/components/core/Auth.js +22 -4
- package/src/client/components/core/Blockchain.js +1 -1
- package/src/client/components/core/CalendarCore.js +128 -121
- package/src/client/components/core/CommonJs.js +283 -19
- package/src/client/components/core/CssCore.js +16 -4
- package/src/client/components/core/Docs.js +1 -2
- package/src/client/components/core/DropDown.js +5 -1
- 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 +22 -6
- 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 +54 -20
- package/src/client/components/core/Panel.js +109 -90
- package/src/client/components/core/PanelForm.js +23 -30
- 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/Scroll.js +1 -0
- package/src/client/components/core/SignUp.js +2 -2
- package/src/client/components/core/Translate.js +47 -9
- package/src/client/components/core/Validator.js +9 -1
- package/src/client/components/core/VanillaJs.js +0 -9
- package/src/client/components/core/Worker.js +34 -31
- 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 +46 -37
- 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 +29 -1
- package/src/index.js +101 -19
- package/src/mailer/MailerProvider.js +3 -0
- package/src/runtime/lampp/Dockerfile +65 -0
- package/src/runtime/lampp/Lampp.js +1 -13
- package/src/runtime/xampp/Xampp.js +0 -13
- package/src/server/auth.js +3 -3
- package/src/server/backup.js +49 -93
- package/src/server/client-build.js +49 -46
- package/src/server/client-formatted.js +6 -3
- package/src/server/conf.js +297 -55
- package/src/server/dns.js +75 -62
- package/src/server/downloader.js +0 -8
- package/src/server/json-schema.js +77 -0
- package/src/server/logger.js +15 -10
- package/src/server/network.js +20 -161
- package/src/server/peer.js +2 -2
- package/src/server/process.js +25 -2
- package/src/server/proxy.js +7 -29
- package/src/server/runtime.js +53 -40
- package/src/server/ssl.js +1 -1
- package/src/server/start.js +122 -0
- package/src/server/valkey.js +27 -11
- package/test/api.test.js +0 -8
- package/src/dns.js +0 -22
- package/src/server/prompt-optimizer.js +0 -28
- package/startup.js +0 -11
package/src/server/dns.js
CHANGED
|
@@ -1,55 +1,79 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import { ip } from './network.js';
|
|
4
|
+
import validator from 'validator';
|
|
5
|
+
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
7
6
|
import { loggerFactory } from './logger.js';
|
|
8
|
-
import
|
|
7
|
+
import UnderpostRootEnv from '../cli/env.js';
|
|
8
|
+
import dns from 'node:dns';
|
|
9
|
+
import os from 'node:os';
|
|
9
10
|
import { shellExec } from './process.js';
|
|
10
11
|
|
|
11
|
-
const httpsAgent = new https.Agent({
|
|
12
|
-
rejectUnauthorized: false,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
axios.defaults.httpsAgent = httpsAgent;
|
|
16
|
-
|
|
17
12
|
dotenv.config();
|
|
18
13
|
|
|
19
14
|
const logger = loggerFactory(import.meta);
|
|
20
15
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
|
|
38
|
+
class Dns {
|
|
39
|
+
static callback = async function (deployList) {
|
|
40
|
+
// Network topology configuration:
|
|
41
|
+
// LAN -> [NAT-VPS](modem/router device) -> WAN
|
|
27
42
|
// enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
|
|
28
|
-
|
|
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
|
+
|
|
29
49
|
// verify inet ip proxy server address
|
|
30
50
|
// DHCP (Dynamic Host Configuration Protocol) LAN reserver IP -> MAC ID
|
|
31
51
|
// LAN server or device's local servers port -> 3000-3100 (2999-3101)
|
|
32
52
|
// DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
|
|
33
53
|
// Forward the router's TCP/UDP ports to the LAN device's IP address
|
|
54
|
+
const isOnline = await isInternetConnection();
|
|
34
55
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
if (!isOnline) return;
|
|
57
|
+
|
|
58
|
+
let testIp;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
testIp = await ip.public.ipv4();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error(error, { testIp, stack: error.stack });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const currentIp = UnderpostRootEnv.API.get('ip');
|
|
67
|
+
|
|
68
|
+
if (validator.isIP(testIp) && currentIp !== testIp) {
|
|
69
|
+
logger.info(`new ip`, testIp);
|
|
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'));
|
|
53
77
|
for (const recordType of Object.keys(confCronData.records)) {
|
|
54
78
|
switch (recordType) {
|
|
55
79
|
case 'A':
|
|
@@ -67,20 +91,21 @@ const Dns = {
|
|
|
67
91
|
const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
|
|
68
92
|
const response = await axios.get(ipUrlTest);
|
|
69
93
|
const verifyIp = response.request.socket.remoteAddress;
|
|
70
|
-
logger.info(ipUrlTest + '
|
|
94
|
+
logger.info(ipUrlTest + ' verify ip', verifyIp);
|
|
71
95
|
if (verifyIp === testIp) {
|
|
72
|
-
|
|
73
|
-
|
|
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);
|
|
74
100
|
} catch (error) {
|
|
75
|
-
logger.error(error
|
|
101
|
+
logger.error(error, error.stack);
|
|
102
|
+
logger.error('ip not updated', testIp);
|
|
76
103
|
}
|
|
77
104
|
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
},
|
|
83
|
-
services: {
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
static services = {
|
|
84
109
|
updateIp: {
|
|
85
110
|
dondominio: (options) => {
|
|
86
111
|
const { user, api_key, host, dns, ip } = options;
|
|
@@ -101,21 +126,9 @@ const Dns = {
|
|
|
101
126
|
});
|
|
102
127
|
},
|
|
103
128
|
},
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
|
|
109
|
-
shellExec(
|
|
110
|
-
`cd ./engine-private` +
|
|
111
|
-
` && git pull ${Dns.repoUrl}` +
|
|
112
|
-
` && git add . && git commit -m "update ip ${new Date().toLocaleDateString()}"` +
|
|
113
|
-
` && git push ${Dns.repoUrl}`,
|
|
114
|
-
{
|
|
115
|
-
disableLog: true,
|
|
116
|
-
},
|
|
117
|
-
);
|
|
118
|
-
},
|
|
119
|
-
};
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default Dns;
|
|
120
133
|
|
|
121
|
-
export { Dns };
|
|
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' }) =>
|
|
@@ -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/logger.js
CHANGED
|
@@ -12,7 +12,6 @@ import morgan from 'morgan';
|
|
|
12
12
|
import colorize from 'json-colorizer';
|
|
13
13
|
import colors from 'colors';
|
|
14
14
|
import v8 from 'v8';
|
|
15
|
-
import isAdmin from 'is-admin';
|
|
16
15
|
import { clearTerminalStringColor, formatBytes } from '../client/components/core/CommonJs.js';
|
|
17
16
|
|
|
18
17
|
colors.enable();
|
|
@@ -79,18 +78,16 @@ const format = (meta) =>
|
|
|
79
78
|
*
|
|
80
79
|
* This function is used to log details about
|
|
81
80
|
* the execution context, such as command-line arguments,
|
|
82
|
-
* environment variables, the
|
|
83
|
-
* and the maximum available heap space size.
|
|
81
|
+
* environment variables, and the maximum available heap space size.
|
|
84
82
|
*
|
|
85
83
|
* @param {winston.Logger} logger - A pre-configured Winston logger object.
|
|
86
84
|
* @memberof Logger
|
|
87
85
|
*/
|
|
88
86
|
const setUpInfo = async (logger = new winston.Logger()) => {
|
|
89
|
-
logger.info('npm_package_version', process.env.npm_package_version);
|
|
90
87
|
logger.info('argv', process.argv);
|
|
88
|
+
logger.info('cwd', process.cwd());
|
|
91
89
|
logger.info('platform', process.platform);
|
|
92
90
|
logger.info('env', process.env.NODE_ENV);
|
|
93
|
-
logger.info('admin', await isAdmin());
|
|
94
91
|
logger.info('--max-old-space-size', {
|
|
95
92
|
total_available_size: formatBytes(v8.getHeapStatistics().total_available_size),
|
|
96
93
|
});
|
|
@@ -115,10 +112,10 @@ const loggerFactory = (meta = { url: '' }) => {
|
|
|
115
112
|
// Allow the use the terminal to print the messages
|
|
116
113
|
new winston.transports.Console(),
|
|
117
114
|
// Allow to print all the error level messages inside the error.log file
|
|
118
|
-
new winston.transports.File({
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}),
|
|
115
|
+
// new winston.transports.File({
|
|
116
|
+
// filename: `logs/${meta}/error.log`,
|
|
117
|
+
// level: 'error',
|
|
118
|
+
// }),
|
|
122
119
|
// Allow to print all the error message inside the all.log file
|
|
123
120
|
// (also the error log that are also printed inside the error.log(
|
|
124
121
|
new winston.transports.File({ filename: `logs/${meta}/all.log` }),
|
|
@@ -189,4 +186,12 @@ const underpostASCI = () => `
|
|
|
189
186
|
░╚═════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚═╝░░░░░░╚════╝░╚═════╝░░░░╚═╝░░░
|
|
190
187
|
`;
|
|
191
188
|
|
|
192
|
-
|
|
189
|
+
const actionInitLog = () =>
|
|
190
|
+
console.log(
|
|
191
|
+
underpostASCI() +
|
|
192
|
+
`
|
|
193
|
+
https://www.nexodev.org/docs
|
|
194
|
+
`,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCI, actionInitLog };
|
package/src/server/network.js
CHANGED
|
@@ -1,168 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
5
|
-
import { killPortProcess } from 'kill-port-process';
|
|
6
|
-
import { loggerFactory } from './logger.js';
|
|
7
|
-
import { orderArrayFromAttrInt } from '../client/components/core/CommonJs.js';
|
|
8
|
-
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
9
|
-
import { getDeployId } from './conf.js';
|
|
10
|
-
|
|
11
|
-
// Network Address Translation Management
|
|
12
|
-
|
|
13
|
-
// import dotenv from 'dotenv';
|
|
14
|
-
// dotenv.config();
|
|
1
|
+
import Underpost from '../index.js';
|
|
2
|
+
import { actionInitLog, loggerFactory } from './logger.js';
|
|
15
3
|
|
|
16
4
|
const logger = loggerFactory(import.meta);
|
|
17
5
|
|
|
18
|
-
const network = {
|
|
19
|
-
port: {
|
|
20
|
-
status: async (ports) => {
|
|
21
|
-
const status = [];
|
|
22
|
-
for (const port of ports) {
|
|
23
|
-
status.push({
|
|
24
|
-
port,
|
|
25
|
-
open: await new Promise((resolve) =>
|
|
26
|
-
detect(port)
|
|
27
|
-
.then((_port) => {
|
|
28
|
-
if (port == _port)
|
|
29
|
-
// `port: ${port} was not occupied`
|
|
30
|
-
return resolve(false);
|
|
31
|
-
|
|
32
|
-
// `port: ${port} was occupied, try port: ${_port}`
|
|
33
|
-
return resolve(true);
|
|
34
|
-
})
|
|
35
|
-
.catch((error) => resolve(`${error.message}`)),
|
|
36
|
-
),
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
return status;
|
|
40
|
-
},
|
|
41
|
-
kill: async (ports) => await killPortProcess(ports),
|
|
42
|
-
portClean: async function (port) {
|
|
43
|
-
const [portStatus] = await this.status([port]);
|
|
44
|
-
// logger.info('port status', portStatus);
|
|
45
|
-
if (portStatus.open) await this.kill([port]);
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const ip = {
|
|
51
|
-
public: {
|
|
52
|
-
get: async () => await publicIp(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
53
|
-
ipv4: async () => await publicIpv4(), // => '46.5.21.123'
|
|
54
|
-
ipv6: async () => await publicIpv6(), // => 'fe80::200:f8ff:fe21:67cf'
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
let ipInstance = '';
|
|
59
|
-
const networkRouter = {};
|
|
60
|
-
|
|
61
6
|
const logRuntimeRouter = () => {
|
|
62
7
|
const displayLog = {};
|
|
63
8
|
|
|
64
|
-
for (const host of Object.keys(
|
|
65
|
-
for (const path of Object.keys(
|
|
66
|
-
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;
|
|
67
12
|
|
|
68
13
|
logger.info('Runtime network', displayLog);
|
|
69
14
|
};
|
|
70
15
|
|
|
71
|
-
const saveRuntimeRouter = async () => {
|
|
72
|
-
try {
|
|
73
|
-
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
74
|
-
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
75
|
-
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
76
|
-
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
77
|
-
if (!deployId || !host || !path) {
|
|
78
|
-
logger.warn('default deploy instance not found');
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
82
|
-
const { db } = confServer[host][path];
|
|
83
|
-
|
|
84
|
-
let closeConn;
|
|
85
|
-
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
86
|
-
await DataBaseProvider.load({ apis: ['instance'], host, path, db });
|
|
87
|
-
closeConn = true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** @type {import('../api/instance/instance.model.js').InstanceModel} */
|
|
91
|
-
const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
|
|
92
|
-
|
|
93
|
-
for (const _host of Object.keys(networkRouter)) {
|
|
94
|
-
for (const _path of Object.keys(networkRouter[_host])) {
|
|
95
|
-
const body = {
|
|
96
|
-
host: _host,
|
|
97
|
-
path: _path,
|
|
98
|
-
deployId: getDeployId(),
|
|
99
|
-
client: networkRouter[_host][_path].client,
|
|
100
|
-
runtime: networkRouter[_host][_path].runtime,
|
|
101
|
-
port: networkRouter[_host][_path].port,
|
|
102
|
-
apis: networkRouter[_host][_path].apis,
|
|
103
|
-
};
|
|
104
|
-
const instance = await Instance.findOne({ deployId: body.deployId, host: _host, path: _path });
|
|
105
|
-
if (instance) {
|
|
106
|
-
await Instance.findByIdAndUpdate(instance._id, body);
|
|
107
|
-
} else {
|
|
108
|
-
await new Instance(body).save();
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
114
|
-
} catch (error) {
|
|
115
|
-
logger.error(error);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const netWorkCron = [];
|
|
120
|
-
|
|
121
|
-
const saveRuntimeCron = async () => {
|
|
122
|
-
try {
|
|
123
|
-
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
124
|
-
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
125
|
-
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
126
|
-
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
127
|
-
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
128
|
-
const { db } = confServer[host][path];
|
|
129
|
-
|
|
130
|
-
let closeConn;
|
|
131
|
-
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
132
|
-
await DataBaseProvider.load({ apis: ['cron'], host, path, db });
|
|
133
|
-
closeConn = true;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** @type {import('../api/cron/cron.model.js').CronModel} */
|
|
137
|
-
const Cron = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Cron;
|
|
138
|
-
|
|
139
|
-
// await Cron.insertMany(netWorkCron);
|
|
140
|
-
|
|
141
|
-
for (const cronInstance of netWorkCron) {
|
|
142
|
-
const cron = await Cron.findOne({ deployId: cronInstance.deployId, jobId: cronInstance.jobId });
|
|
143
|
-
if (cron) {
|
|
144
|
-
await Cron.findByIdAndUpdate(cron._id, cronInstance);
|
|
145
|
-
} else {
|
|
146
|
-
await new Cron(cronInstance).save();
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
151
|
-
} catch (error) {
|
|
152
|
-
logger.error(error);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
16
|
const listenServerFactory = (logic = async () => {}) => {
|
|
157
17
|
return {
|
|
158
|
-
listen: async (...args) => (
|
|
18
|
+
listen: async (...args) => (
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
const message = 'Listen server factory timeout';
|
|
21
|
+
logger.error(message);
|
|
22
|
+
throw new Error(message);
|
|
23
|
+
}, 80000000), // ~ 55 days
|
|
24
|
+
(logic ? await logic(...args) : undefined, args[1]())
|
|
25
|
+
),
|
|
159
26
|
};
|
|
160
27
|
};
|
|
161
28
|
|
|
162
29
|
const listenPortController = async (server, port, metadata) =>
|
|
163
30
|
new Promise((resolve) => {
|
|
164
31
|
try {
|
|
165
|
-
if (
|
|
32
|
+
if (port === ':') {
|
|
33
|
+
server.listen(port, actionInitLog);
|
|
34
|
+
return resolve(true);
|
|
35
|
+
}
|
|
166
36
|
|
|
167
37
|
const { host, path, client, runtime, meta } = metadata;
|
|
168
38
|
const error = [];
|
|
@@ -175,13 +45,12 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
175
45
|
if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
|
|
176
46
|
|
|
177
47
|
server.listen(port, () => {
|
|
178
|
-
if (!
|
|
179
|
-
|
|
48
|
+
if (!Underpost.deployNetwork[host]) Underpost.deployNetwork[host] = {};
|
|
49
|
+
Underpost.deployNetwork[host][path] = {
|
|
180
50
|
meta,
|
|
181
51
|
client,
|
|
182
52
|
runtime,
|
|
183
53
|
port,
|
|
184
|
-
public: `http://${ipInstance}:${port}${path}`,
|
|
185
54
|
publicHost:
|
|
186
55
|
port === 80
|
|
187
56
|
? `http://${host}${path}`
|
|
@@ -200,14 +69,4 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
200
69
|
}
|
|
201
70
|
});
|
|
202
71
|
|
|
203
|
-
export {
|
|
204
|
-
ip,
|
|
205
|
-
network,
|
|
206
|
-
listenPortController,
|
|
207
|
-
networkRouter,
|
|
208
|
-
netWorkCron,
|
|
209
|
-
saveRuntimeRouter,
|
|
210
|
-
logRuntimeRouter,
|
|
211
|
-
listenServerFactory,
|
|
212
|
-
saveRuntimeCron,
|
|
213
|
-
};
|
|
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
|
};
|
package/src/server/process.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import shell from 'shelljs';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
5
|
import fs from 'fs-extra';
|
|
6
|
-
|
|
7
6
|
import { loggerFactory } from './logger.js';
|
|
7
|
+
import clipboard from 'clipboardy';
|
|
8
8
|
|
|
9
9
|
dotenv.config();
|
|
10
10
|
|
|
@@ -63,4 +63,27 @@ const shellCd = (cd, options = { disableLog: false }) => {
|
|
|
63
63
|
return shell.cd(cd);
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
function pbcopy(data) {
|
|
67
|
+
switch (process.platform) {
|
|
68
|
+
case 'linux':
|
|
69
|
+
{
|
|
70
|
+
// sudo dnf install xclip
|
|
71
|
+
// sudo apt update
|
|
72
|
+
// sudo apt install xclip
|
|
73
|
+
// paste: xclip -o
|
|
74
|
+
// copy:
|
|
75
|
+
// shellExec(`echo "${data}" | xclip -sel clip`, { async: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
default:
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
clipboard.writeSync(data || '🦄');
|
|
85
|
+
|
|
86
|
+
logger.info(`copied to clipboard`, clipboard.readSync());
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { ProcessController, getRootDirectory, shellExec, shellCd, pbcopy };
|
package/src/server/proxy.js
CHANGED
|
@@ -5,10 +5,9 @@ import dotenv from 'dotenv';
|
|
|
5
5
|
|
|
6
6
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
7
7
|
import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
8
|
-
import { listenPortController, network } from './network.js';
|
|
9
|
-
import { orderArrayFromAttrInt } from '../client/components/core/CommonJs.js';
|
|
10
8
|
import { createSslServer, sslRedirectMiddleware } from './ssl.js';
|
|
11
|
-
import { buildProxyRouter, maintenanceMiddleware } from './conf.js';
|
|
9
|
+
import { buildPortProxyRouter, buildProxyRouter, maintenanceMiddleware } from './conf.js';
|
|
10
|
+
import UnderpostStartUp from './start.js';
|
|
12
11
|
|
|
13
12
|
dotenv.config();
|
|
14
13
|
|
|
@@ -16,7 +15,7 @@ const logger = loggerFactory(import.meta);
|
|
|
16
15
|
|
|
17
16
|
const buildProxy = async () => {
|
|
18
17
|
// default target
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
express().listen(process.env.PORT);
|
|
21
20
|
|
|
22
21
|
const proxyRouter = buildProxyRouter();
|
|
@@ -57,27 +56,7 @@ const buildProxy = async () => {
|
|
|
57
56
|
// '^/target-path': '/',
|
|
58
57
|
},
|
|
59
58
|
};
|
|
60
|
-
if (!process.argv.includes('maintenance'))
|
|
61
|
-
// build router
|
|
62
|
-
Object.keys(hosts).map((hostKey) => {
|
|
63
|
-
let { host, path, target, proxy, peer } = hosts[hostKey];
|
|
64
|
-
if (process.env.NODE_ENV === 'development') host = `localhost`;
|
|
65
|
-
|
|
66
|
-
if (!proxy.includes(port)) return;
|
|
67
|
-
const absoluteHost = [80, 443].includes(port)
|
|
68
|
-
? `${host}${path === '/' ? '' : path}`
|
|
69
|
-
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
70
|
-
|
|
71
|
-
if (!(absoluteHost in options.router)) options.router[absoluteHost] = target;
|
|
72
|
-
});
|
|
73
|
-
if (Object.keys(options.router).length === 0) continue;
|
|
74
|
-
|
|
75
|
-
// order router
|
|
76
|
-
const router = {};
|
|
77
|
-
for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(options.router), 'length'))
|
|
78
|
-
router[absoluteHostKey] = options.router[absoluteHostKey];
|
|
79
|
-
options.router = router;
|
|
80
|
-
}
|
|
59
|
+
if (!process.argv.includes('maintenance')) options.router = buildPortProxyRouter(port, proxyRouter);
|
|
81
60
|
|
|
82
61
|
const filter = false
|
|
83
62
|
? (pathname, req) => {
|
|
@@ -86,18 +65,17 @@ const buildProxy = async () => {
|
|
|
86
65
|
}
|
|
87
66
|
: proxyPath;
|
|
88
67
|
app.use(proxyPath, createProxyMiddleware(filter, options));
|
|
89
|
-
await network.port.portClean(port);
|
|
90
68
|
|
|
91
69
|
switch (process.env.NODE_ENV) {
|
|
92
70
|
case 'production':
|
|
93
71
|
switch (port) {
|
|
94
72
|
case 443:
|
|
95
73
|
const { ServerSSL } = await createSslServer(app, hosts);
|
|
96
|
-
await listenPortController(ServerSSL, port, runningData);
|
|
74
|
+
await UnderpostStartUp.API.listenPortController(ServerSSL, port, runningData);
|
|
97
75
|
break;
|
|
98
76
|
|
|
99
77
|
default:
|
|
100
|
-
await listenPortController(app, port, runningData);
|
|
78
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
101
79
|
|
|
102
80
|
break;
|
|
103
81
|
}
|
|
@@ -105,7 +83,7 @@ const buildProxy = async () => {
|
|
|
105
83
|
break;
|
|
106
84
|
|
|
107
85
|
default:
|
|
108
|
-
await listenPortController(app, port, runningData);
|
|
86
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
109
87
|
|
|
110
88
|
break;
|
|
111
89
|
}
|