@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
|
@@ -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
|
};
|
package/src/server/proxy.js
CHANGED
|
@@ -5,9 +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 } from './network.js';
|
|
9
8
|
import { createSslServer, sslRedirectMiddleware } from './ssl.js';
|
|
10
9
|
import { buildPortProxyRouter, buildProxyRouter, maintenanceMiddleware } from './conf.js';
|
|
10
|
+
import UnderpostStartUp from './start.js';
|
|
11
11
|
|
|
12
12
|
dotenv.config();
|
|
13
13
|
|
|
@@ -71,11 +71,11 @@ const buildProxy = async () => {
|
|
|
71
71
|
switch (port) {
|
|
72
72
|
case 443:
|
|
73
73
|
const { ServerSSL } = await createSslServer(app, hosts);
|
|
74
|
-
await listenPortController(ServerSSL, port, runningData);
|
|
74
|
+
await UnderpostStartUp.API.listenPortController(ServerSSL, port, runningData);
|
|
75
75
|
break;
|
|
76
76
|
|
|
77
77
|
default:
|
|
78
|
-
await listenPortController(app, port, runningData);
|
|
78
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
79
79
|
|
|
80
80
|
break;
|
|
81
81
|
}
|
|
@@ -83,7 +83,7 @@ const buildProxy = async () => {
|
|
|
83
83
|
break;
|
|
84
84
|
|
|
85
85
|
default:
|
|
86
|
-
await listenPortController(app, port, runningData);
|
|
86
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
87
87
|
|
|
88
88
|
break;
|
|
89
89
|
}
|
package/src/server/runtime.js
CHANGED
|
@@ -9,7 +9,7 @@ import compression from 'compression';
|
|
|
9
9
|
|
|
10
10
|
import { createServer } from 'http';
|
|
11
11
|
import { getRootDirectory } from './process.js';
|
|
12
|
-
import
|
|
12
|
+
import UnderpostStartUp from './start.js';
|
|
13
13
|
import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
14
14
|
import { getCapVariableName, newInstance } from '../client/components/core/CommonJs.js';
|
|
15
15
|
import { Xampp } from '../runtime/xampp/Xampp.js';
|
|
@@ -19,7 +19,9 @@ import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
|
19
19
|
import { createPeerServer } from './peer.js';
|
|
20
20
|
import { Lampp } from '../runtime/lampp/Lampp.js';
|
|
21
21
|
import { getDeployId } from './conf.js';
|
|
22
|
-
import { ssrFactory } from './client-formatted.js';
|
|
22
|
+
import { JSONweb, ssrFactory } from './client-formatted.js';
|
|
23
|
+
import Underpost from '../index.js';
|
|
24
|
+
import { createValkeyConnection } from './valkey.js';
|
|
23
25
|
|
|
24
26
|
dotenv.config();
|
|
25
27
|
|
|
@@ -40,7 +42,6 @@ const buildRuntime = async () => {
|
|
|
40
42
|
// logger.info('promCounterOption', promCounterOption);
|
|
41
43
|
|
|
42
44
|
const requestCounter = new promClient.Counter(promCounterOption);
|
|
43
|
-
const ipInstance = ''; // await ip.public.ipv4();
|
|
44
45
|
const initPort = parseInt(process.env.PORT) + 1;
|
|
45
46
|
let currentPort = initPort;
|
|
46
47
|
const confServer = JSON.parse(fs.readFileSync(`./conf/conf.server.json`, 'utf8'));
|
|
@@ -67,6 +68,7 @@ const buildRuntime = async () => {
|
|
|
67
68
|
peer,
|
|
68
69
|
singleReplica,
|
|
69
70
|
replicas,
|
|
71
|
+
valkey,
|
|
70
72
|
} = confServer[host][path];
|
|
71
73
|
|
|
72
74
|
if (singleReplica && replicas && replicas.length > 0 && !singleReplicaHosts.includes(host)) {
|
|
@@ -140,6 +142,8 @@ const buildRuntime = async () => {
|
|
|
140
142
|
// if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
|
|
141
143
|
// $_SERVER['HTTPS'] = 'on';
|
|
142
144
|
// }
|
|
145
|
+
// For plugins:
|
|
146
|
+
// define( 'FS_METHOD', 'direct' );
|
|
143
147
|
|
|
144
148
|
// ErrorDocument 404 /custom_404.html
|
|
145
149
|
// ErrorDocument 500 /custom_50x.html
|
|
@@ -182,7 +186,11 @@ const buildRuntime = async () => {
|
|
|
182
186
|
// RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
|
|
183
187
|
// RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
|
|
184
188
|
|
|
185
|
-
await listenPortController(
|
|
189
|
+
await UnderpostStartUp.API.listenPortController(
|
|
190
|
+
UnderpostStartUp.API.listenServerFactory(),
|
|
191
|
+
port,
|
|
192
|
+
runningData,
|
|
193
|
+
);
|
|
186
194
|
break;
|
|
187
195
|
case 'xampp':
|
|
188
196
|
if (!Xampp.enabled()) continue;
|
|
@@ -229,7 +237,11 @@ const buildRuntime = async () => {
|
|
|
229
237
|
// if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
|
|
230
238
|
// $_SERVER['HTTPS'] = 'on';
|
|
231
239
|
// }
|
|
232
|
-
await listenPortController(
|
|
240
|
+
await UnderpostStartUp.API.listenPortController(
|
|
241
|
+
UnderpostStartUp.API.listenServerFactory(),
|
|
242
|
+
port,
|
|
243
|
+
runningData,
|
|
244
|
+
);
|
|
233
245
|
break;
|
|
234
246
|
case 'nodejs':
|
|
235
247
|
const app = express();
|
|
@@ -282,7 +294,7 @@ const buildRuntime = async () => {
|
|
|
282
294
|
currentPort += 2;
|
|
283
295
|
const staticPort = newInstance(currentPort);
|
|
284
296
|
|
|
285
|
-
await listenPortController(app, staticPort, runningData);
|
|
297
|
+
await UnderpostStartUp.API.listenPortController(app, staticPort, runningData);
|
|
286
298
|
currentPort++;
|
|
287
299
|
continue;
|
|
288
300
|
}
|
|
@@ -333,7 +345,7 @@ const buildRuntime = async () => {
|
|
|
333
345
|
// }),
|
|
334
346
|
// );
|
|
335
347
|
|
|
336
|
-
await listenPortController(app, port, runningData);
|
|
348
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
337
349
|
break;
|
|
338
350
|
}
|
|
339
351
|
|
|
@@ -353,6 +365,9 @@ const buildRuntime = async () => {
|
|
|
353
365
|
|
|
354
366
|
if (db && apis) await DataBaseProvider.load({ apis, host, path, db });
|
|
355
367
|
|
|
368
|
+
// valkey server
|
|
369
|
+
await createValkeyConnection({ host, path }, valkey);
|
|
370
|
+
|
|
356
371
|
if (mailer) {
|
|
357
372
|
const mailerSsrConf = confSSR[getCapVariableName(client)];
|
|
358
373
|
await MailerProvider.load({
|
|
@@ -384,6 +399,13 @@ const buildRuntime = async () => {
|
|
|
384
399
|
ssrPath,
|
|
385
400
|
ssrHeadComponents: '',
|
|
386
401
|
ssrBodyComponents: (await ssrFactory(`./src/client/ssr/body/404.js`))(),
|
|
402
|
+
renderPayload: {
|
|
403
|
+
apiBasePath: process.env.BASE_API,
|
|
404
|
+
version: Underpost.version,
|
|
405
|
+
},
|
|
406
|
+
renderApi: {
|
|
407
|
+
JSONweb,
|
|
408
|
+
},
|
|
387
409
|
});
|
|
388
410
|
const path404 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/404/index.html`;
|
|
389
411
|
const page404 = fs.existsSync(path404) ? `${path === '/' ? '' : path}/404` : undefined;
|
|
@@ -400,6 +422,13 @@ const buildRuntime = async () => {
|
|
|
400
422
|
ssrPath,
|
|
401
423
|
ssrHeadComponents: '',
|
|
402
424
|
ssrBodyComponents: (await ssrFactory(`./src/client/ssr/body/500.js`))(),
|
|
425
|
+
renderPayload: {
|
|
426
|
+
apiBasePath: process.env.BASE_API,
|
|
427
|
+
version: Underpost.version,
|
|
428
|
+
},
|
|
429
|
+
renderApi: {
|
|
430
|
+
JSONweb,
|
|
431
|
+
},
|
|
403
432
|
});
|
|
404
433
|
const path500 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/500/index.html`;
|
|
405
434
|
const page500 = fs.existsSync(path500) ? `${path === '/' ? '' : path}/500` : undefined;
|
|
@@ -427,7 +456,7 @@ const buildRuntime = async () => {
|
|
|
427
456
|
port,
|
|
428
457
|
origins,
|
|
429
458
|
});
|
|
430
|
-
await listenPortController(listenServerFactory(), port, {
|
|
459
|
+
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), port, {
|
|
431
460
|
runtime: 'nodejs',
|
|
432
461
|
client: null,
|
|
433
462
|
host,
|
|
@@ -447,7 +476,7 @@ const buildRuntime = async () => {
|
|
|
447
476
|
path,
|
|
448
477
|
});
|
|
449
478
|
|
|
450
|
-
await listenPortController(peerServer, peerPort, {
|
|
479
|
+
await UnderpostStartUp.API.listenPortController(peerServer, peerPort, {
|
|
451
480
|
runtime: 'nodejs',
|
|
452
481
|
client: null,
|
|
453
482
|
host,
|
|
@@ -456,7 +485,7 @@ const buildRuntime = async () => {
|
|
|
456
485
|
});
|
|
457
486
|
}
|
|
458
487
|
|
|
459
|
-
await listenPortController(server, port, runningData);
|
|
488
|
+
await UnderpostStartUp.API.listenPortController(server, port, runningData);
|
|
460
489
|
|
|
461
490
|
break;
|
|
462
491
|
default:
|
|
@@ -469,8 +498,7 @@ const buildRuntime = async () => {
|
|
|
469
498
|
if (Xampp.enabled() && Xampp.router) Xampp.initService();
|
|
470
499
|
if (Lampp.enabled() && Lampp.router) Lampp.initService();
|
|
471
500
|
|
|
472
|
-
|
|
473
|
-
logRuntimeRouter();
|
|
501
|
+
UnderpostStartUp.API.logRuntimeRouter();
|
|
474
502
|
};
|
|
475
503
|
|
|
476
504
|
export { buildRuntime };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import UnderpostDeploy from '../cli/deploy.js';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import { awaitDeployMonitor } from './conf.js';
|
|
4
|
+
import { actionInitLog, loggerFactory } from './logger.js';
|
|
5
|
+
import { shellCd, shellExec } from './process.js';
|
|
6
|
+
import UnderpostRootEnv from '../cli/env.js';
|
|
7
|
+
|
|
8
|
+
const logger = loggerFactory(import.meta);
|
|
9
|
+
|
|
10
|
+
class UnderpostStartUp {
|
|
11
|
+
static API = {
|
|
12
|
+
logRuntimeRouter: () => {
|
|
13
|
+
const displayLog = {};
|
|
14
|
+
|
|
15
|
+
for (const host of Object.keys(UnderpostDeploy.NETWORK))
|
|
16
|
+
for (const path of Object.keys(UnderpostDeploy.NETWORK[host]))
|
|
17
|
+
displayLog[UnderpostDeploy.NETWORK[host][path].publicHost] = UnderpostDeploy.NETWORK[host][path].local;
|
|
18
|
+
|
|
19
|
+
logger.info('Runtime network', displayLog);
|
|
20
|
+
},
|
|
21
|
+
listenServerFactory: (logic = async () => {}) => {
|
|
22
|
+
return {
|
|
23
|
+
listen: async (...args) => {
|
|
24
|
+
const msDelta = 1000;
|
|
25
|
+
const msMax = 30 * 24 * 60 * 60 * 1000; // ~ 1 month
|
|
26
|
+
let msCount = 0;
|
|
27
|
+
setInterval(() => {
|
|
28
|
+
msCount += msDelta;
|
|
29
|
+
if (msCount >= msMax) {
|
|
30
|
+
const message = 'Listen server factory timeout';
|
|
31
|
+
logger.error(message);
|
|
32
|
+
throw new Error(message);
|
|
33
|
+
}
|
|
34
|
+
}, msDelta);
|
|
35
|
+
return logic ? await logic(...args) : undefined, args[1]();
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
listenPortController: async (server, port, metadata) =>
|
|
40
|
+
new Promise((resolve) => {
|
|
41
|
+
try {
|
|
42
|
+
if (port === ':') {
|
|
43
|
+
server.listen(port, actionInitLog);
|
|
44
|
+
return resolve(true);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { host, path, client, runtime, meta } = metadata;
|
|
48
|
+
const error = [];
|
|
49
|
+
if (port === undefined) error.push(`port`);
|
|
50
|
+
if (host === undefined) error.push(`host`);
|
|
51
|
+
if (path === undefined) error.push(`path`);
|
|
52
|
+
if (client === undefined) error.push(`client`);
|
|
53
|
+
if (runtime === undefined) error.push(`runtime`);
|
|
54
|
+
if (meta === undefined) error.push(`meta`);
|
|
55
|
+
if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
|
|
56
|
+
|
|
57
|
+
server.listen(port, () => {
|
|
58
|
+
if (!UnderpostDeploy.NETWORK[host]) UnderpostDeploy.NETWORK[host] = {};
|
|
59
|
+
UnderpostDeploy.NETWORK[host][path] = {
|
|
60
|
+
meta,
|
|
61
|
+
client,
|
|
62
|
+
runtime,
|
|
63
|
+
port,
|
|
64
|
+
publicHost:
|
|
65
|
+
port === 80
|
|
66
|
+
? `http://${host}${path}`
|
|
67
|
+
: port === 443
|
|
68
|
+
? `https://${host}${path}`
|
|
69
|
+
: `http://${host}:${port}${path}`,
|
|
70
|
+
local: `http://localhost:${port}${path}`,
|
|
71
|
+
apis: metadata.apis,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return resolve(true);
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
logger.error(error, { metadata, port, stack: error.stack });
|
|
78
|
+
resolve(false);
|
|
79
|
+
}
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
async callback(deployId = 'default', env = 'development', options = { build: false, run: false }) {
|
|
83
|
+
if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
|
|
84
|
+
if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
|
|
85
|
+
},
|
|
86
|
+
async build(deployId = 'default', env = 'development') {
|
|
87
|
+
const buildBasePath = `/home/dd`;
|
|
88
|
+
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
89
|
+
shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
|
|
90
|
+
shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
|
|
91
|
+
shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
|
|
92
|
+
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
93
|
+
shellCd(`${buildBasePath}/engine`);
|
|
94
|
+
shellExec(`npm install`);
|
|
95
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
96
|
+
if (fs.existsSync('./engine-private/itc-scripts')) {
|
|
97
|
+
const itcScripts = await fs.readdir('./engine-private/itc-scripts');
|
|
98
|
+
for (const itcScript of itcScripts)
|
|
99
|
+
if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
|
|
100
|
+
}
|
|
101
|
+
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
102
|
+
},
|
|
103
|
+
async run(deployId = 'default', env = 'development') {
|
|
104
|
+
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
105
|
+
if (fs.existsSync(`./engine-private/replica`)) {
|
|
106
|
+
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
107
|
+
for (const replica of replicas) {
|
|
108
|
+
if (!replica.match(deployId)) continue;
|
|
109
|
+
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
110
|
+
shellExec(`npm ${runCmd} deploy deploy-id:${replica}`, { async: true });
|
|
111
|
+
await awaitDeployMonitor(true);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
115
|
+
shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`, { async: true });
|
|
116
|
+
await awaitDeployMonitor(true);
|
|
117
|
+
UnderpostRootEnv.API.set('container-status', `${deployId}-${env}-running-deployment`);
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default UnderpostStartUp;
|
package/src/server/valkey.js
CHANGED
|
@@ -5,12 +5,24 @@ import { loggerFactory } from './logger.js';
|
|
|
5
5
|
|
|
6
6
|
const logger = loggerFactory(import.meta);
|
|
7
7
|
|
|
8
|
+
const ValkeyInstances = {};
|
|
9
|
+
|
|
8
10
|
let valkeyEnabled = true;
|
|
9
11
|
|
|
10
12
|
const disableValkeyErrorMessage = 'valkey is not enabled';
|
|
11
13
|
|
|
12
14
|
const isValkeyEnable = () => valkeyEnabled;
|
|
13
15
|
|
|
16
|
+
const createValkeyConnection = async (
|
|
17
|
+
instance = { host: '', port: 0 },
|
|
18
|
+
valkeyServerConnectionOptions = { host: '', port: 0 },
|
|
19
|
+
) => {
|
|
20
|
+
ValkeyInstances[`${instance.host}${instance.path}`] = await ValkeyAPI.valkeyClientFactory(
|
|
21
|
+
valkeyServerConnectionOptions,
|
|
22
|
+
);
|
|
23
|
+
return ValkeyInstances[`${instance.host}${instance.path}`];
|
|
24
|
+
};
|
|
25
|
+
|
|
14
26
|
const selectDtoFactory = (payload, select) => {
|
|
15
27
|
const result = {};
|
|
16
28
|
for (const key of Object.keys(select)) {
|
|
@@ -19,10 +31,12 @@ const selectDtoFactory = (payload, select) => {
|
|
|
19
31
|
return result;
|
|
20
32
|
};
|
|
21
33
|
|
|
22
|
-
const valkeyClientFactory = async () => {
|
|
34
|
+
const valkeyClientFactory = async (options) => {
|
|
23
35
|
const valkey = new Valkey({
|
|
24
36
|
// port: 6379,
|
|
25
37
|
// host: 'service-valkey.default.svc.cluster.local',
|
|
38
|
+
port: options?.port ? options.port : undefined,
|
|
39
|
+
host: options?.port ? options.host : undefined,
|
|
26
40
|
retryStrategy: (attempt) => {
|
|
27
41
|
if (attempt === 1) {
|
|
28
42
|
valkey.disconnect();
|
|
@@ -46,12 +60,12 @@ const valkeyClientFactory = async () => {
|
|
|
46
60
|
return valkey;
|
|
47
61
|
};
|
|
48
62
|
|
|
49
|
-
const getValkeyObject = async (key = '') => {
|
|
63
|
+
const getValkeyObject = async (options = { host: '', port: 0 }, key = '') => {
|
|
50
64
|
if (!valkeyEnabled) {
|
|
51
65
|
logger.warn(disableValkeyErrorMessage + ' get', key);
|
|
52
66
|
return null;
|
|
53
67
|
}
|
|
54
|
-
const object = await
|
|
68
|
+
const object = await ValkeyInstances[`${options.host}${options.path}`].get(key);
|
|
55
69
|
try {
|
|
56
70
|
return JSON.parse(object);
|
|
57
71
|
} catch (error) {
|
|
@@ -60,19 +74,19 @@ const getValkeyObject = async (key = '') => {
|
|
|
60
74
|
}
|
|
61
75
|
};
|
|
62
76
|
|
|
63
|
-
const setValkeyObject = async (key = '', payload = {}) => {
|
|
77
|
+
const setValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
|
|
64
78
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
65
|
-
return await
|
|
79
|
+
return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify(payload));
|
|
66
80
|
};
|
|
67
81
|
|
|
68
|
-
const updateValkeyObject = async (key = '', payload = {}) => {
|
|
82
|
+
const updateValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
|
|
69
83
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
70
|
-
const object = await getValkeyObject(key
|
|
84
|
+
const object = await getValkeyObject(key);
|
|
71
85
|
object.updatedAt = new Date().toISOString();
|
|
72
|
-
return await
|
|
86
|
+
return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify({ ...object, ...payload }));
|
|
73
87
|
};
|
|
74
88
|
|
|
75
|
-
const valkeyObjectFactory = async (
|
|
89
|
+
const valkeyObjectFactory = async (options = { host: 'localhost', object: {} }, module = '') => {
|
|
76
90
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
77
91
|
const idoDate = new Date().toISOString();
|
|
78
92
|
options.object = options.object || {};
|
|
@@ -112,10 +126,9 @@ const ValkeyAPI = {
|
|
|
112
126
|
setValkeyObject,
|
|
113
127
|
valkeyObjectFactory,
|
|
114
128
|
updateValkeyObject,
|
|
129
|
+
createValkeyConnection,
|
|
115
130
|
};
|
|
116
131
|
|
|
117
|
-
const valkey = await ValkeyAPI.valkeyClientFactory();
|
|
118
|
-
|
|
119
132
|
export {
|
|
120
133
|
valkeyClientFactory,
|
|
121
134
|
selectDtoFactory,
|
|
@@ -124,5 +137,6 @@ export {
|
|
|
124
137
|
valkeyObjectFactory,
|
|
125
138
|
updateValkeyObject,
|
|
126
139
|
isValkeyEnable,
|
|
140
|
+
createValkeyConnection,
|
|
127
141
|
ValkeyAPI,
|
|
128
142
|
};
|
package/test/api.test.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
|
-
import https from 'https';
|
|
6
5
|
|
|
7
6
|
import { expect } from 'chai';
|
|
8
7
|
import { loggerFactory } from '../src/server/logger.js';
|
|
@@ -20,13 +19,6 @@ const BASE_URL =
|
|
|
20
19
|
? `http://localhost:${PORT}/${process.env.BASE_API}`
|
|
21
20
|
: `https://www.nexodev.org/api`;
|
|
22
21
|
|
|
23
|
-
axios.defaults.baseURL = BASE_URL;
|
|
24
|
-
|
|
25
|
-
const httpsAgent = new https.Agent({
|
|
26
|
-
rejectUnauthorized: false,
|
|
27
|
-
});
|
|
28
|
-
axios.defaults.httpsAgent = httpsAgent;
|
|
29
|
-
|
|
30
22
|
describe(`GET 'Test' API Request `, async () => {
|
|
31
23
|
{
|
|
32
24
|
const url = `${BASE_URL}/test/youtube-id/?url=https://www.youtube.com/watch?v=o4f42SbyDMk`;
|