underpost 2.7.83 → 2.7.91
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 +41 -1
- package/.github/workflows/pwa-microservices-template.page.yml +54 -0
- package/.vscode/settings.json +7 -0
- package/CHANGELOG.md +64 -16
- package/bin/cron.js +47 -0
- package/bin/db.js +60 -7
- package/bin/deploy.js +345 -15
- package/bin/file.js +17 -1
- package/bin/index.js +1 -1
- package/bin/util.js +31 -1
- package/conf.js +18 -4
- package/docker-compose.yml +1 -1
- package/package.json +3 -3
- package/src/api/core/core.router.js +9 -9
- package/src/api/core/core.service.js +12 -4
- package/src/api/default/default.service.js +4 -4
- package/src/api/file/file.service.js +3 -3
- package/src/api/user/user.service.js +10 -8
- package/src/client/components/core/CommonJs.js +3 -0
- package/src/client/components/core/CssCore.js +30 -3
- package/src/client/components/core/Docs.js +110 -10
- package/src/client/components/core/LoadingAnimation.js +4 -2
- package/src/client/components/core/Modal.js +224 -22
- package/src/client/components/core/Panel.js +1 -1
- package/src/client/components/core/PanelForm.js +2 -1
- package/src/client/components/core/Responsive.js +34 -5
- package/src/client/components/core/RichText.js +4 -2
- package/src/client/components/core/WebComponent.js +44 -0
- package/src/client/components/core/Worker.js +13 -15
- package/src/client/public/default/plantuml/client-conf.svg +1 -1
- package/src/client/public/default/plantuml/client-schema.svg +1 -1
- package/src/client/public/default/plantuml/cron-conf.svg +1 -1
- package/src/client/public/default/plantuml/cron-schema.svg +1 -1
- package/src/client/public/default/plantuml/server-conf.svg +1 -1
- package/src/client/public/default/plantuml/server-schema.svg +1 -1
- package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
- package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
- package/src/client/public/default/site.webmanifest +69 -0
- package/src/client/ssr/components/body/CacheControl.js +1 -1
- package/src/client/ssr/components/head/Production.js +1 -0
- package/src/client/ssr/components/head/Pwa.js +146 -0
- package/src/client/ssr/components/head/Seo.js +14 -0
- package/src/client/ssr/pages/maintenance.js +14 -0
- package/src/client/ssr/pages/offline.js +21 -0
- package/src/client/sw/default.sw.js +4 -2
- package/src/db/DataBaseProvider.js +12 -1
- package/src/db/mongo/MongooseDB.js +0 -1
- package/src/runtime/lampp/Lampp.js +9 -9
- package/src/server/backup.js +82 -70
- package/src/server/client-build.js +46 -94
- package/src/server/conf.js +82 -18
- package/src/server/crypto.js +91 -0
- package/src/server/dns.js +48 -16
- package/src/server/network.js +94 -7
- package/src/server/proxy.js +27 -27
- package/src/server/runtime.js +4 -2
- package/src/server/ssl.js +2 -2
- package/src/client/ssr/offline/default.index.js +0 -31
- package/src/cron.js +0 -30
- package/src/server/cron.js +0 -35
package/src/server/backup.js
CHANGED
|
@@ -9,100 +9,112 @@ dotenv.config();
|
|
|
9
9
|
const logger = loggerFactory(import.meta);
|
|
10
10
|
|
|
11
11
|
const BackUpManagement = {
|
|
12
|
-
repoUrl: `https://${process.env.
|
|
13
|
-
Init: async function () {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
Callback: async function () {
|
|
18
|
-
const privateCronConfPath = `./engine-private/conf/${process.argv[2]}/conf.cron.json`;
|
|
12
|
+
repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_BACKUP_REPO}.git`,
|
|
13
|
+
Init: async function ({ deployId }) {
|
|
14
|
+
const Callback = async function () {
|
|
15
|
+
const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
const { backups } = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
|
|
23
20
|
|
|
24
|
-
|
|
21
|
+
if (!backups) return;
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
logger.info('init backups callback');
|
|
24
|
+
await logger.setUpInfo();
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
|
|
26
|
+
const currentDate = new Date().getTime();
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const dataDeploy = getDataDeploy({ deployGroupId });
|
|
28
|
+
if (!fs.existsSync('./engine-private/cron-backups'))
|
|
29
|
+
fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
|
|
34
30
|
|
|
35
|
-
for (const
|
|
36
|
-
const {
|
|
31
|
+
for (const deployGroupData of backups) {
|
|
32
|
+
const { deployGroupId } = deployGroupData;
|
|
33
|
+
const dataDeploy = getDataDeploy({ deployGroupId });
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
for (const deployObj of dataDeploy) {
|
|
36
|
+
const { deployId, replicaHost } = deployObj;
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
42
|
-
? fs.readFileSync(`./engine-private/replica/${deployId}/conf.server.json`, 'utf8')
|
|
43
|
-
: fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
|
|
44
|
-
);
|
|
38
|
+
if (replicaHost) continue;
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
const confServer = JSON.parse(
|
|
41
|
+
fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
42
|
+
? fs.readFileSync(`./engine-private/replica/${deployId}/conf.server.json`, 'utf8')
|
|
43
|
+
: fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
|
|
44
|
+
);
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
for (const host of Object.keys(confServer))
|
|
47
|
+
for (const path of Object.keys(confServer[host])) {
|
|
48
|
+
// retention policy
|
|
49
|
+
let { db, backupFrequency, maxBackupRetention, singleReplica, wp, git, directory } =
|
|
50
|
+
confServer[host][path];
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
if (!maxBackupRetention) maxBackupRetention = 5;
|
|
52
|
+
if (!db || singleReplica) continue;
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// .isDirectory()
|
|
59
|
-
const files = await fs.readdir(backUpPath, { withFileTypes: true });
|
|
54
|
+
if (!backupFrequency) backupFrequency = 'daily';
|
|
55
|
+
if (!maxBackupRetention) maxBackupRetention = 5;
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
.
|
|
63
|
-
.
|
|
64
|
-
.
|
|
57
|
+
const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
|
|
58
|
+
if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
|
|
59
|
+
// .isDirectory()
|
|
60
|
+
const files = await fs.readdir(backUpPath, { withFileTypes: true });
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
const currentBackupsDirs = files
|
|
63
|
+
.map((fileObj) => parseInt(fileObj.name))
|
|
64
|
+
.sort((a, b) => a - b)
|
|
65
|
+
.reverse();
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
67
|
+
switch (backupFrequency) {
|
|
68
|
+
case 'daily':
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
default:
|
|
71
|
+
// if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] < 1000 * 60 * 60 * 24) continue;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
|
|
76
|
+
const removePathRetention = `${backUpPath}/${retentionPath}`;
|
|
77
|
+
logger.info('Remove backup folder', removePathRetention);
|
|
78
|
+
fs.removeSync(removePathRetention);
|
|
79
|
+
}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
if (wp) {
|
|
86
|
+
const repoUrl = `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${git
|
|
87
|
+
.split('/')
|
|
88
|
+
.pop()}.git`;
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
shellExec(
|
|
91
|
+
`cd ${directory}` +
|
|
92
|
+
` && git pull ${repoUrl}` +
|
|
93
|
+
` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
|
|
94
|
+
` && git push ${repoUrl}`,
|
|
95
|
+
{
|
|
96
|
+
disableLog: true,
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
}
|
|
95
100
|
}
|
|
96
|
-
|
|
101
|
+
}
|
|
97
102
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
shellExec(
|
|
104
|
+
`cd ./engine-private/cron-backups` +
|
|
105
|
+
` && git pull ${BackUpManagement.repoUrl}` +
|
|
106
|
+
` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
|
|
107
|
+
` && git push ${BackUpManagement.repoUrl}`,
|
|
108
|
+
{
|
|
109
|
+
disableLog: true,
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
await Callback();
|
|
114
|
+
BackUpManagement.Callback = Callback;
|
|
115
|
+
return Callback;
|
|
105
116
|
},
|
|
117
|
+
Callback: async function (params) {},
|
|
106
118
|
};
|
|
107
119
|
|
|
108
120
|
export { BackUpManagement };
|
|
@@ -40,10 +40,22 @@ const fullBuild = async ({
|
|
|
40
40
|
}) => {
|
|
41
41
|
logger.warn('Full build', rootClientPath);
|
|
42
42
|
|
|
43
|
-
fs.removeSync(rootClientPath);
|
|
44
|
-
|
|
45
43
|
buildAcmeChallengePath(acmeChallengeFullPath);
|
|
46
44
|
|
|
45
|
+
if (publicClientId && publicClientId.startsWith('html-website-templates')) {
|
|
46
|
+
if (!fs.existsSync(`/dd/html-website-templates/`))
|
|
47
|
+
shellExec(`cd /dd && git clone https://github.com/designmodo/html-website-templates.git`);
|
|
48
|
+
if (!fs.existsSync(`${rootClientPath}/index.php`)) {
|
|
49
|
+
fs.copySync(`/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
|
|
50
|
+
shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
|
|
51
|
+
// git remote add origin git@github.com:<username>/<repo>.git
|
|
52
|
+
fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fs.removeSync(rootClientPath);
|
|
58
|
+
|
|
47
59
|
if (fs.existsSync(`./src/client/public/${publicClientId}`)) {
|
|
48
60
|
if (iconsBuild) {
|
|
49
61
|
const defaultBaseIconFolderPath = `src/client/public/${publicClientId}/assets/logo`;
|
|
@@ -52,7 +64,7 @@ const fullBuild = async ({
|
|
|
52
64
|
if (!fs.existsSync(defaultBaseIconPath))
|
|
53
65
|
await buildTextImg(metadata.title, { debugFilename: defaultBaseIconPath });
|
|
54
66
|
|
|
55
|
-
if (
|
|
67
|
+
if (!fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`))
|
|
56
68
|
await buildIcons({ publicClientId, metadata });
|
|
57
69
|
}
|
|
58
70
|
fs.copySync(
|
|
@@ -89,8 +101,15 @@ const fullBuild = async ({
|
|
|
89
101
|
if (dists)
|
|
90
102
|
for (const dist of dists) {
|
|
91
103
|
if ('folder' in dist) {
|
|
92
|
-
fs.
|
|
93
|
-
|
|
104
|
+
if (fs.statSync(dist.folder).isDirectory()) {
|
|
105
|
+
fs.mkdirSync(`${rootClientPath}${dist.public_folder}`, { recursive: true });
|
|
106
|
+
fs.copySync(dist.folder, `${rootClientPath}${dist.public_folder}`);
|
|
107
|
+
} else {
|
|
108
|
+
const folder = dist.public_folder.split('/');
|
|
109
|
+
folder.pop();
|
|
110
|
+
fs.mkdirSync(`${rootClientPath}${folder.join('/')}`, { recursive: true });
|
|
111
|
+
fs.copyFileSync(dist.folder, `${rootClientPath}${dist.public_folder}`);
|
|
112
|
+
}
|
|
94
113
|
}
|
|
95
114
|
if ('styles' in dist) {
|
|
96
115
|
fs.mkdirSync(`${rootClientPath}${dist.public_styles_folder}`, { recursive: true });
|
|
@@ -188,7 +207,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
188
207
|
iconsBuild,
|
|
189
208
|
metadata,
|
|
190
209
|
});
|
|
191
|
-
if (apis)
|
|
210
|
+
if (apis && false)
|
|
192
211
|
for (const apiBuildScript of apis) {
|
|
193
212
|
const scriptPath = `src/api/${apiBuildScript}/${apiBuildScript}.build.js`;
|
|
194
213
|
if (fs.existsSync(`./${scriptPath}`)) {
|
|
@@ -248,8 +267,13 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
248
267
|
'const getBaseHost = () => location.host;',
|
|
249
268
|
`const getBaseHost = () => '${apiBaseHost}';`,
|
|
250
269
|
);
|
|
251
|
-
if (apiBaseProxyPath)
|
|
270
|
+
if (apiBaseProxyPath) {
|
|
252
271
|
jsSrc = jsSrc.replace('${getProxyPath()}api/', `${apiBaseProxyPath}${process.env.BASE_API}/`);
|
|
272
|
+
jsSrc = jsSrc.replace(
|
|
273
|
+
"const getWsBasePath = () => (getProxyPath() !== '/' ? `${getProxyPath()}socket.io/` : undefined);",
|
|
274
|
+
`const getWsBasePath = () => '${apiBaseProxyPath}socket.io/';`,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
253
277
|
}
|
|
254
278
|
fs.writeFileSync(
|
|
255
279
|
jsPublicPath,
|
|
@@ -288,11 +312,11 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
288
312
|
eval(await srcFormatted(fs.readFileSync(`./src/client/ssr/Render.js`, 'utf8')));
|
|
289
313
|
|
|
290
314
|
if (views) {
|
|
291
|
-
const buildJsSrcPage = async (jsSrcPath, jsPublicPath) => {
|
|
315
|
+
const buildJsSrcPage = async (jsSrcPath, jsPublicPath, filter) => {
|
|
292
316
|
if (!(enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath))) {
|
|
293
317
|
let jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
|
|
294
318
|
if (jsSrc.split('/*imports*/')[1]) jsSrc = jsSrc.split('/*imports*/')[1];
|
|
295
|
-
|
|
319
|
+
if (filter) jsSrc = await filter(jsSrc);
|
|
296
320
|
fs.writeFileSync(
|
|
297
321
|
jsPublicPath,
|
|
298
322
|
minifyBuild || process.env.NODE_ENV === 'production' ? UglifyJS.minify(jsSrc).code : jsSrc,
|
|
@@ -301,47 +325,17 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
301
325
|
}
|
|
302
326
|
};
|
|
303
327
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
// offline html
|
|
315
|
-
{
|
|
316
|
-
await buildJsSrcPage(
|
|
317
|
-
fs.existsSync(`./src/client/ssr/offline/${publicClientId}.index.js`)
|
|
318
|
-
? `./src/client/ssr/offline/${publicClientId}.index.js`
|
|
319
|
-
: `./src/client/ssr/offline/default.index.js`,
|
|
320
|
-
`${rootClientPath}/offline.js`,
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
const htmlSrc = Render({
|
|
324
|
-
title: metadata?.title ? metadata.title : cap(client),
|
|
325
|
-
ssrPath: '/',
|
|
326
|
-
ssrHeadComponents: '',
|
|
327
|
-
ssrBodyComponents: '',
|
|
328
|
-
baseSsrLib: jsSsrCommonComponents + fs.readFileSync(`${rootClientPath}/offline.js`, 'utf8'),
|
|
329
|
-
});
|
|
328
|
+
// service woker
|
|
329
|
+
await buildJsSrcPage(
|
|
330
|
+
fs.existsSync(`./src/client/sw/${publicClientId}.sw.js`)
|
|
331
|
+
? `./src/client/sw/${publicClientId}.sw.js`
|
|
332
|
+
: `./src/client/sw/default.sw.js`,
|
|
333
|
+
`${rootClientPath}/sw.js`,
|
|
334
|
+
path !== '/'
|
|
335
|
+
? (jsSrc) => jsSrc.replaceAll(`const PROXY_PATH = '/';`, `const PROXY_PATH = '${path}/';`)
|
|
336
|
+
: undefined,
|
|
337
|
+
);
|
|
330
338
|
|
|
331
|
-
fs.writeFileSync(
|
|
332
|
-
`${rootClientPath}offline.html`,
|
|
333
|
-
minifyBuild || process.env.NODE_ENV === 'production'
|
|
334
|
-
? await minify(htmlSrc, {
|
|
335
|
-
minifyCSS: true,
|
|
336
|
-
minifyJS: true,
|
|
337
|
-
collapseBooleanAttributes: true,
|
|
338
|
-
collapseInlineTagWhitespace: true,
|
|
339
|
-
collapseWhitespace: true,
|
|
340
|
-
})
|
|
341
|
-
: htmlSrc,
|
|
342
|
-
'utf8',
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
339
|
// ssr pages
|
|
346
340
|
for (const page of await fs.readdir('./src/client/ssr/pages')) {
|
|
347
341
|
await buildJsSrcPage(`./src/client/ssr/pages/${page}`, `${rootClientPath}/${page}`);
|
|
@@ -355,7 +349,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
355
349
|
});
|
|
356
350
|
|
|
357
351
|
fs.writeFileSync(
|
|
358
|
-
`${rootClientPath}
|
|
352
|
+
`${rootClientPath}/${page.slice(0, -3)}.html`,
|
|
359
353
|
minifyBuild || process.env.NODE_ENV === 'production'
|
|
360
354
|
? await minify(htmlSrc, {
|
|
361
355
|
minifyCSS: true,
|
|
@@ -432,7 +426,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
432
426
|
fs.existsSync(`./src/client/public/${publicClientId}/browserconfig.xml`) &&
|
|
433
427
|
fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`);
|
|
434
428
|
|
|
435
|
-
if (
|
|
429
|
+
if (validPwaBuild) {
|
|
436
430
|
// build webmanifest
|
|
437
431
|
const webmanifestJson = JSON.parse(
|
|
438
432
|
fs.readFileSync(`./src/client/public/${publicClientId}/site.webmanifest`, 'utf8'),
|
|
@@ -540,48 +534,6 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
540
534
|
host,
|
|
541
535
|
path,
|
|
542
536
|
ttiLoadTimeLimit,
|
|
543
|
-
storage: {
|
|
544
|
-
// 'space-background': fs.readFileSync('./src/client/public/cyberia/space-background', 'utf8'),
|
|
545
|
-
lore0: `data:image/jpeg;base64,${fs
|
|
546
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore0.jpeg')
|
|
547
|
-
.toString('base64')}`,
|
|
548
|
-
lore1: `data:image/jpeg;base64,${fs
|
|
549
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore1.jpeg')
|
|
550
|
-
.toString('base64')}`,
|
|
551
|
-
lore2: `data:image/jpeg;base64,${fs
|
|
552
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore2.jpeg')
|
|
553
|
-
.toString('base64')}`,
|
|
554
|
-
lore3: `data:image/jpeg;base64,${fs
|
|
555
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore3.jpeg')
|
|
556
|
-
.toString('base64')}`,
|
|
557
|
-
lore4: `data:image/jpeg;base64,${fs
|
|
558
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore4.jpeg')
|
|
559
|
-
.toString('base64')}`,
|
|
560
|
-
lore5: `data:image/jpeg;base64,${fs
|
|
561
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore5.jpeg')
|
|
562
|
-
.toString('base64')}`,
|
|
563
|
-
lore6: `data:image/jpeg;base64,${fs
|
|
564
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore6.jpeg')
|
|
565
|
-
.toString('base64')}`,
|
|
566
|
-
lore7: `data:image/jpeg;base64,${fs
|
|
567
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore7.jpeg')
|
|
568
|
-
.toString('base64')}`,
|
|
569
|
-
lore8: `data:image/jpeg;base64,${fs
|
|
570
|
-
.readFileSync('./src/client/public/cyberia/assets/lore/lore8.jpeg')
|
|
571
|
-
.toString('base64')}`,
|
|
572
|
-
['arrow-left']: `data:image/png;base64,${fs
|
|
573
|
-
.readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-left.png')
|
|
574
|
-
.toString('base64')}`,
|
|
575
|
-
['arrow-right']: `data:image/png;base64,${fs
|
|
576
|
-
.readFileSync('./src/client/public/cyberia/assets/ui-icons/arrow-right.png')
|
|
577
|
-
.toString('base64')}`,
|
|
578
|
-
['fullscreen']: `data:image/png;base64,${fs
|
|
579
|
-
.readFileSync('./src/client/public/cyberia/assets/ui-icons/fullscreen.png')
|
|
580
|
-
.toString('base64')}`,
|
|
581
|
-
['cyberia-logo']: `data:image/png;base64,${fs
|
|
582
|
-
.readFileSync('./src/client/public/cyberia/assets/util/cyberia-retro-banner.png')
|
|
583
|
-
.toString('base64')}`,
|
|
584
|
-
},
|
|
585
537
|
});
|
|
586
538
|
break;
|
|
587
539
|
}
|
|
@@ -686,7 +638,7 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
686
638
|
fs.copySync(`./coverage`, coverageBuildPath);
|
|
687
639
|
|
|
688
640
|
// uml
|
|
689
|
-
shellExec(`node bin/deploy uml ${host} ${path}`);
|
|
641
|
+
// shellExec(`node bin/deploy uml ${host} ${path}`);
|
|
690
642
|
|
|
691
643
|
// https://swagger-autogen.github.io/docs/
|
|
692
644
|
|
package/src/server/conf.js
CHANGED
|
@@ -7,7 +7,7 @@ import cliSpinners from 'cli-spinners';
|
|
|
7
7
|
import logUpdate from 'log-update';
|
|
8
8
|
import colors from 'colors';
|
|
9
9
|
import { loggerFactory } from './logger.js';
|
|
10
|
-
import { shellExec, shellCd } from './process.js';
|
|
10
|
+
import { shellExec, shellCd, getRootDirectory } from './process.js';
|
|
11
11
|
import { DefaultConf } from '../../conf.js';
|
|
12
12
|
import ncp from 'copy-paste';
|
|
13
13
|
import read from 'read';
|
|
@@ -44,7 +44,9 @@ const Config = {
|
|
|
44
44
|
this.default.server = {};
|
|
45
45
|
for (const deployId of process.argv[3].split(',')) {
|
|
46
46
|
let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
47
|
-
const privateConfDevPath = `./engine-private/
|
|
47
|
+
const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
48
|
+
? `./engine-private/replica/${deployId}/conf.server.json`
|
|
49
|
+
: `./engine-private/conf/${deployId}/conf.server.dev.${process.argv[4]}.json`;
|
|
48
50
|
const confDevPath = fs.existsSync(privateConfDevPath)
|
|
49
51
|
? privateConfDevPath
|
|
50
52
|
: `./engine-private/conf/${deployId}/conf.server.dev.json`;
|
|
@@ -89,6 +91,11 @@ const loadConf = (deployId) => {
|
|
|
89
91
|
if (!fs.existsSync(`./conf`)) fs.mkdirSync(`./conf`);
|
|
90
92
|
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
91
93
|
const isValidDeployId = fs.existsSync(`${folder}`);
|
|
94
|
+
if (!isValidDeployId) {
|
|
95
|
+
logger.info(`Save new deploy conf: '${deployId}'`);
|
|
96
|
+
shellExec(`node bin/deploy save ${deployId}`);
|
|
97
|
+
return loadConf(deployId);
|
|
98
|
+
}
|
|
92
99
|
for (const typeConf of Object.keys(Config.default)) {
|
|
93
100
|
let srcConf = isValidDeployId
|
|
94
101
|
? fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8')
|
|
@@ -100,7 +107,6 @@ const loadConf = (deployId) => {
|
|
|
100
107
|
if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
|
|
101
108
|
fs.writeFileSync(`./conf/conf.${typeConf}.json`, srcConf, 'utf8');
|
|
102
109
|
}
|
|
103
|
-
if (!isValidDeployId) return {};
|
|
104
110
|
fs.writeFileSync(`./.env.production`, fs.readFileSync(`${folder}/.env.production`, 'utf8'), 'utf8');
|
|
105
111
|
fs.writeFileSync(`./.env.development`, fs.readFileSync(`${folder}/.env.development`, 'utf8'), 'utf8');
|
|
106
112
|
fs.writeFileSync(`./.env.test`, fs.readFileSync(`${folder}/.env.test`, 'utf8'), 'utf8');
|
|
@@ -120,10 +126,16 @@ const loadReplicas = (confServer) => {
|
|
|
120
126
|
for (const host of Object.keys(confServer)) {
|
|
121
127
|
for (const path of Object.keys(confServer[host])) {
|
|
122
128
|
const { replicas, singleReplica } = confServer[host][path];
|
|
123
|
-
if (
|
|
129
|
+
if (
|
|
130
|
+
replicas &&
|
|
131
|
+
(process.argv[2] === 'proxy' ||
|
|
132
|
+
!singleReplica ||
|
|
133
|
+
(singleReplica && process.env.NODE_ENV === 'development' && !process.argv[3]))
|
|
134
|
+
)
|
|
124
135
|
for (const replicaPath of replicas) {
|
|
125
136
|
confServer[host][replicaPath] = newInstance(confServer[host][path]);
|
|
126
137
|
delete confServer[host][replicaPath].replicas;
|
|
138
|
+
delete confServer[host][replicaPath].singleReplica;
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
}
|
|
@@ -246,8 +258,8 @@ const buildClientSrc = async (
|
|
|
246
258
|
);
|
|
247
259
|
|
|
248
260
|
fs.writeFileSync(
|
|
249
|
-
`./src/client/${toClientVariableName}.js`,
|
|
250
|
-
formattedSrc(fs.readFileSync(`./src/client/${fromClientVariableName}.js`, 'utf8')),
|
|
261
|
+
`./src/client/${toClientVariableName}.index.js`,
|
|
262
|
+
formattedSrc(fs.readFileSync(`./src/client/${fromClientVariableName}.index.js`, 'utf8')),
|
|
251
263
|
'utf8',
|
|
252
264
|
);
|
|
253
265
|
|
|
@@ -624,7 +636,7 @@ const deployTest = async (dataDeploy) => {
|
|
|
624
636
|
if (singleReplica) continue;
|
|
625
637
|
const urlTest = `https://${host}${path}`;
|
|
626
638
|
try {
|
|
627
|
-
const result = await axios.get(urlTest);
|
|
639
|
+
const result = await axios.get(urlTest, { timeout: 10000 });
|
|
628
640
|
const test = result.data.split('<title>');
|
|
629
641
|
if (test[1])
|
|
630
642
|
logger.info('Success deploy', {
|
|
@@ -660,19 +672,29 @@ const getDeployGroupId = () => {
|
|
|
660
672
|
return 'dd';
|
|
661
673
|
};
|
|
662
674
|
|
|
675
|
+
const getDeployId = () => {
|
|
676
|
+
const deployIndexArg = process.argv.findIndex((a) => a.match(`deploy-id:`));
|
|
677
|
+
if (deployIndexArg > -1) return process.argv[deployIndexArg].split(':')[1].trim();
|
|
678
|
+
for (const deployId of process.argv) {
|
|
679
|
+
if (fs.existsSync(`./engine-private/conf/${deployId}`)) return deployId;
|
|
680
|
+
else if (fs.existsSync(`./engine-private/replica/${deployId}`)) return deployId;
|
|
681
|
+
}
|
|
682
|
+
return 'default';
|
|
683
|
+
};
|
|
684
|
+
|
|
663
685
|
const getCronBackUpFolder = (host = '', path = '') => {
|
|
664
686
|
return `${host}${path.replace(/\\/g, '/').replace(`/`, '-')}`;
|
|
665
687
|
};
|
|
666
688
|
|
|
667
|
-
const execDeploy = async (options = { deployId: 'default' }) => {
|
|
689
|
+
const execDeploy = async (options = { deployId: 'default' }, currentAttempt = 1) => {
|
|
668
690
|
const { deployId } = options;
|
|
669
691
|
shellExec(Cmd.delete(deployId));
|
|
670
692
|
shellExec(Cmd.conf(deployId));
|
|
671
693
|
shellExec(Cmd.run(deployId));
|
|
694
|
+
const maxTime = 1000 * 60;
|
|
695
|
+
const minTime = 20 * 1000;
|
|
696
|
+
const intervalTime = 1000;
|
|
672
697
|
return await new Promise(async (resolve) => {
|
|
673
|
-
const maxTime = 1000 * 60 * 5;
|
|
674
|
-
const minTime = 10000 * 2;
|
|
675
|
-
const intervalTime = 1000;
|
|
676
698
|
let currentTime = 0;
|
|
677
699
|
const attempt = () => {
|
|
678
700
|
if (currentTime >= minTime && !fs.existsSync(`./tmp/await-deploy`)) {
|
|
@@ -682,27 +704,40 @@ const execDeploy = async (options = { deployId: 'default' }) => {
|
|
|
682
704
|
cliSpinner(
|
|
683
705
|
intervalTime,
|
|
684
706
|
`[deploy.js] `,
|
|
685
|
-
` Load instance | elapsed time ${currentTime / 1000}s / ${maxTime / 1000}s`,
|
|
707
|
+
` Load instance | attempt:${currentAttempt} | elapsed time ${currentTime / 1000}s / ${maxTime / 1000}s`,
|
|
686
708
|
'yellow',
|
|
687
709
|
'material',
|
|
688
710
|
);
|
|
689
711
|
currentTime += intervalTime;
|
|
690
|
-
if (currentTime >= maxTime)
|
|
712
|
+
if (currentTime >= maxTime) {
|
|
713
|
+
clearInterval(processMonitor);
|
|
714
|
+
return resolve(false);
|
|
715
|
+
}
|
|
691
716
|
};
|
|
692
717
|
const processMonitor = setInterval(attempt, intervalTime);
|
|
693
718
|
});
|
|
694
719
|
};
|
|
695
720
|
|
|
696
|
-
const deployRun = async (dataDeploy,
|
|
721
|
+
const deployRun = async (dataDeploy, currentAttempt = 1) => {
|
|
697
722
|
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
698
|
-
if (reset) fs.writeFileSync(`./tmp/runtime-router.json`, '{}', 'utf8');
|
|
699
723
|
await fixDependencies();
|
|
700
|
-
|
|
724
|
+
const maxAttempts = 3;
|
|
725
|
+
for (const deploy of dataDeploy) {
|
|
726
|
+
let currentAttempt = 1;
|
|
727
|
+
const attempt = async () => {
|
|
728
|
+
const success = await execDeploy(deploy, currentAttempt);
|
|
729
|
+
currentAttempt++;
|
|
730
|
+
if (!success && currentAttempt <= maxAttempts) await attempt();
|
|
731
|
+
};
|
|
732
|
+
await attempt();
|
|
733
|
+
}
|
|
701
734
|
const { failed } = await deployTest(dataDeploy);
|
|
702
735
|
if (failed.length > 0) {
|
|
703
736
|
for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
|
|
704
|
-
|
|
705
|
-
await
|
|
737
|
+
if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
|
|
738
|
+
if (process.argv.includes('manual')) await read({ prompt: 'Press enter to retry failed processes\n' });
|
|
739
|
+
currentAttempt++;
|
|
740
|
+
await deployRun(failed, currentAttempt);
|
|
706
741
|
} else logger.info(`Deploy process successfully`);
|
|
707
742
|
};
|
|
708
743
|
|
|
@@ -833,6 +868,10 @@ const Cmd = {
|
|
|
833
868
|
conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
|
|
834
869
|
replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
|
|
835
870
|
syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
|
|
871
|
+
cron: (deployId, job, expression) => {
|
|
872
|
+
shellExec(Cmd.delete(`${deployId}-${job}`));
|
|
873
|
+
return `env-cmd -f .env.production pm2 start bin/cron.js --no-autorestart --instances 1 --cron "${expression}" --name ${deployId}-${job} -- ${job} ${deployId}`;
|
|
874
|
+
},
|
|
836
875
|
};
|
|
837
876
|
|
|
838
877
|
const fixDependencies = async () => {
|
|
@@ -852,6 +891,27 @@ const fixDependencies = async () => {
|
|
|
852
891
|
);
|
|
853
892
|
};
|
|
854
893
|
|
|
894
|
+
const maintenancePath = `${getRootDirectory()}/public/${process.env.DEFAULT_DEPLOY_HOST}${
|
|
895
|
+
process.env.DEFAULT_DEPLOY_PATH
|
|
896
|
+
}/maintenance.html`;
|
|
897
|
+
|
|
898
|
+
const maintenanceMiddleware = (req, res, port, proxyRouter) => {
|
|
899
|
+
if (process.argv.includes('maintenance') && fs.existsSync(maintenancePath)) {
|
|
900
|
+
if (req.method.toUpperCase() === 'GET') return res.status(503).sendFile(maintenancePath);
|
|
901
|
+
return res.status(503).json({
|
|
902
|
+
status: 'error',
|
|
903
|
+
message: 'Server is under maintenance',
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
|
|
909
|
+
shellExec(`pm2 kill`);
|
|
910
|
+
const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
|
|
911
|
+
shellExec(`node bin/deploy conf ${proxyDeployId} production`);
|
|
912
|
+
shellExec(`node bin/deploy run ${proxyDeployId} maintenance`);
|
|
913
|
+
};
|
|
914
|
+
|
|
855
915
|
export {
|
|
856
916
|
Cmd,
|
|
857
917
|
Config,
|
|
@@ -880,4 +940,8 @@ export {
|
|
|
880
940
|
getRestoreCronCmd,
|
|
881
941
|
mergeBackUp,
|
|
882
942
|
fixDependencies,
|
|
943
|
+
getDeployId,
|
|
944
|
+
maintenancePath,
|
|
945
|
+
maintenanceMiddleware,
|
|
946
|
+
setUpProxyMaintenanceServer,
|
|
883
947
|
};
|