@prosopo/database 1.0.1 → 2.0.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.
- package/dist/captchaDatabase/captchaDatabase.d.ts +4 -0
- package/dist/captchaDatabase/captchaDatabase.d.ts.map +1 -0
- package/dist/captchaDatabase/captchaDatabase.js +31 -0
- package/dist/captchaDatabase/captchaDatabase.js.map +1 -0
- package/dist/captchaDatabase/index.d.ts +2 -0
- package/dist/captchaDatabase/index.d.ts.map +1 -0
- package/dist/captchaDatabase/index.js +2 -0
- package/dist/captchaDatabase/index.js.map +1 -0
- package/dist/cjs/captchaDatabase/captchaDatabase.cjs +37 -0
- package/dist/cjs/captchaDatabase/index.cjs +4 -0
- package/dist/cjs/databases/mongo.cjs +189 -67
- package/dist/cjs/databases/mongoMemory.cjs +1 -1
- package/dist/cjs/index.cjs +3 -0
- package/dist/databases/index.d.ts +2 -2
- package/dist/databases/index.d.ts.map +1 -1
- package/dist/databases/index.js +3 -3
- package/dist/databases/index.js.map +1 -1
- package/dist/databases/mongo.d.ts +10 -7
- package/dist/databases/mongo.d.ts.map +1 -1
- package/dist/databases/mongo.js +200 -119
- package/dist/databases/mongo.js.map +1 -1
- package/dist/databases/mongoMemory.d.ts +2 -2
- package/dist/databases/mongoMemory.d.ts.map +1 -1
- package/dist/databases/mongoMemory.js +2 -2
- package/dist/databases/mongoMemory.js.map +1 -1
- package/dist/eventsDatabase/eventsDatabase.d.ts +1 -1
- package/dist/eventsDatabase/eventsDatabase.d.ts.map +1 -1
- package/dist/eventsDatabase/eventsDatabase.js +8 -6
- package/dist/eventsDatabase/eventsDatabase.js.map +1 -1
- package/dist/eventsDatabase/index.d.ts +1 -1
- package/dist/eventsDatabase/index.d.ts.map +1 -1
- package/dist/eventsDatabase/index.js +1 -1
- package/dist/eventsDatabase/index.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +44 -53
- package/vite.cjs.config.ts +3 -3
- package/typedoc.config.js +0 -19
package/dist/databases/mongo.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { ServerApiVersion } from
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const DEFAULT_ENDPOINT = 'mongodb://127.0.0.1:27017';
|
|
1
|
+
import { isHex } from "@polkadot/util/is";
|
|
2
|
+
import { AsyncFactory, ProsopoDBError, ProsopoEnvError, getLoggerDefault, } from "@prosopo/common";
|
|
3
|
+
import { CaptchaStates, CaptchaStatus, DatasetWithIdsAndTreeSchema, ScheduledTaskNames, ScheduledTaskStatus, } from "@prosopo/types";
|
|
4
|
+
import { CaptchaRecordSchema, DatasetRecordSchema, PendingRecordSchema, PowCaptchaRecordSchema, ScheduledTaskRecordSchema, ScheduledTaskSchema, SolutionRecordSchema, UserCommitmentRecordSchema, UserCommitmentSchema, UserSolutionRecordSchema, UserSolutionSchema, } from "@prosopo/types-database";
|
|
5
|
+
import { ServerApiVersion } from "mongodb";
|
|
6
|
+
import mongoose from "mongoose";
|
|
7
|
+
mongoose.set("strictQuery", false);
|
|
8
|
+
const DEFAULT_ENDPOINT = "mongodb://127.0.0.1:27017";
|
|
10
9
|
export class ProsopoDatabase extends AsyncFactory {
|
|
11
10
|
constructor() {
|
|
12
11
|
super();
|
|
13
|
-
this.url =
|
|
14
|
-
this.dbname =
|
|
12
|
+
this.url = "";
|
|
13
|
+
this.dbname = "";
|
|
15
14
|
this.logger = getLoggerDefault();
|
|
16
15
|
}
|
|
17
16
|
async init(url, dbname, logger, authSource) {
|
|
@@ -19,7 +18,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
19
18
|
const parsedUrl = new URL(baseEndpoint);
|
|
20
19
|
parsedUrl.pathname = dbname;
|
|
21
20
|
if (authSource) {
|
|
22
|
-
parsedUrl.searchParams.set(
|
|
21
|
+
parsedUrl.searchParams.set("authSource", authSource);
|
|
23
22
|
}
|
|
24
23
|
this.url = parsedUrl.toString();
|
|
25
24
|
this.dbname = dbname;
|
|
@@ -28,7 +27,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
28
27
|
}
|
|
29
28
|
getTables() {
|
|
30
29
|
if (!this.tables) {
|
|
31
|
-
throw new ProsopoDBError(
|
|
30
|
+
throw new ProsopoDBError("DATABASE.TABLES_UNDEFINED", {
|
|
32
31
|
context: { failedFuncName: this.getTables.name },
|
|
33
32
|
logger: this.logger,
|
|
34
33
|
});
|
|
@@ -37,7 +36,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
37
36
|
}
|
|
38
37
|
getConnection() {
|
|
39
38
|
if (!this.connection) {
|
|
40
|
-
throw new ProsopoDBError(
|
|
39
|
+
throw new ProsopoDBError("DATABASE.CONNECTION_UNDEFINED", {
|
|
41
40
|
context: { failedFuncName: this.getConnection.name },
|
|
42
41
|
logger: this.logger,
|
|
43
42
|
});
|
|
@@ -45,48 +44,51 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
45
44
|
return this.connection;
|
|
46
45
|
}
|
|
47
46
|
async connect() {
|
|
48
|
-
this.logger.info(`Mongo url: ${this.url.replace(/\w+:\w+/,
|
|
47
|
+
this.logger.info(`Mongo url: ${this.url.replace(/\w+:\w+/, "<Credentials>")}`);
|
|
49
48
|
this.connection = await new Promise((resolve, reject) => {
|
|
50
49
|
const connection = mongoose.createConnection(this.url, {
|
|
51
50
|
dbName: this.dbname,
|
|
52
51
|
serverApi: ServerApiVersion.v1,
|
|
53
52
|
});
|
|
54
|
-
connection.on(
|
|
53
|
+
connection.on("open", () => {
|
|
55
54
|
this.logger.info(`Database connection to ${this.url} opened`);
|
|
56
55
|
resolve(connection);
|
|
57
56
|
});
|
|
58
|
-
connection.on(
|
|
57
|
+
connection.on("error", (err) => {
|
|
59
58
|
this.logger.error(`Database error: ${err}`);
|
|
60
59
|
reject(err);
|
|
61
60
|
});
|
|
62
|
-
connection.on(
|
|
61
|
+
connection.on("connected", () => {
|
|
63
62
|
this.logger.info(`Database connected to ${this.url}`);
|
|
63
|
+
resolve(connection);
|
|
64
64
|
});
|
|
65
|
-
connection.on(
|
|
65
|
+
connection.on("disconnected", () => {
|
|
66
66
|
this.logger.info(`Database disconnected from ${this.url}`);
|
|
67
67
|
});
|
|
68
|
-
connection.on(
|
|
68
|
+
connection.on("reconnected", () => {
|
|
69
69
|
this.logger.info(`Database reconnected to ${this.url}`);
|
|
70
|
+
resolve(connection);
|
|
70
71
|
});
|
|
71
|
-
connection.on(
|
|
72
|
+
connection.on("reconnectFailed", () => {
|
|
72
73
|
this.logger.error(`Database reconnect failed to ${this.url}`);
|
|
73
74
|
});
|
|
74
|
-
connection.on(
|
|
75
|
+
connection.on("close", () => {
|
|
75
76
|
this.logger.info(`Database connection to ${this.url} closed`);
|
|
76
77
|
});
|
|
77
|
-
connection.on(
|
|
78
|
+
connection.on("fullsetup", () => {
|
|
78
79
|
this.logger.info(`Database connection to ${this.url} is fully setup`);
|
|
80
|
+
resolve(connection);
|
|
79
81
|
});
|
|
80
82
|
});
|
|
81
83
|
this.tables = {
|
|
82
|
-
captcha: this.connection.model(
|
|
83
|
-
powCaptcha: this.connection.model(
|
|
84
|
-
dataset: this.connection.model(
|
|
85
|
-
solution: this.connection.model(
|
|
86
|
-
commitment: this.connection.model(
|
|
87
|
-
usersolution: this.connection.model(
|
|
88
|
-
pending: this.connection.model(
|
|
89
|
-
scheduler: this.connection.model(
|
|
84
|
+
captcha: this.connection.model("Captcha", CaptchaRecordSchema),
|
|
85
|
+
powCaptcha: this.connection.model("PowCaptcha", PowCaptchaRecordSchema),
|
|
86
|
+
dataset: this.connection.model("Dataset", DatasetRecordSchema),
|
|
87
|
+
solution: this.connection.model("Solution", SolutionRecordSchema),
|
|
88
|
+
commitment: this.connection.model("UserCommitment", UserCommitmentRecordSchema),
|
|
89
|
+
usersolution: this.connection.model("UserSolution", UserSolutionRecordSchema),
|
|
90
|
+
pending: this.connection.model("Pending", PendingRecordSchema),
|
|
91
|
+
scheduler: this.connection.model("Scheduler", ScheduledTaskRecordSchema),
|
|
90
92
|
};
|
|
91
93
|
}
|
|
92
94
|
async close() {
|
|
@@ -95,7 +97,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
95
97
|
}
|
|
96
98
|
async storeDataset(dataset) {
|
|
97
99
|
try {
|
|
98
|
-
this.logger.debug(
|
|
100
|
+
this.logger.debug("Storing dataset in database");
|
|
99
101
|
const parsedDataset = DatasetWithIdsAndTreeSchema.parse(dataset);
|
|
100
102
|
const datasetDoc = {
|
|
101
103
|
datasetId: parsedDataset.datasetId,
|
|
@@ -112,7 +114,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
112
114
|
index,
|
|
113
115
|
solved: !!solution?.length,
|
|
114
116
|
}));
|
|
115
|
-
this.logger.debug(
|
|
117
|
+
this.logger.debug("Inserting captcha records");
|
|
116
118
|
if (captchaDocs.length) {
|
|
117
119
|
await this.tables?.captcha.bulkWrite(captchaDocs.map((captchaDoc) => ({
|
|
118
120
|
updateOne: {
|
|
@@ -132,7 +134,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
132
134
|
datasetId: parsedDataset.datasetId,
|
|
133
135
|
datasetContentId: parsedDataset.datasetContentId,
|
|
134
136
|
}));
|
|
135
|
-
this.logger.debug(
|
|
137
|
+
this.logger.debug("Inserting solution records");
|
|
136
138
|
if (captchaSolutionDocs.length) {
|
|
137
139
|
await this.tables?.solution.bulkWrite(captchaSolutionDocs.map((captchaSolutionDoc) => ({
|
|
138
140
|
updateOne: {
|
|
@@ -142,23 +144,23 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
142
144
|
},
|
|
143
145
|
})));
|
|
144
146
|
}
|
|
145
|
-
this.logger.debug(
|
|
147
|
+
this.logger.debug("Dataset stored in database");
|
|
146
148
|
}
|
|
147
149
|
catch (err) {
|
|
148
|
-
throw new ProsopoDBError(
|
|
150
|
+
throw new ProsopoDBError("DATABASE.DATASET_LOAD_FAILED", {
|
|
149
151
|
context: { failedFuncName: this.storeDataset.name, error: err },
|
|
150
152
|
logger: this.logger,
|
|
151
153
|
});
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
async getSolutions(datasetId) {
|
|
155
|
-
const docs = await this.tables?.solution
|
|
157
|
+
const docs = await this.tables?.solution
|
|
158
|
+
.find({ datasetId })
|
|
159
|
+
.lean();
|
|
156
160
|
return docs ? docs : [];
|
|
157
161
|
}
|
|
158
162
|
async getDataset(datasetId) {
|
|
159
|
-
const datasetDoc = await this.tables?.dataset
|
|
160
|
-
.findOne({ datasetId: datasetId })
|
|
161
|
-
.lean();
|
|
163
|
+
const datasetDoc = await this.tables?.dataset.findOne({ datasetId: datasetId }).lean();
|
|
162
164
|
if (datasetDoc) {
|
|
163
165
|
const { datasetContentId, format, contentTree, solutionTree } = datasetDoc;
|
|
164
166
|
const captchas = (await this.tables?.captcha.find({ datasetId }).lean()) || [];
|
|
@@ -188,13 +190,13 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
188
190
|
}),
|
|
189
191
|
};
|
|
190
192
|
}
|
|
191
|
-
throw new ProsopoDBError(
|
|
193
|
+
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
192
194
|
context: { failedFuncName: this.getDataset.name, datasetId },
|
|
193
195
|
});
|
|
194
196
|
}
|
|
195
197
|
async getRandomCaptcha(solved, datasetId, size) {
|
|
196
198
|
if (!isHex(datasetId)) {
|
|
197
|
-
throw new ProsopoDBError(
|
|
199
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
198
200
|
context: { failedFuncName: this.getRandomCaptcha.name, datasetId },
|
|
199
201
|
});
|
|
200
202
|
}
|
|
@@ -214,26 +216,33 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
214
216
|
},
|
|
215
217
|
]);
|
|
216
218
|
const docs = await cursor;
|
|
217
|
-
if (docs
|
|
219
|
+
if (docs?.length) {
|
|
218
220
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
219
221
|
}
|
|
220
|
-
throw new ProsopoDBError(
|
|
221
|
-
context: {
|
|
222
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
223
|
+
context: {
|
|
224
|
+
failedFuncName: this.getRandomCaptcha.name,
|
|
225
|
+
solved,
|
|
226
|
+
datasetId,
|
|
227
|
+
size,
|
|
228
|
+
},
|
|
222
229
|
});
|
|
223
230
|
}
|
|
224
231
|
async getCaptchaById(captchaId) {
|
|
225
|
-
const cursor = this.tables?.captcha
|
|
232
|
+
const cursor = this.tables?.captcha
|
|
233
|
+
.find({ captchaId: { $in: captchaId } })
|
|
234
|
+
.lean();
|
|
226
235
|
const docs = await cursor;
|
|
227
|
-
if (docs
|
|
236
|
+
if (docs?.length) {
|
|
228
237
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
229
238
|
}
|
|
230
|
-
throw new ProsopoDBError(
|
|
239
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
231
240
|
context: { failedFuncName: this.getCaptchaById.name, captchaId },
|
|
232
241
|
});
|
|
233
242
|
}
|
|
234
243
|
async updateCaptcha(captcha, datasetId) {
|
|
235
244
|
if (!isHex(datasetId)) {
|
|
236
|
-
throw new ProsopoDBError(
|
|
245
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
237
246
|
context: { failedFuncName: this.updateCaptcha.name, datasetId },
|
|
238
247
|
});
|
|
239
248
|
}
|
|
@@ -241,7 +250,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
241
250
|
await this.tables?.captcha.updateOne({ datasetId }, { $set: captcha }, { upsert: false });
|
|
242
251
|
}
|
|
243
252
|
catch (err) {
|
|
244
|
-
throw new ProsopoDBError(
|
|
253
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
245
254
|
context: { failedFuncName: this.getDatasetDetails.name, error: err },
|
|
246
255
|
});
|
|
247
256
|
}
|
|
@@ -251,16 +260,21 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
251
260
|
}
|
|
252
261
|
async getDatasetDetails(datasetId) {
|
|
253
262
|
if (!isHex(datasetId)) {
|
|
254
|
-
throw new ProsopoDBError(
|
|
263
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
255
264
|
context: { failedFuncName: this.getDatasetDetails.name, datasetId },
|
|
256
265
|
});
|
|
257
266
|
}
|
|
258
|
-
const doc = await this.tables?.dataset
|
|
267
|
+
const doc = await this.tables?.dataset
|
|
268
|
+
.findOne({ datasetId })
|
|
269
|
+
.lean();
|
|
259
270
|
if (doc) {
|
|
260
271
|
return doc;
|
|
261
272
|
}
|
|
262
|
-
throw new ProsopoDBError(
|
|
263
|
-
context: {
|
|
273
|
+
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
274
|
+
context: {
|
|
275
|
+
failedFuncName: this.getDatasetDetails.name,
|
|
276
|
+
datasetId,
|
|
277
|
+
},
|
|
264
278
|
});
|
|
265
279
|
}
|
|
266
280
|
async storeDappUserSolution(captchas, commit) {
|
|
@@ -288,24 +302,27 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
288
302
|
await this.tables?.usersolution.bulkWrite(ops);
|
|
289
303
|
}
|
|
290
304
|
}
|
|
291
|
-
async storePowCaptchaRecord(challenge, checked) {
|
|
292
|
-
|
|
293
|
-
throw new ProsopoEnvError('DATABASE.DATABASE_UNDEFINED', {
|
|
294
|
-
context: { failedFuncName: this.storePowCaptchaRecord.name },
|
|
295
|
-
logger: this.logger,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
305
|
+
async storePowCaptchaRecord(challenge, components, checked) {
|
|
306
|
+
const tables = this.getTables();
|
|
298
307
|
const powCaptchaRecord = {
|
|
299
308
|
challenge,
|
|
309
|
+
...components,
|
|
300
310
|
checked,
|
|
301
311
|
};
|
|
302
312
|
try {
|
|
303
|
-
await
|
|
304
|
-
this.logger.info(
|
|
313
|
+
await tables.powCaptcha.create(powCaptchaRecord);
|
|
314
|
+
this.logger.info("PowCaptcha record added successfully", {
|
|
315
|
+
challenge,
|
|
316
|
+
checked,
|
|
317
|
+
});
|
|
305
318
|
}
|
|
306
319
|
catch (error) {
|
|
307
|
-
this.logger.error(
|
|
308
|
-
|
|
320
|
+
this.logger.error("Failed to add PowCaptcha record", {
|
|
321
|
+
error,
|
|
322
|
+
challenge,
|
|
323
|
+
checked,
|
|
324
|
+
});
|
|
325
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
309
326
|
context: { error, challenge, checked },
|
|
310
327
|
logger: this.logger,
|
|
311
328
|
});
|
|
@@ -313,60 +330,70 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
313
330
|
}
|
|
314
331
|
async getPowCaptchaRecordByChallenge(challenge) {
|
|
315
332
|
if (!this.tables) {
|
|
316
|
-
throw new ProsopoEnvError(
|
|
333
|
+
throw new ProsopoEnvError("DATABASE.DATABASE_UNDEFINED", {
|
|
317
334
|
context: { failedFuncName: this.getPowCaptchaRecordByChallenge.name },
|
|
318
335
|
logger: this.logger,
|
|
319
336
|
});
|
|
320
337
|
}
|
|
321
338
|
try {
|
|
322
|
-
const record = await this.tables.powCaptcha
|
|
339
|
+
const record = await this.tables.powCaptcha
|
|
340
|
+
.findOne({ challenge })
|
|
341
|
+
.lean();
|
|
323
342
|
if (record) {
|
|
324
|
-
this.logger.info(
|
|
343
|
+
this.logger.info("PowCaptcha record retrieved successfully", {
|
|
344
|
+
challenge,
|
|
345
|
+
});
|
|
325
346
|
return record;
|
|
326
347
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
348
|
+
this.logger.info("No PowCaptcha record found", { challenge });
|
|
349
|
+
return null;
|
|
331
350
|
}
|
|
332
351
|
catch (error) {
|
|
333
|
-
this.logger.error(
|
|
334
|
-
|
|
352
|
+
this.logger.error("Failed to retrieve PowCaptcha record", {
|
|
353
|
+
error,
|
|
354
|
+
challenge,
|
|
355
|
+
});
|
|
356
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
335
357
|
context: { error, challenge },
|
|
336
358
|
logger: this.logger,
|
|
337
359
|
});
|
|
338
360
|
}
|
|
339
361
|
}
|
|
340
362
|
async updatePowCaptchaRecord(challenge, checked) {
|
|
341
|
-
|
|
342
|
-
throw new ProsopoEnvError('DATABASE.DATABASE_UNDEFINED', {
|
|
343
|
-
context: { failedFuncName: this.updatePowCaptchaRecord.name },
|
|
344
|
-
logger: this.logger,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
363
|
+
const tables = this.getTables();
|
|
347
364
|
try {
|
|
348
|
-
const updateResult = await
|
|
365
|
+
const updateResult = await tables.powCaptcha.updateOne({ challenge }, { $set: { checked } });
|
|
349
366
|
if (updateResult.matchedCount === 0) {
|
|
350
|
-
this.logger.info(
|
|
351
|
-
|
|
367
|
+
this.logger.info("No PowCaptcha record found to update", {
|
|
368
|
+
challenge,
|
|
369
|
+
checked,
|
|
370
|
+
});
|
|
371
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
352
372
|
context: { challenge, checked },
|
|
353
373
|
logger: this.logger,
|
|
354
374
|
});
|
|
355
375
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
376
|
+
this.logger.info("PowCaptcha record updated successfully", {
|
|
377
|
+
challenge,
|
|
378
|
+
checked,
|
|
379
|
+
});
|
|
359
380
|
}
|
|
360
381
|
catch (error) {
|
|
361
|
-
this.logger.error(
|
|
362
|
-
|
|
382
|
+
this.logger.error("Failed to update PowCaptcha record", {
|
|
383
|
+
error,
|
|
384
|
+
challenge,
|
|
385
|
+
checked,
|
|
386
|
+
});
|
|
387
|
+
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
363
388
|
context: { error, challenge, checked },
|
|
364
389
|
logger: this.logger,
|
|
365
390
|
});
|
|
366
391
|
}
|
|
367
392
|
}
|
|
368
393
|
async getProcessedDappUserSolutions() {
|
|
369
|
-
const docs = await this.tables?.usersolution
|
|
394
|
+
const docs = await this.tables?.usersolution
|
|
395
|
+
.find({ processed: true })
|
|
396
|
+
.lean();
|
|
370
397
|
return docs ? docs.map((doc) => UserSolutionSchema.parse(doc)) : [];
|
|
371
398
|
}
|
|
372
399
|
async getProcessedDappUserCommitments() {
|
|
@@ -377,20 +404,51 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
377
404
|
const docs = await this.tables?.commitment.find({ batched: false }).lean();
|
|
378
405
|
return docs ? docs.map((doc) => UserCommitmentSchema.parse(doc)) : [];
|
|
379
406
|
}
|
|
407
|
+
async getUnstoredDappUserCommitments() {
|
|
408
|
+
const docs = await this.tables?.commitment
|
|
409
|
+
.find({
|
|
410
|
+
$or: [{ stored: false }, { stored: { $exists: false } }],
|
|
411
|
+
})
|
|
412
|
+
.lean();
|
|
413
|
+
return docs ? docs.map((doc) => UserCommitmentSchema.parse(doc)) : [];
|
|
414
|
+
}
|
|
415
|
+
async markDappUserCommitmentsStored(commitmentIds) {
|
|
416
|
+
await this.tables?.commitment.updateMany({ id: { $in: commitmentIds } }, { $set: { stored: true } }, { upsert: false });
|
|
417
|
+
}
|
|
418
|
+
async getUnstoredDappUserPoWCommitments() {
|
|
419
|
+
const docs = await this.tables?.powCaptcha
|
|
420
|
+
.find({
|
|
421
|
+
$or: [{ stored: false }, { stored: { $exists: false } }],
|
|
422
|
+
})
|
|
423
|
+
.lean();
|
|
424
|
+
return docs || [];
|
|
425
|
+
}
|
|
426
|
+
async markDappUserPoWCommitmentsStored(challengeIds) {
|
|
427
|
+
await this.tables?.powCaptcha.updateMany({ challenge: { $in: challengeIds } }, { $set: { stored: true } }, { upsert: false });
|
|
428
|
+
}
|
|
380
429
|
async getBatchedDappUserCommitments() {
|
|
381
430
|
const docs = await this.tables?.commitment.find({ batched: true }).lean();
|
|
382
431
|
return docs ? docs.map((doc) => UserCommitmentSchema.parse(doc)) : [];
|
|
383
432
|
}
|
|
384
433
|
async removeProcessedDappUserSolutions(commitmentIds) {
|
|
385
|
-
return await this.tables?.usersolution.deleteMany({
|
|
434
|
+
return await this.tables?.usersolution.deleteMany({
|
|
435
|
+
processed: true,
|
|
436
|
+
commitmentId: { $in: commitmentIds },
|
|
437
|
+
});
|
|
386
438
|
}
|
|
387
439
|
async removeProcessedDappUserCommitments(commitmentIds) {
|
|
388
|
-
return await this.tables?.commitment.deleteMany({
|
|
440
|
+
return await this.tables?.commitment.deleteMany({
|
|
441
|
+
processed: true,
|
|
442
|
+
id: { $in: commitmentIds },
|
|
443
|
+
});
|
|
389
444
|
}
|
|
390
445
|
async storeDappUserPending(userAccount, requestHash, salt, deadlineTimestamp, requestedAtBlock) {
|
|
391
446
|
if (!isHex(requestHash)) {
|
|
392
|
-
throw new ProsopoDBError(
|
|
393
|
-
context: {
|
|
447
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
448
|
+
context: {
|
|
449
|
+
failedFuncName: this.storeDappUserPending.name,
|
|
450
|
+
requestHash,
|
|
451
|
+
},
|
|
394
452
|
});
|
|
395
453
|
}
|
|
396
454
|
const pendingRecord = {
|
|
@@ -405,24 +463,25 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
405
463
|
}
|
|
406
464
|
async getDappUserPending(requestHash) {
|
|
407
465
|
if (!isHex(requestHash)) {
|
|
408
|
-
throw new ProsopoEnvError(
|
|
466
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
409
467
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
410
468
|
});
|
|
411
469
|
}
|
|
412
|
-
const doc = await this.tables?.pending
|
|
413
|
-
.findOne({ requestHash: requestHash })
|
|
414
|
-
.lean();
|
|
470
|
+
const doc = await this.tables?.pending.findOne({ requestHash: requestHash }).lean();
|
|
415
471
|
if (doc) {
|
|
416
472
|
return doc;
|
|
417
473
|
}
|
|
418
|
-
throw new ProsopoEnvError(
|
|
474
|
+
throw new ProsopoEnvError("DATABASE.PENDING_RECORD_NOT_FOUND", {
|
|
419
475
|
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
420
476
|
});
|
|
421
477
|
}
|
|
422
478
|
async updateDappUserPendingStatus(requestHash) {
|
|
423
479
|
if (!isHex(requestHash)) {
|
|
424
|
-
throw new ProsopoEnvError(
|
|
425
|
-
context: {
|
|
480
|
+
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
481
|
+
context: {
|
|
482
|
+
failedFuncName: this.updateDappUserPendingStatus.name,
|
|
483
|
+
requestHash,
|
|
484
|
+
},
|
|
426
485
|
});
|
|
427
486
|
}
|
|
428
487
|
await this.tables?.pending.updateOne({ requestHash: requestHash }, {
|
|
@@ -442,15 +501,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
442
501
|
if (docs) {
|
|
443
502
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
444
503
|
}
|
|
445
|
-
throw new ProsopoEnvError(
|
|
504
|
+
throw new ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED");
|
|
446
505
|
}
|
|
447
506
|
async getAllDappUserSolutions(captchaId) {
|
|
448
|
-
const cursor = this.tables?.usersolution
|
|
507
|
+
const cursor = this.tables?.usersolution
|
|
508
|
+
?.find({ captchaId: { $in: captchaId } })
|
|
509
|
+
.lean();
|
|
449
510
|
const docs = await cursor;
|
|
450
511
|
if (docs) {
|
|
451
512
|
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
452
513
|
}
|
|
453
|
-
throw new ProsopoEnvError(
|
|
514
|
+
throw new ProsopoEnvError("DATABASE.SOLUTION_GET_FAILED");
|
|
454
515
|
}
|
|
455
516
|
async getDatasetIdWithSolvedCaptchasOfSizeN(solvedCaptchaCount) {
|
|
456
517
|
const cursor = this.tables?.solution.aggregate([
|
|
@@ -459,7 +520,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
459
520
|
},
|
|
460
521
|
{
|
|
461
522
|
$group: {
|
|
462
|
-
_id:
|
|
523
|
+
_id: "$datasetId",
|
|
463
524
|
count: { $sum: 1 },
|
|
464
525
|
},
|
|
465
526
|
},
|
|
@@ -473,15 +534,18 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
473
534
|
},
|
|
474
535
|
]);
|
|
475
536
|
const docs = await cursor;
|
|
476
|
-
if (docs
|
|
537
|
+
if (docs?.length) {
|
|
477
538
|
return docs[0]._id;
|
|
478
539
|
}
|
|
479
|
-
throw new ProsopoDBError(
|
|
540
|
+
throw new ProsopoDBError("DATABASE.DATASET_WITH_SOLUTIONS_GET_FAILED");
|
|
480
541
|
}
|
|
481
542
|
async getRandomSolvedCaptchasFromSingleDataset(datasetId, size) {
|
|
482
543
|
if (!isHex(datasetId)) {
|
|
483
|
-
throw new ProsopoDBError(
|
|
484
|
-
context: {
|
|
544
|
+
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
545
|
+
context: {
|
|
546
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
547
|
+
datasetId,
|
|
548
|
+
},
|
|
485
549
|
});
|
|
486
550
|
}
|
|
487
551
|
const sampleSize = size ? Math.abs(Math.trunc(size)) : 1;
|
|
@@ -497,11 +561,15 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
497
561
|
},
|
|
498
562
|
]);
|
|
499
563
|
const docs = await cursor;
|
|
500
|
-
if (docs
|
|
564
|
+
if (docs?.length) {
|
|
501
565
|
return docs;
|
|
502
566
|
}
|
|
503
|
-
throw new ProsopoDBError(
|
|
504
|
-
context: {
|
|
567
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
568
|
+
context: {
|
|
569
|
+
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
570
|
+
datasetId,
|
|
571
|
+
size,
|
|
572
|
+
},
|
|
505
573
|
});
|
|
506
574
|
}
|
|
507
575
|
async getDappUserSolutionById(commitmentId) {
|
|
@@ -514,12 +582,14 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
514
582
|
if (doc) {
|
|
515
583
|
return doc;
|
|
516
584
|
}
|
|
517
|
-
throw new ProsopoDBError(
|
|
585
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
518
586
|
context: { failedFuncName: this.getCaptchaById.name, commitmentId },
|
|
519
587
|
});
|
|
520
588
|
}
|
|
521
589
|
async getDappUserCommitmentById(commitmentId) {
|
|
522
|
-
const commitmentCursor = this.tables?.commitment
|
|
590
|
+
const commitmentCursor = this.tables?.commitment
|
|
591
|
+
?.findOne({ id: commitmentId })
|
|
592
|
+
.lean();
|
|
523
593
|
const doc = await commitmentCursor;
|
|
524
594
|
return doc ? UserCommitmentSchema.parse(doc) : undefined;
|
|
525
595
|
}
|
|
@@ -536,7 +606,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
536
606
|
.lean();
|
|
537
607
|
}
|
|
538
608
|
catch (err) {
|
|
539
|
-
throw new ProsopoDBError(
|
|
609
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_APPROVE_FAILED", {
|
|
610
|
+
context: { error: err, commitmentId },
|
|
611
|
+
});
|
|
540
612
|
}
|
|
541
613
|
}
|
|
542
614
|
async flagProcessedDappUserSolutions(captchaIds) {
|
|
@@ -546,7 +618,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
546
618
|
.lean();
|
|
547
619
|
}
|
|
548
620
|
catch (err) {
|
|
549
|
-
throw new ProsopoDBError(
|
|
621
|
+
throw new ProsopoDBError("DATABASE.SOLUTION_FLAG_FAILED", {
|
|
622
|
+
context: { error: err, captchaIds },
|
|
623
|
+
});
|
|
550
624
|
}
|
|
551
625
|
}
|
|
552
626
|
async flagProcessedDappUserCommitments(commitmentIds) {
|
|
@@ -557,7 +631,9 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
557
631
|
.lean();
|
|
558
632
|
}
|
|
559
633
|
catch (err) {
|
|
560
|
-
throw new ProsopoDBError(
|
|
634
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
635
|
+
context: { error: err, commitmentIds },
|
|
636
|
+
});
|
|
561
637
|
}
|
|
562
638
|
}
|
|
563
639
|
async flagBatchedDappUserCommitments(commitmentIds) {
|
|
@@ -568,12 +644,17 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
568
644
|
.lean();
|
|
569
645
|
}
|
|
570
646
|
catch (err) {
|
|
571
|
-
throw new ProsopoDBError(
|
|
647
|
+
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
648
|
+
context: { error: err, commitmentIds },
|
|
649
|
+
});
|
|
572
650
|
}
|
|
573
651
|
}
|
|
574
652
|
async getLastBatchCommitTime() {
|
|
575
653
|
const cursor = this.tables?.scheduler
|
|
576
|
-
?.findOne({
|
|
654
|
+
?.findOne({
|
|
655
|
+
processName: ScheduledTaskNames.BatchCommitment,
|
|
656
|
+
status: ScheduledTaskStatus.Completed,
|
|
657
|
+
})
|
|
577
658
|
.sort({ timestamp: -1 });
|
|
578
659
|
const doc = await cursor?.lean();
|
|
579
660
|
if (doc) {
|
|
@@ -590,7 +671,7 @@ export class ProsopoDatabase extends AsyncFactory {
|
|
|
590
671
|
async getLastScheduledTaskStatus(task, status) {
|
|
591
672
|
const lookup = { processName: task };
|
|
592
673
|
if (status) {
|
|
593
|
-
lookup
|
|
674
|
+
lookup.status = status;
|
|
594
675
|
}
|
|
595
676
|
const cursor = await this.tables?.scheduler
|
|
596
677
|
?.findOne(lookup)
|