@ejfdelgado/ejflab-back 1.1.0

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.
Files changed (64) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -0
  3. package/package.json +57 -0
  4. package/srv/AudIASrv.mjs +218 -0
  5. package/srv/AuthorizationSrv.mjs +213 -0
  6. package/srv/ComputeEngineSrv.mjs +289 -0
  7. package/srv/EmailHandler.mjs +54 -0
  8. package/srv/Image2MeshSrv.mjs +101 -0
  9. package/srv/ImagiationSrv.mjs +408 -0
  10. package/srv/KeysSrv.mjs +104 -0
  11. package/srv/MainHandler.mjs +140 -0
  12. package/srv/MainReplacer.mjs +77 -0
  13. package/srv/MfaSrv.mjs +266 -0
  14. package/srv/MilvusSrv.mjs +152 -0
  15. package/srv/MinioSrv.mjs +154 -0
  16. package/srv/MongoSrv.mjs +320 -0
  17. package/srv/MyError.mjs +48 -0
  18. package/srv/MyFileService.mjs +392 -0
  19. package/srv/MyFileServiceLocal.mjs +177 -0
  20. package/srv/MyPdf.mjs +37 -0
  21. package/srv/MyShell.mjs +205 -0
  22. package/srv/MySqlSrv.mjs +43 -0
  23. package/srv/Network.mjs +111 -0
  24. package/srv/OpenCVSrv.mjs +27 -0
  25. package/srv/PageSrv.mjs +234 -0
  26. package/srv/PayUSrv.mjs +186 -0
  27. package/srv/PayUSrvConstants.mjs +46 -0
  28. package/srv/PostgresSrv.mjs +109 -0
  29. package/srv/SecretsSrv.mjs +126 -0
  30. package/srv/SocketIOCall.mjs +494 -0
  31. package/srv/TupleSrv.mjs +141 -0
  32. package/srv/UtilesSrv.mjs +8 -0
  33. package/srv/callprocessors/AskIceServersProcessor.mjs +14 -0
  34. package/srv/callprocessors/AskRoomProcessor.mjs +15 -0
  35. package/srv/callprocessors/CallUserProcessor.mjs +17 -0
  36. package/srv/callprocessors/ChatSetSawProcessor.mjs +42 -0
  37. package/srv/callprocessors/CheckSrcResponseProcessor.mjs +28 -0
  38. package/srv/callprocessors/ClientChangeProcessor.mjs +19 -0
  39. package/srv/callprocessors/CloseVideoChatProcessor.mjs +16 -0
  40. package/srv/callprocessors/DestroyModelProcessor.mjs +16 -0
  41. package/srv/callprocessors/DisconnectProcessor.mjs +53 -0
  42. package/srv/callprocessors/GenericProcessor.mjs +7 -0
  43. package/srv/callprocessors/GetModelProcessor.mjs +11 -0
  44. package/srv/callprocessors/IncludeOtherPeersProcessor.mjs +12 -0
  45. package/srv/callprocessors/LoadFlowChartProcessor.mjs +103 -0
  46. package/srv/callprocessors/MakeAnswerProcessor.mjs +17 -0
  47. package/srv/callprocessors/OnIceCandidateProcessor.mjs +13 -0
  48. package/srv/callprocessors/OpenVideoChatProcessor.mjs +17 -0
  49. package/srv/callprocessors/PauseFlowChartProcessor.mjs +16 -0
  50. package/srv/callprocessors/ProcessResponseProcessor.mjs +123 -0
  51. package/srv/callprocessors/ReadSrcResponseProcessor.mjs +30 -0
  52. package/srv/callprocessors/RegisterProcessorProcessor.mjs +23 -0
  53. package/srv/callprocessors/RegisterSourceProcessor.mjs +22 -0
  54. package/srv/callprocessors/SendChatProcessor.mjs +71 -0
  55. package/srv/callprocessors/StartFlowChartProcessor.mjs +48 -0
  56. package/srv/callprocessors/StopFlowChartProcessor.mjs +16 -0
  57. package/srv/callprocessors/SubscribemeProcessor.mjs +13 -0
  58. package/srv/callprocessors/UpdateMyInformationProcessor.mjs +30 -0
  59. package/srv/common/FirebasConfig.mjs +160 -0
  60. package/srv/common/General.mjs +69 -0
  61. package/srv/common/MimeTypeMap.mjs +142 -0
  62. package/srv/common/MyStore.mjs +169 -0
  63. package/srv/common/Usuario.mjs +101 -0
  64. package/srv/common/Utilidades.mjs +43 -0
