@opengis/fastify-table 2.0.111 → 2.0.112
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/dist/server/routes/file/controllers/export.d.ts.map +1 -1
- package/dist/server/routes/file/controllers/export.js +21 -14
- package/dist/server/routes/file/controllers/utils/pubsub.d.ts +2 -0
- package/dist/server/routes/file/controllers/utils/pubsub.d.ts.map +1 -0
- package/dist/server/routes/file/controllers/utils/pubsub.js +112 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../../../server/routes/file/controllers/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../../../server/routes/file/controllers/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgCzD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,wBAA8B,WAAW,CACvC,EACE,EAAqB,EACrB,OAAO,EACP,IAAI,EACJ,OAAO,EAAE,QAAQ,EACjB,GAAG,EACH,KAAU,EACV,IAAkB,EAClB,QAAQ,EACR,UAAU,GACX,EAAE;IACD,EAAE,EAAE,UAAU,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,EACD,KAAK,EAAE,YAAY,gBAsYpB"}
|
|
@@ -20,6 +20,7 @@ import jsonToXls from "./utils/jsonToXls.js";
|
|
|
20
20
|
import jsonToCsv from "./utils/jsonToCsv.js";
|
|
21
21
|
import formatResult from "./utils/formatResult.js";
|
|
22
22
|
import jsonlToJsonFile from "./utils/jsonlToJsonFile.js";
|
|
23
|
+
import pubsub from "./utils/pubsub.js";
|
|
23
24
|
const startStreamWithTotal = 10000;
|
|
24
25
|
const rootDir = getFolder(config, "local");
|
|
25
26
|
/**
|
|
@@ -84,12 +85,6 @@ export default async function exportTable({ pg = pgClients.client, headers, user
|
|
|
84
85
|
reply,
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
|
-
// delete old file, prevent append
|
|
88
|
-
if (cacheFile && (nocache || config.disableCache)) {
|
|
89
|
-
await rm(filePath);
|
|
90
|
-
}
|
|
91
|
-
// create directory if not exists
|
|
92
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
93
88
|
const loadTable = await getTemplate("table", table);
|
|
94
89
|
const meta = await getMeta({ pg, table: loadTable?.table || table });
|
|
95
90
|
const viewSql = await getTemplate("view", loadTable?.table || table);
|
|
@@ -165,12 +160,22 @@ export default async function exportTable({ pg = pgClients.client, headers, user
|
|
|
165
160
|
.split(".")
|
|
166
161
|
.pop()}` // check for json data
|
|
167
162
|
: el.name);
|
|
168
|
-
const
|
|
169
|
-
process.env.NODE_ENV !== "test"
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
163
|
+
const isStream = ((!slice && +filtered > startStreamWithTotal) || stream) &&
|
|
164
|
+
process.env.NODE_ENV !== "test" &&
|
|
165
|
+
!process.env.VITEST;
|
|
166
|
+
const sendOriginal = isStream ? eventStream(reply) : () => { };
|
|
167
|
+
const redisKey = `exportTable:${fileName}`;
|
|
168
|
+
const send = isStream
|
|
169
|
+
? await pubsub(redisKey, (msg, finishStream = false) => {
|
|
170
|
+
sendOriginal(msg, finishStream);
|
|
171
|
+
}, query.reload && user?.user_type?.includes?.("admin"))
|
|
172
|
+
: () => { };
|
|
173
|
+
// delete old file, prevent append
|
|
174
|
+
if (cacheFile && (nocache || config.disableCache)) {
|
|
175
|
+
await rm(filePath);
|
|
176
|
+
}
|
|
177
|
+
// create directory if not exists
|
|
178
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
174
179
|
// export xlsx / csv / json
|
|
175
180
|
const source = loadTable?.title || loadTable?.ua || table || sourceName;
|
|
176
181
|
const interval = setInterval(async () => {
|
|
@@ -248,7 +253,8 @@ export default async function exportTable({ pg = pgClients.client, headers, user
|
|
|
248
253
|
await jsonlToJsonFile(filePathJSON.replace(/.json$/, ".jsonl"));
|
|
249
254
|
clearInterval(interval);
|
|
250
255
|
if (res.error) {
|
|
251
|
-
send(
|
|
256
|
+
send("finish");
|
|
257
|
+
sendOriginal(res.error, 1);
|
|
252
258
|
return reply.status(500).send(res.error);
|
|
253
259
|
}
|
|
254
260
|
logger.file("export/table", {
|
|
@@ -302,7 +308,8 @@ export default async function exportTable({ pg = pgClients.client, headers, user
|
|
|
302
308
|
if (resp.error) {
|
|
303
309
|
return reply.status(resp.status || 500).send(resp.error);
|
|
304
310
|
}
|
|
305
|
-
send("
|
|
311
|
+
send("finish");
|
|
312
|
+
sendOriginal("Файл успішно сформовано. Натистіть кнопку ще раз для завантаження даних", 1);
|
|
306
313
|
return formatResult({
|
|
307
314
|
filePath,
|
|
308
315
|
formatAnswer,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsub.d.ts","sourceRoot":"","sources":["../../../../../../server/routes/file/controllers/utils/pubsub.ts"],"names":[],"mappings":"AAkDA,wBAA8B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,gBA2EzE"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const keyCacheSubscribe = "emit_cache";
|
|
2
|
+
const listenter = {}; // callback send message listener
|
|
3
|
+
const promise = {}; // promise await for subscribe
|
|
4
|
+
const resolve = {}; // resolve
|
|
5
|
+
const publish = {}; // publish
|
|
6
|
+
import config from "../../../../../config.js";
|
|
7
|
+
import getRedis from "../../../../plugins/redis/funcs/getRedis.js";
|
|
8
|
+
// getRedisPublisher
|
|
9
|
+
function getRedisPublisher() {
|
|
10
|
+
const rst = getRedis({
|
|
11
|
+
name: "rst",
|
|
12
|
+
...(config.redis || {}),
|
|
13
|
+
});
|
|
14
|
+
const subscriber = getRedis({
|
|
15
|
+
name: "sub",
|
|
16
|
+
...(config.redis || {}),
|
|
17
|
+
});
|
|
18
|
+
subscriber.unsubscribe(keyCacheSubscribe);
|
|
19
|
+
subscriber.subscribe(keyCacheSubscribe, () => { });
|
|
20
|
+
subscriber.on("message", async (channel, text) => {
|
|
21
|
+
const [code, msg] = text.split("|||");
|
|
22
|
+
if (msg === "finish" && resolve[code]) {
|
|
23
|
+
resolve[code]();
|
|
24
|
+
resolve[code] = null;
|
|
25
|
+
}
|
|
26
|
+
listenter[code].forEach((cb1, i) => {
|
|
27
|
+
cb1(`${msg} - ${i}`);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return rst;
|
|
31
|
+
}
|
|
32
|
+
// native publisher
|
|
33
|
+
function getPublisher() {
|
|
34
|
+
const rst = {
|
|
35
|
+
publish(key, text) {
|
|
36
|
+
const [code, msg] = text.split("|||");
|
|
37
|
+
listenter[code]?.forEach((cb1, i) => {
|
|
38
|
+
cb1?.(`${msg} - ${i}`);
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
return rst;
|
|
43
|
+
}
|
|
44
|
+
// !!! work non cluster mode for cluster subscribe redis
|
|
45
|
+
export default async function subscribe(code, cb, reload) {
|
|
46
|
+
try {
|
|
47
|
+
const rclient = getRedis();
|
|
48
|
+
const { isRedis, timeout = 150 } = config?.redis?.pubsub || {}; // test!
|
|
49
|
+
const publisher = isRedis ? getRedisPublisher() : getPublisher();
|
|
50
|
+
const keyCacheCode = `${keyCacheSubscribe}:${code}`;
|
|
51
|
+
// check code is run
|
|
52
|
+
const isNotRun = await rclient.setnx(keyCacheCode, 1);
|
|
53
|
+
const ttl = await rclient.ttl(keyCacheCode);
|
|
54
|
+
// if Run
|
|
55
|
+
if (!isNotRun && !reload && ttl > 0) {
|
|
56
|
+
// add listener
|
|
57
|
+
cb(`==== run as slave ttl: ${ttl}==== `);
|
|
58
|
+
const alldata = await rclient.lrange(keyCacheCode + ":list", 0, -1);
|
|
59
|
+
alldata.forEach((el) => {
|
|
60
|
+
cb(el);
|
|
61
|
+
});
|
|
62
|
+
// for redis
|
|
63
|
+
if (!listenter[code]) {
|
|
64
|
+
listenter[code] = [];
|
|
65
|
+
promise[code] = new Promise((rsv) => {
|
|
66
|
+
resolve[code] = rsv;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// check master finish
|
|
70
|
+
const interval = setInterval(async () => {
|
|
71
|
+
const ttl1 = await rclient.ttl(keyCacheCode);
|
|
72
|
+
if (ttl1 < 0) {
|
|
73
|
+
clearInterval(interval);
|
|
74
|
+
cb(`finish master timeout ${timeout}`, 1);
|
|
75
|
+
}
|
|
76
|
+
}, 5000);
|
|
77
|
+
listenter[code].push(cb);
|
|
78
|
+
return promise[code];
|
|
79
|
+
}
|
|
80
|
+
await rclient.expire(keyCacheCode, timeout);
|
|
81
|
+
// if not run
|
|
82
|
+
// create return promise
|
|
83
|
+
promise[code] = new Promise((rsv) => {
|
|
84
|
+
resolve[code] = rsv;
|
|
85
|
+
});
|
|
86
|
+
listenter[code] = [cb];
|
|
87
|
+
// listenter[code].push(cb);
|
|
88
|
+
// create publish function
|
|
89
|
+
publish[code] = (msg) => {
|
|
90
|
+
rclient.rpush(keyCacheCode + ":list", msg);
|
|
91
|
+
rclient.expire(keyCacheCode, timeout);
|
|
92
|
+
// send message to all listener
|
|
93
|
+
publisher.publish(keyCacheSubscribe, `${code}|||${msg}`); // redis
|
|
94
|
+
// finish and clear
|
|
95
|
+
if (msg === "finish") {
|
|
96
|
+
// clear code to run again
|
|
97
|
+
rclient.del(keyCacheCode);
|
|
98
|
+
rclient.del(keyCacheCode + ":list");
|
|
99
|
+
// resolve promise
|
|
100
|
+
resolve[code]();
|
|
101
|
+
// clear
|
|
102
|
+
resolve[code] = null;
|
|
103
|
+
promise[code] = null;
|
|
104
|
+
listenter[code] = [];
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return publish[code];
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
console.error(err.toString());
|
|
111
|
+
}
|
|
112
|
+
}
|