@opengis/fastify-table 1.3.62 → 1.3.64
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/index.js +3 -2
- package/package.json +2 -14
- package/server/migrations/context.sql +1 -0
- package/server/migrations/template.sql +1 -1
- package/server/plugins/cron/funcs/verifyUnique.js +2 -1
- package/server/plugins/cron/index.js +12 -10
- package/server/plugins/crud/funcs/dataDelete.js +8 -3
- package/server/plugins/crud/funcs/dataInsert.js +11 -4
- package/server/plugins/crud/funcs/dataUpdate.js +27 -4
- package/server/plugins/crud/funcs/getOpt.js +3 -2
- package/server/plugins/crud/funcs/getToken.js +3 -2
- package/server/plugins/crud/funcs/setOpt.js +4 -4
- package/server/plugins/crud/funcs/setToken.js +1 -2
- package/server/plugins/logger/getLogger.js +3 -2
- package/server/plugins/metric/loggerSystem.js +12 -10
- package/server/plugins/metric/systemMetricsFifthly.js +3 -2
- package/server/plugins/migration/exec.migrations.js +3 -2
- package/server/plugins/migration/exec.sql.js +11 -5
- package/server/plugins/pg/funcs/getMeta.js +2 -2
- package/server/plugins/pg/funcs/getPG.js +2 -0
- package/server/plugins/pg/funcs/getPGAsync.js +2 -0
- package/server/plugins/pg/funcs/init.js +13 -8
- package/server/plugins/policy/funcs/checkPolicy.js +1 -1
- package/server/routes/crud/controllers/insert.js +1 -1
- package/server/routes/dblist/controllers/readItems.js +11 -4
- package/server/routes/dblist/controllers/setItem.js +2 -2
package/index.js
CHANGED
|
@@ -33,6 +33,7 @@ import addTemplateDir from './server/plugins/table/funcs/addTemplateDir.js';
|
|
|
33
33
|
import execMigrations from './server/plugins/migration/exec.migrations.js';
|
|
34
34
|
|
|
35
35
|
import locales from './server/routes/table/controllers/utils/locales.js';
|
|
36
|
+
import pgClients from './server/plugins/pg/pgClients.js';
|
|
36
37
|
|
|
37
38
|
// core templates && cls
|
|
38
39
|
const filename = fileURLToPath(import.meta.url);
|
|
@@ -76,7 +77,7 @@ async function plugin(fastify, opt) {
|
|
|
76
77
|
});
|
|
77
78
|
|
|
78
79
|
// core migrations (second argument for core only)
|
|
79
|
-
execMigrations(path.join(cwd, 'server/migrations'), true).catch(err => console.log(err));
|
|
80
|
+
execMigrations(path.join(cwd, 'server/migrations'), pgClients.client, true).catch(err => console.log(err));
|
|
80
81
|
|
|
81
82
|
// core templates && cls
|
|
82
83
|
config.templates?.forEach(el => addTemplateDir(el));
|
|
@@ -103,4 +104,4 @@ async function plugin(fastify, opt) {
|
|
|
103
104
|
utilRoutes(fastify, opt);
|
|
104
105
|
fastify.get('/api/test-proxy', {}, (req) => req.headers);
|
|
105
106
|
}
|
|
106
|
-
export default fp(plugin);
|
|
107
|
+
export default fp(plugin);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/fastify-table",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.64",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "core-plugins",
|
|
6
6
|
"keywords": [
|
|
@@ -25,9 +25,6 @@
|
|
|
25
25
|
"test:helpers": "node --test .\\test\\helpers",
|
|
26
26
|
"test:routes": "node --test .\\test\\routes",
|
|
27
27
|
"test:functions": "node --test .\\test\\functions",
|
|
28
|
-
"docs:dev": "vitepress dev docs",
|
|
29
|
-
"docs:build": "vitepress build docs",
|
|
30
|
-
"docs:preview": "vitepress preview docs",
|
|
31
28
|
"compress": "node compress.js"
|
|
32
29
|
},
|
|
33
30
|
"dependencies": {
|
|
@@ -48,17 +45,8 @@
|
|
|
48
45
|
"uglify-js": "3.19.3"
|
|
49
46
|
},
|
|
50
47
|
"devDependencies": {
|
|
51
|
-
"@panzoom/panzoom": "4.5.1",
|
|
52
48
|
"eslint": "8.49.0",
|
|
53
|
-
"eslint-config-airbnb": "19.0.4"
|
|
54
|
-
"markdown-it-abbr": "2.0.0",
|
|
55
|
-
"mermaid": "10.9.3",
|
|
56
|
-
"sass": "1.72.0",
|
|
57
|
-
"vitepress": "1.3.4",
|
|
58
|
-
"vitepress-plugin-mermaid": "2.0.16",
|
|
59
|
-
"vitepress-plugin-tabs": "0.5.0",
|
|
60
|
-
"vitepress-sidebar": "1.25.0",
|
|
61
|
-
"vue": "3.4.27"
|
|
49
|
+
"eslint-config-airbnb": "19.0.4"
|
|
62
50
|
},
|
|
63
51
|
"author": "Softpro",
|
|
64
52
|
"license": "ISC"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
CREATE SCHEMA IF NOT EXISTS admin;
|
|
2
2
|
|
|
3
3
|
CREATE TABLE IF NOT EXISTS admin.rules();
|
|
4
|
+
CREATE TABLE IF NOT EXISTS admin.users( uid text not null constraint admin_user_uid_pkey PRIMARY KEY DEFAULT next_id() );
|
|
4
5
|
ALTER TABLE admin.rules DROP CONSTRAINT IF EXISTS admin_rules_pkey cascade;
|
|
5
6
|
ALTER TABLE admin.rules add column if not exists rule_id text NOT NULL DEFAULT next_id();
|
|
6
7
|
|
|
@@ -30,7 +30,7 @@ ALTER TABLE admin.templates add CONSTRAINT admin_templates_name_type_unique UNIQ
|
|
|
30
30
|
|
|
31
31
|
COMMENT ON TABLE admin.templates IS 'Шаблони для друку';
|
|
32
32
|
|
|
33
|
-
COMMENT ON COLUMN admin.templates.
|
|
33
|
+
COMMENT ON COLUMN admin.templates.created_by IS 'ID користувача';
|
|
34
34
|
|
|
35
35
|
COMMENT ON COLUMN admin.templates.name IS 'Систамна назва шаблону';
|
|
36
36
|
COMMENT ON COLUMN admin.templates.title IS 'Назва шаблону українською';
|
|
@@ -9,6 +9,7 @@ const md5 = (string) => createHash('md5').update(string).digest('hex');
|
|
|
9
9
|
const rclient = getRedis();
|
|
10
10
|
|
|
11
11
|
export default async function verifyUnique(name) {
|
|
12
|
+
if (!config.redis) return true; // skip if redis is disabled
|
|
12
13
|
const cronId = config.port || 3000 + md5(name);
|
|
13
14
|
// one per node check
|
|
14
15
|
const key = `cron:unique:${cronId}`;
|
|
@@ -19,4 +20,4 @@ export default async function verifyUnique(name) {
|
|
|
19
20
|
}
|
|
20
21
|
await rclient.expire(key, 20);
|
|
21
22
|
return true;
|
|
22
|
-
}
|
|
23
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
|
|
3
|
-
import config from
|
|
3
|
+
import config from '../../../config.js';
|
|
4
4
|
|
|
5
|
-
import getPG from
|
|
6
|
-
import pgClients from
|
|
5
|
+
import getPG from '../pg/funcs/getPG.js';
|
|
6
|
+
import pgClients from '../pg/pgClients.js';
|
|
7
7
|
import getRedis from '../redis/funcs/getRedis.js';
|
|
8
|
-
import logger from
|
|
9
|
-
import interval2ms from
|
|
8
|
+
import logger from '../logger/getLogger.js';
|
|
9
|
+
import interval2ms from './funcs/interval2ms.js';
|
|
10
10
|
|
|
11
11
|
const rclient = getRedis();
|
|
12
12
|
|
|
@@ -17,21 +17,23 @@ async function runCron({
|
|
|
17
17
|
|
|
18
18
|
// verifyUnique
|
|
19
19
|
const key = `cron:unique:${name}`;
|
|
20
|
-
const unique = await rclient.setnx(key, 1);
|
|
21
|
-
const ttl = await rclient.ttl(key);
|
|
20
|
+
const unique = config.redis ? await rclient.setnx(key, 1) : null;
|
|
21
|
+
const ttl = config.redis ? await rclient.ttl(key) : -1;
|
|
22
22
|
|
|
23
23
|
if (!unique && ttl !== -1) {
|
|
24
24
|
// if (config.trace) console.log(name, db, query, 'skip unique');
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
if (config.redis) {
|
|
29
|
+
await rclient.expire(key, 20);
|
|
30
|
+
}
|
|
29
31
|
|
|
30
32
|
try {
|
|
31
|
-
if (!pg.pk) await pg.init();
|
|
33
|
+
if (!pg.pk && config.pg) { await pg.init(); }
|
|
32
34
|
|
|
33
35
|
if (config.trace) console.time(`${db}:${query}`);
|
|
34
|
-
const { command, rows = [], rowCount } = await pg.query(query);
|
|
36
|
+
const { command, rows = [], rowCount } = pg?.pk ? await pg.query(query) : {};
|
|
35
37
|
if (config.trace) console.timeEnd(`${db}:${query}`);
|
|
36
38
|
|
|
37
39
|
logger.file('cron', { db, name, result: { command, rows, rowCount } });
|
|
@@ -2,6 +2,7 @@ import getPG from '../../pg/funcs/getPG.js';
|
|
|
2
2
|
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
3
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
4
4
|
import pgClients from '../../pg/pgClients.js';
|
|
5
|
+
import config from '../../../../config.js';
|
|
5
6
|
|
|
6
7
|
import extraData from '../../extra/extraData.js';
|
|
7
8
|
import logChanges from './utils/logChanges.js';
|
|
@@ -25,7 +26,9 @@ export default async function dataDelete({
|
|
|
25
26
|
|
|
26
27
|
const { pk } = await getMeta({ pg, table })
|
|
27
28
|
.catch(err => {
|
|
28
|
-
logger.file('crud/delete', {
|
|
29
|
+
logger.file('crud/delete', {
|
|
30
|
+
error: err.toString(), stack: err.stack, table, id, referer, uid,
|
|
31
|
+
});
|
|
29
32
|
throw new Error(err.toString());
|
|
30
33
|
});
|
|
31
34
|
const table1 = table.replace(/"/g, '');
|
|
@@ -38,7 +41,9 @@ export default async function dataDelete({
|
|
|
38
41
|
|
|
39
42
|
const res = await pg.query(delQuery, [id])
|
|
40
43
|
.catch(err => {
|
|
41
|
-
logger.file('crud/delete', {
|
|
44
|
+
logger.file('crud/delete', {
|
|
45
|
+
error: err.toString(), stack: err.stack, table, id, referer, uid, q: delQuery,
|
|
46
|
+
});
|
|
42
47
|
throw new Error(err.toString());
|
|
43
48
|
})
|
|
44
49
|
.then(el => el.rows?.[0] || {});
|
|
@@ -46,6 +51,6 @@ export default async function dataDelete({
|
|
|
46
51
|
await logChanges({
|
|
47
52
|
pg, table, tokenData, referer, id, uid, type: 'DELETE',
|
|
48
53
|
});
|
|
49
|
-
rclient.incr(`pg:${table}:crud`);
|
|
54
|
+
if (config.redis) { rclient.incr(`pg:${table}:crud`); }
|
|
50
55
|
return { ...res, ...extraRes || {} };
|
|
51
56
|
}
|
|
@@ -2,6 +2,7 @@ import getPG from '../../pg/funcs/getPG.js';
|
|
|
2
2
|
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
3
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
4
4
|
import pgClients from '../../pg/pgClients.js';
|
|
5
|
+
import config from '../../../../config.js';
|
|
5
6
|
|
|
6
7
|
import logChanges from './utils/logChanges.js';
|
|
7
8
|
import logger from '../../logger/getLogger.js';
|
|
@@ -32,7 +33,9 @@ export default async function dataInsert({
|
|
|
32
33
|
Object.assign(data, {
|
|
33
34
|
...(id && pg.pk?.[table] ? { [pg.pk?.[table]]: id } : {}),
|
|
34
35
|
...(table !== 'admin.users' ? { uid } : {}),
|
|
35
|
-
editor_id: uid,
|
|
36
|
+
editor_id: uid,
|
|
37
|
+
created_by: uid,
|
|
38
|
+
updated_by: uid,
|
|
36
39
|
// editor_id: uid,
|
|
37
40
|
});
|
|
38
41
|
|
|
@@ -52,13 +55,17 @@ export default async function dataInsert({
|
|
|
52
55
|
|
|
53
56
|
const res = await pg.query(insertQuery, [...filterData.map((el) => (typeof el[1] === 'object' && (!Array.isArray(el[1]) || typeof el[1]?.[0] === 'object') ? JSON.stringify(el[1]) : el[1]))])
|
|
54
57
|
.catch(err => {
|
|
55
|
-
logger.file('crud/insert', {
|
|
58
|
+
logger.file('crud/insert', {
|
|
59
|
+
error: err.toString(), stack: err.stack, table, id, referer, uid, q: insertQuery,
|
|
60
|
+
});
|
|
56
61
|
throw new Error(err.toString());
|
|
57
62
|
}).then(el => el || {});
|
|
58
63
|
|
|
59
64
|
const table1 = pg.pk[table] ? table : table.replace(/"/g, '');
|
|
60
65
|
|
|
61
|
-
const extraRes = await extraData({
|
|
66
|
+
const extraRes = await extraData({
|
|
67
|
+
table, form: tokenData?.form, id: res.rows?.[0]?.[pg.pk[table1]], data, uid,
|
|
68
|
+
}, pg);
|
|
62
69
|
if (extraRes && res?.rows?.[0]) {
|
|
63
70
|
Object.assign(res.rows[0], { ...extraRes });
|
|
64
71
|
}
|
|
@@ -74,6 +81,6 @@ export default async function dataInsert({
|
|
|
74
81
|
type: 'INSERT',
|
|
75
82
|
});
|
|
76
83
|
|
|
77
|
-
rclient.incr(`pg:${table}:crud`);
|
|
84
|
+
if (config.redis) { rclient.incr(`pg:${table}:crud`); }
|
|
78
85
|
return res;
|
|
79
86
|
}
|
|
@@ -2,6 +2,7 @@ import getPG from '../../pg/funcs/getPG.js';
|
|
|
2
2
|
import getMeta from '../../pg/funcs/getMeta.js';
|
|
3
3
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
4
4
|
import pgClients from '../../pg/pgClients.js';
|
|
5
|
+
import config from '../../../../config.js';
|
|
5
6
|
|
|
6
7
|
import extraData from '../../extra/extraData.js';
|
|
7
8
|
import logChanges from './utils/logChanges.js';
|
|
@@ -72,17 +73,39 @@ export default async function dataUpdate({
|
|
|
72
73
|
// console.log(updateQuery, filterValue);
|
|
73
74
|
const res = await pg.query(updateQuery, [id, ...filterValue])
|
|
74
75
|
.catch(err => {
|
|
75
|
-
logger.file('crud/update', {
|
|
76
|
+
logger.file('crud/update', {
|
|
77
|
+
error: err.toString(),
|
|
78
|
+
stack: err.stack,
|
|
79
|
+
table,
|
|
80
|
+
id,
|
|
81
|
+
referer,
|
|
82
|
+
uid,
|
|
83
|
+
data,
|
|
84
|
+
q: updateQuery,
|
|
85
|
+
});
|
|
76
86
|
throw new Error(err.toString());
|
|
77
87
|
})
|
|
78
88
|
.then(el => el?.rows?.[0]) || {};
|
|
79
89
|
|
|
80
|
-
const extraRes = await extraData({
|
|
90
|
+
const extraRes = await extraData({
|
|
91
|
+
table,
|
|
92
|
+
form: tokenData?.form,
|
|
93
|
+
id,
|
|
94
|
+
data,
|
|
95
|
+
uid,
|
|
96
|
+
}, pg);
|
|
81
97
|
|
|
82
98
|
await logChanges({
|
|
83
|
-
pg,
|
|
99
|
+
pg,
|
|
100
|
+
table,
|
|
101
|
+
tokenData,
|
|
102
|
+
referer,
|
|
103
|
+
data,
|
|
104
|
+
id,
|
|
105
|
+
uid,
|
|
106
|
+
type: 'UPDATE',
|
|
84
107
|
});
|
|
85
108
|
|
|
86
|
-
rclient.incr(`pg:${table}:crud`);
|
|
109
|
+
if (config.redis) { rclient.incr(`pg:${table}:crud`); }
|
|
87
110
|
return { ...res, ...extraRes || {} };
|
|
88
111
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import config from '../../../../config.js';
|
|
1
2
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const rclient = getRedis({ db: 0 });
|
|
4
5
|
|
|
5
6
|
export default async function getOpt(token, uid = 0) {
|
|
6
|
-
|
|
7
|
+
if (!config.redis) return null;
|
|
7
8
|
|
|
8
9
|
const key = `opt:${uid}:${token}`;
|
|
9
10
|
// console.log(key);
|
|
@@ -15,14 +15,15 @@ const keys = {
|
|
|
15
15
|
e: '%s:token:exec:%s',
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
const rclient = getRedis({ db: 0 });
|
|
19
|
+
|
|
18
20
|
async function getToken({
|
|
19
21
|
uid, token, json,
|
|
20
22
|
}) {
|
|
23
|
+
if (!config.redis) return null;
|
|
21
24
|
const mode = 'w';
|
|
22
25
|
// if (mode === 'r') return token;
|
|
23
26
|
|
|
24
|
-
const rclient = getRedis({ db: 0 });
|
|
25
|
-
|
|
26
27
|
const key = sprintf(keys[mode], config?.pg?.database, uid?.toString());
|
|
27
28
|
const id = await rclient.hget(key, token);
|
|
28
29
|
// console.log(key, token);
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'crypto';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import config from '../../../../config.js';
|
|
5
4
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
const random = randomUUID();
|
|
7
|
+
const rclient = getRedis({ db: 0 });
|
|
8
8
|
|
|
9
9
|
function md5(string) {
|
|
10
10
|
return createHash('md5').update(string).digest('hex');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export default function setOpt(params, uid = 0) {
|
|
14
|
+
if (!config.redis) return null;
|
|
14
15
|
const token = Buffer.from(md5(typeof params === 'object' ? JSON.stringify(params) : params) + random, 'hex').toString('base64').replace(/[+-=]+/g, '');
|
|
15
16
|
// const token = md5(params);
|
|
16
17
|
const key = `opt:${uid}:${token}`;
|
|
17
18
|
|
|
18
|
-
const rclient = getRedis({ db: 0 });
|
|
19
19
|
rclient.set(key, JSON.stringify(params), 'EX', 60 * 60);
|
|
20
20
|
return token;
|
|
21
21
|
}
|
|
@@ -23,8 +23,7 @@ const generateCodes = (ids, userToken) => {
|
|
|
23
23
|
function setToken({
|
|
24
24
|
ids: idsOrigin, uid, array,
|
|
25
25
|
}) {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if (!config.redis) return null;
|
|
28
27
|
if (!uid) return { user: 'empty' };
|
|
29
28
|
if (!Object.keys(idsOrigin).length) return { ids: 'empty' };
|
|
30
29
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import pino from 'pino';
|
|
2
2
|
// import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import config from '../../../config.js';
|
|
5
|
+
import getRedis from '../redis/funcs/getRedis.js';
|
|
5
6
|
import redactionList from '../../../redactionList.js';
|
|
6
7
|
|
|
7
8
|
// utils
|
|
@@ -45,10 +46,10 @@ if (config.debug) {
|
|
|
45
46
|
logger.file('test/redaction', { clientId: 'should be redacted', clientSecret: 'should be redacted' });
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
|
|
49
49
|
logger.metrics = function metrics(key, val, dbName) {
|
|
50
50
|
const dbname = dbName || config.pg?.database;
|
|
51
51
|
if (!dbname && !isServer) return;
|
|
52
|
+
if (!config.redis) return;
|
|
52
53
|
rclient2.hincrby(`${dbname}:system_metrics`, key, val || 1);
|
|
53
54
|
};
|
|
54
55
|
|
|
@@ -3,7 +3,9 @@ import process from 'process';
|
|
|
3
3
|
import util from 'node:util';
|
|
4
4
|
import { exec } from 'node:child_process';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
config, getFolder, pgClients, getRedis,
|
|
8
|
+
} from '../../../utils.js';
|
|
7
9
|
|
|
8
10
|
const execAsync = util.promisify(exec);
|
|
9
11
|
const platform = os.platform();
|
|
@@ -23,7 +25,7 @@ export default async function loggerSystem(req) {
|
|
|
23
25
|
const { pg = pgClients.client } = req;
|
|
24
26
|
const dbName = pg.options?.database;
|
|
25
27
|
|
|
26
|
-
const dbsize = await rclient.get(`${dbName}:content:dbsize:${redisKey}`);
|
|
28
|
+
const dbsize = config.redis ? await rclient.get(`${dbName}:content:dbsize:${redisKey}`) : null;
|
|
27
29
|
|
|
28
30
|
const dbVerion = await pg.query('select version();').then(el => el.rows?.[0]?.version);
|
|
29
31
|
|
|
@@ -46,7 +48,7 @@ export default async function loggerSystem(req) {
|
|
|
46
48
|
const resource = process.resourceUsage();
|
|
47
49
|
|
|
48
50
|
const currentCpuUsage = (((process.cpuUsage().user + process.cpuUsage().system) * 1000) / totalCpu) * 100;
|
|
49
|
-
const redisInfo = await rclient.info();
|
|
51
|
+
const redisInfo = config.redis ? await rclient.info() : '';
|
|
50
52
|
|
|
51
53
|
const lines = redisInfo.split('\r\n').filter((el) => el && el.split);
|
|
52
54
|
const redis = {};
|
|
@@ -58,21 +60,21 @@ export default async function loggerSystem(req) {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
await rclient.set(`${dbName}:content:dbsize:${redisKey}`, dbSize, 'EX', 30 * 60);
|
|
63
|
+
if (config.redis) { await rclient.set(`${dbName}:content:dbsize:${redisKey}`, dbSize, 'EX', 30 * 60); }
|
|
62
64
|
|
|
63
|
-
const latency = await rclient.latency('latest');
|
|
65
|
+
const latency = config.redis ? await rclient.latency('latest') : null;
|
|
64
66
|
|
|
65
|
-
const uptime = await pg.query(
|
|
67
|
+
const uptime = await pg.query('select extract(\'epoch\' from current_timestamp - pg_postmaster_start_time())::int as uptime')
|
|
66
68
|
.then(el => el.rows?.[0]?.uptime);
|
|
67
69
|
|
|
68
|
-
const metric5 = await rclient2.hgetall(`${dbName}:system_metrics`);
|
|
70
|
+
const metric5 = config.redis ? await rclient2.hgetall(`${dbName}:system_metrics`) : {};
|
|
69
71
|
|
|
70
72
|
Object.keys(metric5 || {}).filter((el) => el.startsWith('time')).forEach((m) => {
|
|
71
73
|
metric5[m] /= 1000.0;
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
const metricSort = metric5 ? JSON.parse(JSON.stringify(metric5, Object.keys(metric5).sort())) : undefined;
|
|
75
|
-
const userOnline = await rclient2.scan(['0', 'match', `${dbName}:user:*`, 'count', '10000']);
|
|
77
|
+
const userOnline = config.redis ? await rclient2.scan(['0', 'match', `${dbName}:user:*`, 'count', '10000']) : [];
|
|
76
78
|
// const userOnline = await rclient10.scan(['0', 'match', 'sess:*', 'count', '10000']);
|
|
77
79
|
|
|
78
80
|
return {
|
|
@@ -101,7 +103,7 @@ export default async function loggerSystem(req) {
|
|
|
101
103
|
'node.cpu.time': resource.systemCPUTime,
|
|
102
104
|
'node.cpu.load': os.loadavg()[0],
|
|
103
105
|
'redis.ram': redis.used_memory_human,
|
|
104
|
-
'redis.latency': latency?.join(','),
|
|
106
|
+
'redis.latency': latency?.join?.(','),
|
|
105
107
|
'redis.ram.peak': redis.used_memory_peak_human,
|
|
106
108
|
'redis.clients': redis.connected_clients,
|
|
107
109
|
'redis.db0': redis.db0?.split(',')?.[0]?.substring(5),
|
|
@@ -126,4 +128,4 @@ export default async function loggerSystem(req) {
|
|
|
126
128
|
top: topProcess,
|
|
127
129
|
query,
|
|
128
130
|
};
|
|
129
|
-
}
|
|
131
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import pgClients from '../pg/pgClients.js';
|
|
2
2
|
import logger from '../logger/getLogger.js';
|
|
3
3
|
import getRedis from '../redis/funcs/getRedis.js';
|
|
4
|
+
import config from '../../../config.js';
|
|
4
5
|
|
|
5
6
|
import loggerSystem from './loggerSystem.js';
|
|
6
7
|
|
|
@@ -10,7 +11,7 @@ export default async function systemMetricsFifthly({ pg = pgClients.client }) {
|
|
|
10
11
|
const system = await loggerSystem({ pg });
|
|
11
12
|
const dbName = pg.options?.database;
|
|
12
13
|
|
|
13
|
-
await rclient2.del(`${dbName}:system_metrics`);
|
|
14
|
+
if (config.redis) { await rclient2.del(`${dbName}:system_metrics`); }
|
|
14
15
|
|
|
15
16
|
logger.file('metric', {
|
|
16
17
|
dbname: dbName,
|
|
@@ -20,4 +21,4 @@ export default async function systemMetricsFifthly({ pg = pgClients.client }) {
|
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
return { message: 'Saved Fifthly' };
|
|
23
|
-
}
|
|
24
|
+
}
|
|
@@ -3,11 +3,12 @@ import { readdirSync, existsSync } from 'node:fs';
|
|
|
3
3
|
|
|
4
4
|
import config from '../../../config.js';
|
|
5
5
|
import execSql from './exec.sql.js';
|
|
6
|
+
import pgClients from '../pg/pgClients.js';
|
|
6
7
|
// import getCallerDir from './get.caller.dir.js';
|
|
7
8
|
|
|
8
9
|
const time = Date.now();
|
|
9
10
|
|
|
10
|
-
export default async function execMigrations(dirPath, iscore) {
|
|
11
|
+
export default async function execMigrations(dirPath, pg = pgClients.client, iscore = false) {
|
|
11
12
|
if (
|
|
12
13
|
!dirPath
|
|
13
14
|
|| (config.migrationsCore === false && iscore)
|
|
@@ -30,7 +31,7 @@ export default async function execMigrations(dirPath, iscore) {
|
|
|
30
31
|
|
|
31
32
|
// execute sql files
|
|
32
33
|
if (content?.length) {
|
|
33
|
-
await content.reduce((promise, filename) => promise.then(() => execSql(path.join(dirPath, filename))), Promise.resolve());
|
|
34
|
+
await content.reduce((promise, filename) => promise.then(() => execSql(path.join(dirPath, filename), pg)), Promise.resolve());
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -2,14 +2,20 @@ import path from 'node:path';
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import config from '../../../config.js';
|
|
6
|
+
|
|
7
|
+
import pgClients from '../pg/pgClients.js';
|
|
8
|
+
|
|
9
|
+
import logger from '../logger/getLogger.js';
|
|
10
|
+
|
|
11
|
+
import getRedis from '../redis/funcs/getRedis.js';
|
|
6
12
|
|
|
7
13
|
const rclient = getRedis();
|
|
8
14
|
|
|
9
15
|
export default async function execSql(filepath, pg = pgClients.client) {
|
|
10
16
|
const start = Date.now();
|
|
11
17
|
|
|
12
|
-
if (!filepath) return null;
|
|
18
|
+
if (!pg || !filepath) return null;
|
|
13
19
|
|
|
14
20
|
const filename = path.basename(filepath);
|
|
15
21
|
|
|
@@ -25,7 +31,7 @@ export default async function execSql(filepath, pg = pgClients.client) {
|
|
|
25
31
|
const sql = readFileSync(filepath, 'utf-8');
|
|
26
32
|
|
|
27
33
|
const hash = createHash('md5').update(sql).digest('hex');
|
|
28
|
-
const hashes = await rclient.hgetall(`${pg.options?.database}:migration-hashes`).then(obj => Object.keys(obj));
|
|
34
|
+
const hashes = config.redis ? await rclient.hgetall(`${pg.options?.database}:migration-hashes`).then(obj => Object.keys(obj)) : {};
|
|
29
35
|
|
|
30
36
|
if (hashes.includes(hash) && !config.disableCache) {
|
|
31
37
|
console.log(filename, 'skip equal hash', Date.now() - start);
|
|
@@ -35,7 +41,7 @@ export default async function execSql(filepath, pg = pgClients.client) {
|
|
|
35
41
|
try {
|
|
36
42
|
console.log(filename, 'start', Date.now() - start);
|
|
37
43
|
await pg.query(sql);
|
|
38
|
-
if (!config.disableCache) await rclient.hset(`${pg.options?.database}:migration-hashes`, hash, 1);
|
|
44
|
+
if (!config.disableCache && config.redis) await rclient.hset(`${pg.options?.database}:migration-hashes`, hash, 1);
|
|
39
45
|
console.log(filename, 'finish', Date.now() - start);
|
|
40
46
|
logger.file('migration/success', {
|
|
41
47
|
filepath,
|
|
@@ -55,4 +61,4 @@ export default async function execSql(filepath, pg = pgClients.client) {
|
|
|
55
61
|
});
|
|
56
62
|
return err.toString();
|
|
57
63
|
}
|
|
58
|
-
}
|
|
64
|
+
}
|
|
@@ -7,9 +7,9 @@ export default async function getMeta(opt, nocache) {
|
|
|
7
7
|
const pg = opt?.pg || getPG({ name: 'client' });
|
|
8
8
|
const table = opt?.table || opt;
|
|
9
9
|
|
|
10
|
-
if (pg
|
|
10
|
+
if (pg?.options?.database && data[pg.options.database]?.[table] && !nocache) return data[pg.options.database][table];
|
|
11
11
|
|
|
12
|
-
if (!pg
|
|
12
|
+
if (!pg?.tlist?.includes(table?.replace?.(/"/g, ''))) {
|
|
13
13
|
return { error: `${table} - not found`, status: 400 };
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -7,6 +7,9 @@ import logger from '../../logger/getLogger.js';
|
|
|
7
7
|
const rclient = getRedis({ db: 0 });
|
|
8
8
|
|
|
9
9
|
async function init(client) {
|
|
10
|
+
if (!client.options?.database) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
10
13
|
const textQuery = `select
|
|
11
14
|
(select json_object_agg(conrelid::regclass ,(SELECT attname FROM pg_attribute WHERE attrelid = c.conrelid and attnum = c.conkey[1]))
|
|
12
15
|
from pg_constraint c where contype='p' and connamespace::regnamespace::text not in ('sde')) as pk,
|
|
@@ -20,15 +23,16 @@ async function init(client) {
|
|
|
20
23
|
from pg_class where relkind in ('r','v')`);
|
|
21
24
|
const relkinds = rows.reduce((acc, curr) => Object.assign(acc, { [curr.tname]: curr.relkind }), {});
|
|
22
25
|
|
|
23
|
-
async function query(q, args = [],
|
|
26
|
+
async function query(q, args = [], isstream) {
|
|
24
27
|
try {
|
|
25
|
-
if (
|
|
26
|
-
await client.query('set statement_timeout to
|
|
28
|
+
if (isstream) {
|
|
29
|
+
await client.query('set statement_timeout to 100000000');
|
|
27
30
|
}
|
|
28
31
|
const data = await client.query(q, args);
|
|
29
32
|
await client.query('set statement_timeout to 0');
|
|
30
33
|
return data;
|
|
31
|
-
}
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
32
36
|
await client.query('set statement_timeout to 0');
|
|
33
37
|
if (err.message === 'canceling statement due to statement timeout') {
|
|
34
38
|
logger.file('timeout/query', { q, stack: err.stack });
|
|
@@ -39,7 +43,8 @@ async function init(client) {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
async function querySafe(q, param = {}) {
|
|
42
|
-
const
|
|
46
|
+
const { args, isstream } = param;
|
|
47
|
+
const data = await query(q, args, isstream);
|
|
43
48
|
return data;
|
|
44
49
|
}
|
|
45
50
|
|
|
@@ -78,13 +83,13 @@ async function init(client) {
|
|
|
78
83
|
|
|
79
84
|
// CRUD table state
|
|
80
85
|
const keyCacheTable = `pg:${table}:crud`;
|
|
81
|
-
const crudInc = table ? await rclient.get(keyCacheTable) || 0 : 0;
|
|
86
|
+
const crudInc = table && config.redis ? (await rclient.get(keyCacheTable) || 0) : 0;
|
|
82
87
|
|
|
83
88
|
//
|
|
84
89
|
const hash = createHash('sha1').update([q, JSON.stringify(args)].join()).digest('base64');
|
|
85
90
|
const keyCache = `pg:${hash}:${crudInc}`;
|
|
86
91
|
|
|
87
|
-
const cacheData = await rclient.get(keyCache);
|
|
92
|
+
const cacheData = config.redis ? await rclient.get(keyCache) : null;
|
|
88
93
|
|
|
89
94
|
if (cacheData && !config.local) {
|
|
90
95
|
// console.log('from cache', table, query);
|
|
@@ -93,7 +98,7 @@ async function init(client) {
|
|
|
93
98
|
|
|
94
99
|
const data = await query(q, args || []);
|
|
95
100
|
|
|
96
|
-
if (seconds > 0) {
|
|
101
|
+
if (seconds > 0 && config.redis) {
|
|
97
102
|
rclient.set(keyCache, JSON.stringify(data), 'EX', seconds);
|
|
98
103
|
}
|
|
99
104
|
|
|
@@ -88,7 +88,7 @@ export default function checkPolicy(req, reply) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/* === 3. policy: user === */
|
|
91
|
-
if (!validToken && !user && policy.includes('user') && !skipCheckPolicy(path)) {
|
|
91
|
+
if (!validToken && !user && policy.includes('user') && config.pg && !config.auth?.disable && !skipCheckPolicy(path)) {
|
|
92
92
|
logger.file('policy/user', {
|
|
93
93
|
path, method, params, query, body, message: 'access restricted: 3',
|
|
94
94
|
});
|
|
@@ -8,7 +8,7 @@ export default async function insert(req) {
|
|
|
8
8
|
} = req || {};
|
|
9
9
|
if (!user) return { message: 'access restricted', status: 403 };
|
|
10
10
|
|
|
11
|
-
const hookData = await applyHook('preInsert', { pg, table: params?.table, user });
|
|
11
|
+
const hookData = await applyHook('preInsert', { pg, table: params?.table, user, body });
|
|
12
12
|
|
|
13
13
|
if (hookData?.message && hookData?.status) {
|
|
14
14
|
return { message: hookData?.message, status: hookData?.status };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dblist, getRedis } from '../../../../utils.js';
|
|
1
|
+
import { config, dblist, getRedis } from '../../../../utils.js';
|
|
2
2
|
|
|
3
3
|
import formatData from '../utils/formatData.js';
|
|
4
4
|
|
|
@@ -12,10 +12,17 @@ export default async function readItemList(req) {
|
|
|
12
12
|
|| '2';
|
|
13
13
|
|
|
14
14
|
const key = `current-db:${uid}`;
|
|
15
|
-
const ttl = await rclient.ttl(key);
|
|
16
|
-
const currentId = await rclient.get(key);
|
|
15
|
+
const ttl = config.redis ? await rclient.ttl(key) : null;
|
|
16
|
+
const currentId = config.redis ? await rclient.get(key) : null;
|
|
17
17
|
rclient.setex(key, 60 * 60 * 10000, currentId);
|
|
18
18
|
|
|
19
19
|
const { originalMaxAge, expires } = req.session?.cookie || {};
|
|
20
|
-
return {
|
|
20
|
+
return {
|
|
21
|
+
ttl,
|
|
22
|
+
current: currentId || rows[0]?.id,
|
|
23
|
+
rows,
|
|
24
|
+
user: {
|
|
25
|
+
...req.user, originalMaxAge, expires, uid,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
21
28
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dblist, getRedis } from '../../../../utils.js';
|
|
1
|
+
import { config, dblist, getRedis } from '../../../../utils.js';
|
|
2
2
|
|
|
3
3
|
const rclient = getRedis();
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ export default async function setItem(req) {
|
|
|
19
19
|
|| req.session?.passport?.user?.username // login passwd
|
|
20
20
|
|| '2';
|
|
21
21
|
|
|
22
|
-
await rclient.setex(`current-db:${uid}`, 60 * 60 * 10000, id);
|
|
22
|
+
if (config.redis) { await rclient.setex(`current-db:${uid}`, 60 * 60 * 10000, id); }
|
|
23
23
|
|
|
24
24
|
return { current: id };
|
|
25
25
|
}
|