@@ -0,0 +1,77 @@
1
+ import { MyConstants } from "@ejfdelgado/ejflab-common/src/MyConstants.js";
2
+ import { MyUtilities } from "@ejfdelgado/ejflab-common/src/MyUtilities.js"
3
+
4
+ export class MainReplacer {
5
+ static replace(rta, replaces, theUrl) {
6
+ const REMPLAZOS = [
7
+ {
8
+ old: /name="og:title"[\s]+content="[^"]*"/,
9
+ new: `name="og:title" content="${MyUtilities.htmlEntities(replaces.tit)}"`,
10
+ empty: typeof replaces.tit != "string" || replaces.tit.length == 0,
11
+ },
12
+ {
13
+ old: /name="og:description"[\s]+content="[^"]*"/,
14
+ new: `name="og:description" content="${MyUtilities.htmlEntities(
15
+ replaces.desc
16
+ )}"`,
17
+ empty: typeof replaces.desc != "string" || replaces.desc.length == 0,
18
+ },
19
+ {
20
+ old: /name="og:image"[\s]+content="[^"]*"/,
21
+ new: `name="og:image" content="${replaces.img}"`,
22
+ empty: typeof replaces.img != "string" || replaces.img.length == 0,
23
+ },
24
+ {
25
+ old: /name="og:url"[\s]+content="[^"]*"/,
26
+ new: `name="og:url" content="${theUrl.href}"`,
27
+ },
28
+ {
29
+ old: /name="keywords"[\s]+content="[^"]*"/,
30
+ new: `name="keywords" content="${replaces.kw}"`,
31
+ empty: typeof replaces.kw != "string" || replaces.kw.length == 0,
32
+ },
33
+ {
34
+ old: /<title>.*?<\/title>/,
35
+ new: `<title>${MyUtilities.htmlEntities(replaces.tit)}<\/title>`,
36
+ empty: typeof replaces.tit != "string" || replaces.tit.length == 0,
37
+ },
38
+ {
39
+ old: /name="pageId"[\s]*content="[^"]*"/,
40
+ new: `name="pageId" content="${replaces.id}"`,
41
+ empty: typeof replaces.id != "string" || replaces.id.length == 0,
42
+ },
43
+ {
44
+ old: /name="random"[\s]*content="[^"]*"/,
45
+ new: `name="random" content="${replaces.pass}"`,
46
+ empty: typeof replaces.pass != "string" || replaces.pass.length == 0,
47
+ },
48
+ {
49
+ old: /name="custom"[\s]*content="[^"]*"/,
50
+ new: `name="custom" content="${replaces.firebase}"`,
51
+ empty: typeof replaces.firebase != "string" || replaces.firebase.length == 0,
52
+ },
53
+ {
54
+ old: /name="time"[\s]*content="[^"]*"/,
55
+ new: `name="time" content="${replaces.time}"`,
56
+ empty: typeof replaces.time != "string" || replaces.time.length == 0,
57
+ },
58
+ {
59
+ old: /<base[\s]*href="[^"]*">/,
60
+ new: `<base href="${MyConstants.SRV_ROOT}">`,
61
+ empty: typeof replaces.time != "string" || replaces.time.length == 0,
62
+ }
63
+ ];
64
+ if (
65
+ rta != null &&
66
+ typeof rta.data == "string" &&
67
+ rta.metadata.filename == "index.html"
68
+ ) {
69
+ for (let i = 0; i < REMPLAZOS.length; i++) {
70
+ const remplazo = REMPLAZOS[i];
71
+ if (!remplazo.empty) {
72
+ rta.data = rta.data.replace(remplazo.old, remplazo.new);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
package/srv/MfaSrv.mjs ADDED
@@ -0,0 +1,266 @@
1
+ import { MyStore } from "./common/MyStore.mjs";
2
+ import { General } from "./common/General.mjs";
3
+ import axios from "axios";
4
+ import { ModuloDatoSeguroBack } from "@ejfdelgado/ejflab-common/src/ModuloDatoSeguroBack.mjs";
5
+
6
+ const MAX_READ_SIZE = 60;
7
+
8
+ const FACE_SERVER = process.env.FACE_SERVER;
9
+
10
+ export class MfaSrv {
11
+ static async computeVector(req, res, next) {
12
+ const imgId = General.readParam(req, "imgid");
13
+ const url = `${FACE_SERVER}compute?imgid=${imgId}`;
14
+ const responseRequest = await new Promise((resolve, reject) => {
15
+ const options = {};
16
+ axios.get(url, options)
17
+ .then(res => {
18
+ resolve(res)
19
+ })
20
+ .catch(error => {
21
+ reject(Error(error.response.data))
22
+ });
23
+ });
24
+ const response = responseRequest.data;
25
+ res.status(200).send({
26
+ status: "ok",
27
+ response
28
+ });
29
+ }
30
+ static async validateFace(req, res, next) {
31
+ const base64 = General.readParam(req, "base64");
32
+ const searchtype = General.readParam(req, "searchtype");
33
+ const value = General.readParam(req, "value");
34
+ const url = `${FACE_SERVER}validateface`;
35
+ const responseRequest = await new Promise((resolve, reject) => {
36
+ const options = {};
37
+ axios.post(url, { base64, searchtype, value }, options)
38
+ .then(res => { resolve(res) })
39
+ .catch(error => {
40
+ reject(Error(error.response.data))
41
+ });
42
+ });
43
+ const response = responseRequest.data;
44
+ res.status(200).send({
45
+ status: "ok",
46
+ response
47
+ });
48
+ }
49
+ static async save(req, res, next) {
50
+ const token = res.locals.token;
51
+ const AHORA = new Date().getTime();
52
+ const image = General.readParam(req, "image");
53
+ const pageId = req.params['pageId'];
54
+ const pageType = "mfa";
55
+
56
+ if (image instanceof Array) {
57
+ for (let i = 0; i < image.length; i++) {
58
+ const image1 = image[i];
59
+ image1.author = token.email;
60
+ image1.updated = AHORA;
61
+ image1.pg = pageId;
62
+ image1.pageType = pageType;
63
+ MfaSrv.serializeImage(image1);
64
+ if (image1.id) {
65
+ await MyStore.updateById("mfaimg", image1.id, image1);
66
+ } else {
67
+ image1.created = AHORA;
68
+ await MyStore.create("mfaimg", image1);
69
+ }
70
+ MfaSrv.deserializeImage(image1);
71
+ }
72
+ } else {
73
+ image.author = token.email;
74
+ image.updated = AHORA;
75
+ image.pg = pageId;
76
+ image.pageType = pageType;
77
+ MfaSrv.serializeImage(image);
78
+ if (image.id) {
79
+ await MyStore.updateById("mfaimg", image.id, image);
80
+ } else {
81
+ image.created = AHORA;
82
+ await MyStore.create("mfaimg", image);
83
+ }
84
+ MfaSrv.deserializeImage(image);
85
+ }
86
+
87
+ res.status(200).send({
88
+ status: "ok",
89
+ image
90
+ });
91
+ }
92
+ static serializeImage(image) {
93
+ //
94
+ }
95
+ static deserializeImage(image) {
96
+ //
97
+ }
98
+ static async validateuid(req, res, next) {
99
+ const pageId = req.params['pageId'];
100
+ const uid = General.readParam(req, "uid");
101
+ const imgid = General.readParam(req, "imgid");
102
+ const page = await MyStore.readById("page", pageId);
103
+ const pass = page.pass;
104
+ if (!pass) {
105
+ throw Error("Primero debe generar las llaves secretas de la página");
106
+ }
107
+ let validated = false;
108
+ try {
109
+ const decifrado = ModuloDatoSeguroBack.decifrarSimple(uid, pass);
110
+ const respuesta = /^(.{2})_([^_]*)_(.{2})$/.exec(decifrado);
111
+ validated = (respuesta != null && respuesta[2] == imgid);
112
+ } catch (err) { }
113
+ res.status(200).send({
114
+ status: "ok",
115
+ validated,
116
+ });
117
+ }
118
+ static async rotate(req, res, next) {
119
+ const pageId = req.params['pageId'];
120
+ const imgid = General.readParam(req, "imgid");
121
+ const page = await MyStore.readById("page", pageId);
122
+ const pass = page.pass;
123
+ if (!pass) {
124
+ throw Error("Primero debe generar las llaves secretas de la página");
125
+ }
126
+ const rand1 = ModuloDatoSeguroBack.generateKey(2);
127
+ const rand2 = ModuloDatoSeguroBack.generateKey(2);
128
+ const dato = `${rand1}_${imgid}_${rand2}`;
129
+ const uid = ModuloDatoSeguroBack.cifrarSimple(dato, pass);
130
+ // Guardo el uid
131
+ await MyStore.updateById("mfaimg", imgid, { uid });
132
+ res.status(200).send({
133
+ status: "ok",
134
+ uid,
135
+ });
136
+ }
137
+ static async read(req, res, next) {
138
+ const { max, offset } = General.readMaxOffset(req, MAX_READ_SIZE);
139
+ const max_date = parseInt(General.readParam(req, "max_date", 0));
140
+ const min_date = parseInt(General.readParam(req, "min_date", 0));
141
+ let response = [];
142
+ const pageId = req.params['pageId'];
143
+ // Se debe realizar la lectura como tal
144
+ const where = [
145
+ { key: "pg", oper: "==", value: pageId },
146
+ ];
147
+ if (!isNaN(max_date) && max_date > 0) {
148
+ where.push({ key: "created", oper: "<=", value: max_date });
149
+ }
150
+ if (!isNaN(min_date) && min_date > 0) {
151
+ where.push({ key: "created", oper: ">=", value: min_date });
152
+ }
153
+ const select = ["created", "updated", "author", "pg", "urlBig", "urlThumbnail", "name", "lastname", "idType", "uid", "face_confidence", "embedding_time"];
154
+ response = await MyStore.paginate("mfaimg", [{ name: "created", dir: 'desc' }], offset, max, where, null, select);
155
+ for (let i = 0; i < response.length; i++) {
156
+ const image = response[i];
157
+ MfaSrv.deserializeImage(image);
158
+ }
159
+ res.status(200).send({
160
+ status: "ok",
161
+ images: response,
162
+ });
163
+ }
164
+ static async delete(req, res, next) {
165
+ const image = General.readParam(req, "image");
166
+
167
+ if (image instanceof Array) {
168
+ for (let i = 0; i < image.length; i++) {
169
+ if (image1.id) {
170
+ await MyStore.deleteById("mfaimg", image1.id);
171
+ }
172
+ }
173
+ } else {
174
+ await MyStore.deleteById("mfaimg", image.id);
175
+ }
176
+
177
+ res.status(200).send({
178
+ status: "ok",
179
+ image: []
180
+ });
181
+ }
182
+
183
+ static async createUpdateEnrollmentLink(req, res, next) {
184
+ const imgid = General.readParam(req, "imgid");
185
+ const origin = General.readParam(req, "origin");
186
+ const pageId = req.params['pageId'];
187
+ const AHORA = new Date().getTime();
188
+
189
+ let [mfaenrollment, image, page] = await Promise.all([
190
+ MyStore.readById("mfaenrollment", imgid),
191
+ MyStore.readById("mfaimg", imgid),
192
+ MyStore.readById("page", pageId),
193
+ ]);
194
+
195
+ if (mfaenrollment) {
196
+ mfaenrollment.created = AHORA;
197
+ await MyStore.updateById("mfaenrollment", imgid, mfaenrollment);
198
+ } else {
199
+ mfaenrollment = {
200
+ created: AHORA,
201
+ name: `${image.name} ${image.lastname}`,
202
+ id: imgid,
203
+ };
204
+ await MyStore.createById("mfaenrollment", imgid, mfaenrollment);
205
+ }
206
+
207
+ const cifrado = ModuloDatoSeguroBack.cifrar({ id: mfaenrollment.id, t: AHORA }, page.public2);
208
+
209
+ const url = `${origin}/mfaenrollment/?pg=${pageId}&data=${cifrado}`;
210
+ //const srv = `http://localhost:8081/srv/mfa/${pageId}/executeenrollment?pass=hey&data=${cifrado}`;
211
+
212
+ res.status(200).send({
213
+ status: "ok",
214
+ mfaenrollment,
215
+ url,
216
+ //srv
217
+ });
218
+ }
219
+
220
+ static async executeEnrollment(req, res, next) {
221
+ const data = General.readParam(req, "data");
222
+ const pass = General.readParam(req, "pass");
223
+ const pageId = req.params['pageId'];
224
+ const AHORA = new Date().getTime();
225
+ const MAX_TIME = 1000 * 60 * 60 * 24 * 1;// 1 día
226
+
227
+ if (!data) {
228
+ throw Error("Err A");
229
+ }
230
+
231
+ if (!pass) {
232
+ throw Error("Err Z");
233
+ }
234
+
235
+ const page = await MyStore.readById("page", pageId);
236
+ if (!page) {
237
+ throw Error("Err 0");
238
+ }
239
+ const decifrado = ModuloDatoSeguroBack.decifrar(data, page.private2);
240
+ const imgid = decifrado.id;
241
+ const t = decifrado.t;
242
+
243
+ const mfaenrollment = await MyStore.readById("mfaenrollment", imgid);
244
+ if (!mfaenrollment) {
245
+ throw Error("Err 1");
246
+ }
247
+ if (mfaenrollment.created != t) {
248
+ throw Error("Err B");
249
+ }
250
+ const difference = AHORA - mfaenrollment.created;
251
+ if (difference > MAX_TIME) {
252
+ throw Error("El enlace caducó, pide ayuda a soporte.");
253
+ }
254
+
255
+ await MyStore.runTransaction(async (firebaseInstance) => {
256
+ await Promise.all([
257
+ MyStore.updateById("mfaimg", imgid, { pass }, firebaseInstance),
258
+ MyStore.deleteById("mfaenrollment", imgid, firebaseInstance),
259
+ ]);
260
+ });
261
+
262
+ res.status(200).send({
263
+ status: "ok",
264
+ });
265
+ }
266
+ }
@@ -0,0 +1,152 @@
1
+ import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
2
+
3
+ export class MilvusSrv {
4
+ // MilvusSrv.checkErrors(res);
5
+ static checkErrors(res) {
6
+ let status = res;
7
+ if ("status" in status) {
8
+ status = status.status;
9
+ }
10
+ if (status.error_code != "Success") {
11
+ throw new Error(status.reason);
12
+ }
13
+ }
14
+ static connect() {
15
+ const uri = process.env.MILVUS_URI;
16
+ console.log(`Milvus uri ${uri}`);
17
+ const parts = /^\s*(https?):\/\/([^:]+):(\d+)\s*$/i.exec(uri)
18
+ const scheme = parts[1];
19
+ const host = parts[2];
20
+ const port = parts[3];
21
+ const client = new MilvusClient(uri);
22
+ return {
23
+ scheme,
24
+ host,
25
+ port,
26
+ client
27
+ }
28
+ }
29
+ static async existsDatabase(client, name) {
30
+ const res = await client.listDatabases();
31
+ return res.db_names.indexOf(name) >= 0;
32
+ }
33
+ static async existsCollection(client, name) {
34
+ const resListCollections = await client.listCollections();
35
+ MilvusSrv.checkErrors(resListCollections);
36
+ const { data } = resListCollections;
37
+ return data.indexOf(name) >= 0;
38
+ }
39
+ static async introspect(client) {
40
+ const res = await client.listDatabases();
41
+ MilvusSrv.checkErrors(res);
42
+ const databases = res.db_names;
43
+ for (let i = 0; i < databases.length; i++) {
44
+ const database = databases[i];
45
+ console.log(`- Database: ${database}`);
46
+ const resUseDatabase = await client.useDatabase({ db_name: database });
47
+ MilvusSrv.checkErrors(resUseDatabase);
48
+ const resListCollections = await client.listCollections();
49
+ MilvusSrv.checkErrors(resListCollections);
50
+ const { data } = resListCollections;
51
+ for (let j = 0; j < data.length; j++) {
52
+ const collection = data[j];
53
+ console.log(` - Collection: ${collection.name}`);
54
+ }
55
+ }
56
+ }
57
+ static async dropDatabaseTemp(client) {
58
+ const res = await client.listDatabases();
59
+ MilvusSrv.checkErrors(res);
60
+ const databases = res.db_names;
61
+ for (let i = 0; i < databases.length; i++) {
62
+ const database = databases[i];
63
+ if (database.startsWith("temp_")) {
64
+ await MilvusSrv.dropDatabase(client, database)
65
+ }
66
+ }
67
+ }
68
+ static async dropCollection(client, collection_name) {
69
+ console.log(`Drop collection ${collection_name}...`);
70
+ const resHasCollection = await client.hasCollection({ collection_name });
71
+ MilvusSrv.checkErrors(resHasCollection);
72
+ if (!resHasCollection.value) {
73
+ console.log(`Drop collection ${collection_name} NOT EXISTS...`);
74
+ return false;
75
+ }
76
+ const resDrop = await client.dropCollection({ collection_name });
77
+ MilvusSrv.checkErrors(resDrop);
78
+ console.log(`Drop collection ${collection_name}... OK`);
79
+ return true;
80
+ }
81
+ static async dropDatabase(client, name) {
82
+ console.log(`Drop database ${name}...`);
83
+ const resUseDatabase1 = await client.useDatabase({ db_name: name });
84
+ MilvusSrv.checkErrors(resUseDatabase1);
85
+ const resListCollections = await client.listCollections();
86
+ MilvusSrv.checkErrors(resListCollections);
87
+ const { data } = resListCollections;
88
+ for (let j = 0; j < data.length; j++) {
89
+ const collection = data[j];
90
+ await MilvusSrv.dropCollection(client, collection.name);
91
+ }
92
+ const resDropDatabase = await client.dropDatabase({ db_name: name });
93
+ MilvusSrv.checkErrors(resDropDatabase);
94
+ }
95
+ static async useDatabase(client, name, recreate = false) {
96
+ console.log(`Use database ${name} recreate? ${recreate}...`);
97
+ if (!await MilvusSrv.existsDatabase(client, name)) {
98
+ console.log(`Creating '${name}' database...`);
99
+ const resCreate = await client.createDatabase({ db_name: name });
100
+ MilvusSrv.checkErrors(resCreate);
101
+ } else {
102
+ if (recreate) {
103
+ console.log(`Recreating '${name}' database...`);
104
+ await MilvusSrv.dropDatabase(client, name);
105
+ const resCreate = await client.createDatabase({ db_name: name });
106
+ MilvusSrv.checkErrors(resCreate);
107
+ } else {
108
+ console.log(`Using old '${name}' database...`);
109
+ }
110
+ }
111
+ const resUseDatabase2 = await client.useDatabase({ db_name: name });
112
+ MilvusSrv.checkErrors(resUseDatabase2);
113
+ console.log(`Use database ${name} recreate? ${recreate}... OK`);
114
+ }
115
+ static getDataType(text) {
116
+ const parts = text.split(".");
117
+ return DataType[parts[1]];
118
+ }
119
+ static async createCollectionWithSchema(client, myJson, recreate = false) {
120
+ // Translate data types
121
+ const myCopy = JSON.parse(JSON.stringify(myJson));
122
+ const collection_name = myCopy.collection_name;
123
+ const exists = await this.existsCollection(client, collection_name);
124
+ if (exists) {
125
+ if (recreate) {
126
+ // Erase
127
+ await MilvusSrv.dropCollection(client, collection_name);
128
+ } else {
129
+ // Do nothing
130
+ console.log(`Using old collection ${collection_name}`);
131
+ return;
132
+ }
133
+ }
134
+ const { fields } = myCopy;
135
+ for (let i = 0; i < fields.length; i++) {
136
+ const field = fields[i];
137
+ field.data_type = MilvusSrv.getDataType(field.data_type);
138
+ }
139
+ const res = await client.createCollection(myCopy);
140
+ MilvusSrv.checkErrors(res);
141
+ }
142
+ static async ping(req, res, next) {
143
+ const { client } = MilvusSrv.connect();
144
+ const databases = await client.listDatabases();
145
+ MilvusSrv.checkErrors(databases);
146
+ const response = {
147
+ databases,
148
+ status: "ok",
149
+ };
150
+ res.status(200).send(response);
151
+ }
152
+ }
@@ -0,0 +1,154 @@
1
+ import * as Minio from 'minio';
2
+ import { Buffer } from 'buffer';
3
+ import { NoExisteException } from './MyError.mjs';
4
+ import { decode } from "@msgpack/msgpack";
5
+
6
+ export class MinioSrv {
7
+ static getClient() {
8
+ const uri = process.env.MINIO_URI;
9
+ const uriParts = /^\s*([^:]+):(\d+)\s*$/.exec(uri);
10
+ if (!uriParts) {
11
+ throw new Error(`Bad MINIO_URI ${uri}`);
12
+ }
13
+ const minioClient = new Minio.Client({
14
+ endPoint: uriParts[1],
15
+ port: parseInt(uriParts[2]),
16
+ useSSL: false,
17
+ accessKey: process.env.MINIO_ACCESS_KEY,
18
+ secretKey: process.env.MINIO_SECRET_KEY,
19
+ });
20
+ return minioClient;
21
+ }
22
+ static async assureBucket(minioClient, bucket, region = "us-east-1") {
23
+ const exists = await minioClient.bucketExists(bucket)
24
+ if (exists) {
25
+ //console.log(`Bucket ${bucket} exists.`);
26
+ } else {
27
+ await minioClient.makeBucket(bucket, region)
28
+ //console.log(`Bucket ${bucket} created in "${region}".`);
29
+ }
30
+ }
31
+ static async putObject(minioClient, bucketName, objectPath, buffer, metadata = {}) {
32
+ return new Promise((resolve, reject) => {
33
+ minioClient.putObject(bucketName, objectPath, buffer, Buffer.byteLength(buffer), metadata, function (err, etag) {
34
+ if (err) {
35
+ reject(err);
36
+ } else {
37
+ resolve(etag);
38
+ }
39
+ });
40
+ });
41
+ }
42
+ static async stream2Buffer(stream) {
43
+ return new Promise((resolve, reject) => {
44
+ const _buf = [];
45
+ stream.on("data", (chunk) => _buf.push(chunk));
46
+ stream.on("end", () => resolve(Buffer.concat(_buf)));
47
+ stream.on("error", (err) => reject(err));
48
+ });
49
+ }
50
+ static async getObject(minioClient, bucketName, objectPath) {
51
+ const readedMetadataPromise = minioClient.statObject(bucketName, objectPath);
52
+ const dataStreamPromise = new Promise(async (resolve, reject) => {
53
+ try {
54
+ const dataStream = await minioClient.getObject(bucketName, objectPath);
55
+ const bytes = await MinioSrv.stream2Buffer(dataStream);
56
+ resolve(bytes);
57
+ } catch (err) {
58
+ reject(err);
59
+ }
60
+ });
61
+ try {
62
+ const [readedMetadata, bytes] = await Promise.all([readedMetadataPromise, dataStreamPromise]);
63
+ const metadata = readedMetadata.metaData;
64
+ metadata['Last-Modified'] = readedMetadata.lastModified;
65
+ return {
66
+ data: bytes,
67
+ metadata,
68
+ };
69
+ } catch (err) {
70
+ if (err.code == 'NotFound') {
71
+ throw new NoExisteException(`Not found ${objectPath} on ${bucketName}`);
72
+ } else {
73
+ throw err;
74
+ }
75
+ }
76
+ }
77
+ static async test(req, res, next) {
78
+ const minioClient = MinioSrv.getClient();
79
+ const bucketName = "public";
80
+ const objectPath = "local/myFile.txt";
81
+ const b64string = "Hola cómo estás?";
82
+ const metaData = { 'Content-Type': 'text/plain; charset=utf-8' };
83
+
84
+ await MinioSrv.assureBucket(minioClient, bucketName);
85
+ const buffer = Buffer.from(b64string, 'utf8');
86
+ const putResponse = await MinioSrv.putObject(minioClient, bucketName, objectPath, buffer, metaData);
87
+
88
+ const getResponse = await MinioSrv.getObject(minioClient, bucketName, objectPath);
89
+
90
+ const headers = getResponse.metadata;
91
+ headers['Content-disposition'] = "inline; filename=name.txt";
92
+ //headers['Cache-Control'] = "max-age=0";
93
+
94
+ res.writeHead(200, headers);
95
+ res.end(getResponse.data);
96
+ }
97
+ static async readFile(req, res, next) {
98
+ const bucketName = req.params['bucket'];
99
+ const downloadFlag = req.query ? req.query.download : false;
100
+ const minioClient = MinioSrv.getClient();
101
+ await MinioSrv.assureBucket(minioClient, bucketName);
102
+ const cleanedUrl = decodeURIComponent(req.originalUrl.replace(/^\//, "").replace(/\?.*$/, ""));
103
+ const urlParts = /^srv\/minio\/[^\/]+\/(.*)$/.exec(cleanedUrl);
104
+ const objectPath = urlParts[1];
105
+ const getResponse = await MinioSrv.getObject(minioClient, bucketName, objectPath);
106
+ const headers = getResponse.metadata;
107
+ const fileName = /([^\/]+)$/.exec(objectPath)[1];
108
+ if (downloadFlag != undefined) {
109
+ headers['Content-disposition'] = `attachment; filename=${fileName}`;
110
+ } else {
111
+ headers['Content-disposition'] = `inline; filename=${fileName}`;
112
+ }
113
+ if (req.query.max_age) {
114
+ headers["Cache-Control"] = `max-age=${req.query.max_age}`;
115
+ }
116
+ res.writeHead(200, headers);
117
+ res.end(getResponse.data);
118
+ }
119
+ static async writeFileLocal(bucketName, fileList) {
120
+ const minioClient = MinioSrv.getClient();
121
+ await MinioSrv.assureBucket(minioClient, bucketName);
122
+ const promesas = [];
123
+ // Ensure it is an array
124
+ if (!(fileList instanceof Array)) {
125
+ fileList = [fileList];
126
+ }
127
+ for (let i = 0; i < fileList.length; i++) {
128
+ const someFile = fileList[i];
129
+ const { objectPath, bytes, metadata } = someFile;
130
+ const promesa = MinioSrv.putObject(minioClient, bucketName, objectPath, bytes, metadata);
131
+ promesas.push(promesa);
132
+ }
133
+ await Promise.all(promesas);
134
+ }
135
+ static async writeFile(req, res, next) {
136
+ const bucketName = req.params['bucket'];
137
+ const buffer = req.body;
138
+ const fileList = decode(buffer);
139
+ await MinioSrv.writeFileLocal(bucketName, fileList);
140
+ const response = {
141
+ status: "ok",
142
+ };
143
+ res.status(200).send(response);
144
+ }
145
+ static async ping(req, res, next) {
146
+ const minioClient = MinioSrv.getClient();
147
+ const buckets = await minioClient.listBuckets();
148
+ const response = {
149
+ buckets,
150
+ status: "ok",
151
+ };
152
+ res.status(200).send(response);
153
+ }
154
+ }