@xyo-network/image-thumbnail-plugin 2.75.5 → 2.75.6
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/docs.json +5065 -5089
- package/dist/node/Diviner/Config.d.cts +23 -0
- package/dist/node/Diviner/Config.d.cts.map +1 -1
- package/dist/node/Diviner/Config.d.mts +23 -0
- package/dist/node/Diviner/Config.d.mts.map +1 -1
- package/dist/node/Diviner/Config.d.ts +23 -0
- package/dist/node/Diviner/Config.d.ts.map +1 -1
- package/dist/node/Diviner/Config.js.map +1 -1
- package/dist/node/Diviner/Config.mjs.map +1 -1
- package/dist/node/Diviner/Diviner.d.cts +37 -20
- package/dist/node/Diviner/Diviner.d.cts.map +1 -1
- package/dist/node/Diviner/Diviner.d.mts +37 -20
- package/dist/node/Diviner/Diviner.d.mts.map +1 -1
- package/dist/node/Diviner/Diviner.d.ts +37 -20
- package/dist/node/Diviner/Diviner.d.ts.map +1 -1
- package/dist/node/Diviner/Diviner.js +158 -138
- package/dist/node/Diviner/Diviner.js.map +1 -1
- package/dist/node/Diviner/Diviner.mjs +156 -136
- package/dist/node/Diviner/Diviner.mjs.map +1 -1
- package/dist/node/Diviner/index.js +158 -138
- package/dist/node/Diviner/index.js.map +1 -1
- package/dist/node/Diviner/index.mjs +156 -136
- package/dist/node/Diviner/index.mjs.map +1 -1
- package/dist/node/Plugin.d.cts +3 -0
- package/dist/node/Plugin.d.cts.map +1 -1
- package/dist/node/Plugin.d.mts +3 -0
- package/dist/node/Plugin.d.mts.map +1 -1
- package/dist/node/Plugin.d.ts +3 -0
- package/dist/node/Plugin.d.ts.map +1 -1
- package/dist/node/Plugin.js +163 -143
- package/dist/node/Plugin.js.map +1 -1
- package/dist/node/Plugin.mjs +161 -141
- package/dist/node/Plugin.mjs.map +1 -1
- package/dist/node/index.js +163 -143
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +161 -141
- package/dist/node/index.mjs.map +1 -1
- package/package.json +22 -16
- package/src/Diviner/Config.ts +24 -0
- package/src/Diviner/Diviner.ts +223 -157
|
@@ -24,137 +24,184 @@ __export(Diviner_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(Diviner_exports);
|
|
26
26
|
var import_assert = require("@xylabs/assert");
|
|
27
|
-
var
|
|
28
|
-
var import_lodash = require("@xylabs/lodash");
|
|
27
|
+
var import_exists = require("@xylabs/exists");
|
|
29
28
|
var import_abstract_diviner = require("@xyo-network/abstract-diviner");
|
|
30
29
|
var import_archivist_model = require("@xyo-network/archivist-model");
|
|
30
|
+
var import_archivist_wrapper = require("@xyo-network/archivist-wrapper");
|
|
31
|
+
var import_boundwitness_model = require("@xyo-network/boundwitness-model");
|
|
31
32
|
var import_core = require("@xyo-network/core");
|
|
33
|
+
var import_diviner_boundwitness_model = require("@xyo-network/diviner-boundwitness-model");
|
|
32
34
|
var import_diviner_model = require("@xyo-network/diviner-model");
|
|
33
35
|
var import_diviner_payload_model = require("@xyo-network/diviner-payload-model");
|
|
36
|
+
var import_diviner_wrapper = require("@xyo-network/diviner-wrapper");
|
|
34
37
|
var import_image_thumbnail_payload_plugin2 = require("@xyo-network/image-thumbnail-payload-plugin");
|
|
38
|
+
var import_payload_builder = require("@xyo-network/payload-builder");
|
|
39
|
+
var import_payload_model = require("@xyo-network/payload-model");
|
|
40
|
+
var import_url_payload_plugin = require("@xyo-network/url-payload-plugin");
|
|
41
|
+
var import_witness_timestamp = require("@xyo-network/witness-timestamp");
|
|
35
42
|
|
|
36
43
|
// src/Diviner/Config.ts
|
|
37
44
|
var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
|
|
38
45
|
var ImageThumbnailDivinerConfigSchema = `${import_image_thumbnail_payload_plugin.ImageThumbnailSchema}.diviner.config`;
|
|
39
46
|
|
|
40
47
|
// src/Diviner/Diviner.ts
|
|
48
|
+
var ModuleStateSchema = "network.xyo.module.state";
|
|
49
|
+
var isModuleState = (0, import_payload_model.isPayloadOfSchemaType)(ModuleStateSchema);
|
|
50
|
+
var ImageThumbnailResultIndexSchema = `${import_image_thumbnail_payload_plugin2.ImageThumbnailSchema}.index`;
|
|
51
|
+
var isImageThumbnailResult = (0, import_payload_model.isPayloadOfSchemaType)(ImageThumbnailResultIndexSchema);
|
|
52
|
+
var moduleName = "ImageThumbnailDiviner";
|
|
41
53
|
var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDiviner {
|
|
42
54
|
static configSchemas = [ImageThumbnailDivinerConfigSchema, import_diviner_model.DivinerConfigSchema];
|
|
43
|
-
_archivistInstance;
|
|
44
|
-
_initializeArchivistConnectionIfNeededPromise;
|
|
45
|
-
_map;
|
|
46
|
-
_payloadDivinerInstance;
|
|
47
55
|
_pollId;
|
|
48
|
-
// static override get configSchema() {
|
|
49
|
-
// return ImageThumbnailDivinerConfigSchema
|
|
50
|
-
// }
|
|
51
|
-
get archivist() {
|
|
52
|
-
return this.config.archivist;
|
|
53
|
-
}
|
|
54
|
-
get payloadDiviner() {
|
|
55
|
-
return this.config.payloadDiviner;
|
|
56
|
-
}
|
|
57
56
|
get payloadDivinerLimit() {
|
|
58
57
|
return this.config.payloadDivinerLimit ?? 1e4;
|
|
59
58
|
}
|
|
60
59
|
get pollFrequency() {
|
|
61
|
-
return this.config.pollFrequency;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
60
|
+
return this.config.pollFrequency ?? 1e4;
|
|
61
|
+
}
|
|
62
|
+
backgroundDivine = async () => {
|
|
63
|
+
const lastState = await this.retrieveState() ?? { offset: 0 };
|
|
64
|
+
const { offset } = lastState;
|
|
65
|
+
const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore("thumbnailStore");
|
|
66
|
+
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_boundwitness_model.BoundWitnessDivinerQuerySchema }).fields({
|
|
67
|
+
limit: this.payloadDivinerLimit,
|
|
68
|
+
offset,
|
|
69
|
+
order: "asc",
|
|
70
|
+
payload_schemas: [import_image_thumbnail_payload_plugin2.ImageThumbnailSchema, import_witness_timestamp.TimestampSchema]
|
|
71
|
+
});
|
|
72
|
+
const batch = await boundWitnessDiviner.divine([query]);
|
|
73
|
+
if (batch.length === 0)
|
|
74
|
+
return;
|
|
75
|
+
const imageThumbnailTimestampTuples = batch.filter(import_boundwitness_model.isBoundWitness).map((bw) => {
|
|
76
|
+
var _a, _b, _c, _d;
|
|
77
|
+
const imageThumbnailIndex = (_a = bw.payload_schemas) == null ? void 0 : _a.findIndex((schema) => schema === import_image_thumbnail_payload_plugin2.ImageThumbnailSchema);
|
|
78
|
+
const timestampIndex = (_b = bw.payload_schemas) == null ? void 0 : _b.findIndex((schema) => schema === import_witness_timestamp.TimestampSchema);
|
|
79
|
+
if (!imageThumbnailIndex || !timestampIndex)
|
|
80
|
+
return void 0;
|
|
81
|
+
const imageThumbnail = (_c = bw.payload_hashes) == null ? void 0 : _c[imageThumbnailIndex];
|
|
82
|
+
const timestamp = (_d = bw.payload_hashes) == null ? void 0 : _d[timestampIndex];
|
|
83
|
+
return [imageThumbnail, timestamp];
|
|
84
|
+
}).filter(import_exists.exists);
|
|
85
|
+
const archivist = await this.getArchivistForStore("thumbnailStore");
|
|
86
|
+
const payloadTuples = (await Promise.all(
|
|
87
|
+
imageThumbnailTimestampTuples.map(async ([imageThumbnailHash, timestampHash]) => {
|
|
88
|
+
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
89
|
+
const imageThumbnailPayload = results.find(import_image_thumbnail_payload_plugin2.isImageThumbnail);
|
|
90
|
+
const timestampPayload = results.find(import_witness_timestamp.isTimestamp);
|
|
91
|
+
if (!imageThumbnailPayload || !timestampPayload)
|
|
92
|
+
return void 0;
|
|
93
|
+
const calculatedImageThumbnailHash = await import_core.PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
94
|
+
const calculatedTimestampHash = await import_core.PayloadHasher.hashAsync(timestampPayload);
|
|
95
|
+
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
96
|
+
return void 0;
|
|
97
|
+
return [imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload];
|
|
98
|
+
})
|
|
99
|
+
)).filter(import_exists.exists);
|
|
100
|
+
const indexedResults = payloadTuples.map(([thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
|
|
101
|
+
var _a;
|
|
102
|
+
const { url } = thumbnailPayload;
|
|
103
|
+
const { timestamp } = timestampPayload;
|
|
104
|
+
const status = ((_a = thumbnailPayload.http) == null ? void 0 : _a.status) ?? -1;
|
|
105
|
+
const sources = [thumbnailHash, timestampHash];
|
|
106
|
+
const result = new import_payload_builder.PayloadBuilder({ schema: ImageThumbnailResultIndexSchema }).fields({ sources, status, timestamp, url }).build();
|
|
107
|
+
return result;
|
|
108
|
+
});
|
|
109
|
+
const indexArchivist = await this.getArchivistForStore("indexStore");
|
|
110
|
+
await indexArchivist.insert(indexedResults);
|
|
111
|
+
const nextOffset = offset + batch.length + 1;
|
|
112
|
+
const currentState = { ...lastState, offset: nextOffset };
|
|
113
|
+
await this.commitState(currentState);
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Commit the internal state of the Diviner process. This is similar
|
|
117
|
+
* to a transaction completion in a database and should only be called
|
|
118
|
+
* when results have been successfully persisted to the appropriate
|
|
119
|
+
* external stores.
|
|
120
|
+
*/
|
|
121
|
+
async commitState(state) {
|
|
122
|
+
var _a;
|
|
123
|
+
const stateStore = (0, import_assert.assertEx)((_a = this.config.stateStore) == null ? void 0 : _a.archivist, `${moduleName}: No stateStore configured`);
|
|
124
|
+
const module2 = (0, import_assert.assertEx)(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`);
|
|
125
|
+
await (0, import_archivist_model.withArchivistModule)(module2, async (archivist) => {
|
|
126
|
+
const mod = import_archivist_wrapper.ArchivistWrapper.wrap(archivist, this.account);
|
|
127
|
+
const payload = new import_payload_builder.PayloadBuilder({ schema: ModuleStateSchema }).fields({ state }).build();
|
|
128
|
+
await mod.insert([payload]);
|
|
129
|
+
});
|
|
87
130
|
}
|
|
88
131
|
async divineHandler(payloads = []) {
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
132
|
+
const urls = payloads.filter(import_url_payload_plugin.isUrlPayload).map((urlPayload) => urlPayload.url);
|
|
133
|
+
const diviner = await this.getPayloadDivinerForStore("indexStore");
|
|
134
|
+
const results = (await Promise.all(
|
|
135
|
+
urls.map(async (url) => {
|
|
136
|
+
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_payload_model.PayloadDivinerQuerySchema }).fields({ limit: 1, offset: 0, order: "desc", url }).build();
|
|
137
|
+
return await diviner.divine([query]);
|
|
138
|
+
})
|
|
139
|
+
)).flat().filter(isImageThumbnailResult);
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
async getArchivistForStore(store, wrap) {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
const name = (0, import_assert.assertEx)((_b = (_a = this.config) == null ? void 0 : _a[store]) == null ? void 0 : _b.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.archivist not specified`);
|
|
145
|
+
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`);
|
|
146
|
+
return wrap ? import_archivist_wrapper.ArchivistWrapper.wrap(mod, this.account) : (0, import_archivist_model.asArchivistInstance)(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not an Archivist`);
|
|
147
|
+
}
|
|
148
|
+
async getBoundWitnessDivinerForStore(store, wrap) {
|
|
149
|
+
var _a, _b;
|
|
150
|
+
const name = (0, import_assert.assertEx)((_b = (_a = this.config) == null ? void 0 : _a[store]) == null ? void 0 : _b.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`);
|
|
151
|
+
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`);
|
|
152
|
+
return wrap ? import_diviner_wrapper.DivinerWrapper.wrap(mod, this.account) : (0, import_diviner_model.asDivinerInstance)(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`);
|
|
153
|
+
}
|
|
154
|
+
async getPayloadDivinerForStore(store, wrap) {
|
|
155
|
+
var _a, _b;
|
|
156
|
+
const name = (0, import_assert.assertEx)((_b = (_a = this.config) == null ? void 0 : _a[store]) == null ? void 0 : _b.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`);
|
|
157
|
+
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`);
|
|
158
|
+
return wrap ? import_diviner_wrapper.DivinerWrapper.wrap(mod, this.account) : (0, import_diviner_model.asDivinerInstance)(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Retrieves the last state of the Diviner process. Used to recover state after
|
|
162
|
+
* preemptions, reboots, etc.
|
|
163
|
+
*/
|
|
164
|
+
async retrieveState() {
|
|
116
165
|
var _a;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
166
|
+
let hash = "";
|
|
167
|
+
const diviner = await this.getBoundWitnessDivinerForStore("stateStore");
|
|
168
|
+
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_payload_model.PayloadDivinerQuerySchema }).fields({
|
|
169
|
+
address: this.account.address,
|
|
170
|
+
limit: 1,
|
|
171
|
+
offset: 0,
|
|
172
|
+
order: "desc",
|
|
173
|
+
schemas: [import_image_thumbnail_payload_plugin2.ImageThumbnailSchema]
|
|
174
|
+
});
|
|
175
|
+
const boundWitnesses = await diviner.divine([query]);
|
|
176
|
+
if (boundWitnesses.length > 0) {
|
|
177
|
+
const boundWitness = boundWitnesses[0];
|
|
178
|
+
if ((0, import_boundwitness_model.isBoundWitness)(boundWitness)) {
|
|
179
|
+
hash = boundWitness.addresses.map((address, index) => ({ address, index })).filter(({ address }) => address === this.account.address).reduce(
|
|
180
|
+
(prev, curr) => {
|
|
181
|
+
var _a2;
|
|
182
|
+
return ((_a2 = boundWitness.payload_schemas) == null ? void 0 : _a2[curr == null ? void 0 : curr.index]) === ModuleStateSchema ? boundWitness.payload_hashes[curr == null ? void 0 : curr.index] : prev;
|
|
183
|
+
},
|
|
184
|
+
""
|
|
185
|
+
);
|
|
186
|
+
}
|
|
128
187
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
schema: import_diviner_payload_model.PayloadDivinerQuerySchema,
|
|
143
|
-
schemas: [import_image_thumbnail_payload_plugin2.ImageThumbnailSchema]
|
|
144
|
-
};
|
|
145
|
-
const payloads = await diviner.divine([payloadDivinerQuery]);
|
|
146
|
-
offset = (offset ?? 0) + payloads.length;
|
|
147
|
-
moreAvailable = payloads.length > 0;
|
|
148
|
-
console.log(`loadMapWithPayloadDiviner.offset: ${offset}`);
|
|
149
|
-
console.log(`loadMapWithPayloadDiviner.moreAvailable: ${moreAvailable}`);
|
|
150
|
-
const imagePayloadPairs = await Promise.all(
|
|
151
|
-
payloads.filter((payload) => payload.schema === import_image_thumbnail_payload_plugin2.ImageThumbnailSchema).map(async (payload) => [await import_core.PayloadHasher.hashAsync(payload), payload])
|
|
152
|
-
);
|
|
153
|
-
imagePayloadPairs.forEach(([hash, payload]) => newMap[payload.sourceUrl] = hash);
|
|
188
|
+
if (hash) {
|
|
189
|
+
const stateStoreArchivist = (0, import_assert.assertEx)((_a = this.config.stateStore) == null ? void 0 : _a.archivist, `${moduleName}: No stateStore archivist configured`);
|
|
190
|
+
await (0, import_archivist_model.withArchivistModule)(
|
|
191
|
+
(0, import_assert.assertEx)(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),
|
|
192
|
+
async (mod) => {
|
|
193
|
+
const archivist = import_archivist_wrapper.ArchivistWrapper.wrap(mod, this.account);
|
|
194
|
+
const payloads = await archivist.get([hash]);
|
|
195
|
+
if (payloads.length > 0) {
|
|
196
|
+
const payload = payloads[0];
|
|
197
|
+
if (isModuleState(payload)) {
|
|
198
|
+
return payload.state;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
154
201
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
202
|
+
);
|
|
157
203
|
}
|
|
204
|
+
return void 0;
|
|
158
205
|
}
|
|
159
206
|
async stopHandler(_timeout) {
|
|
160
207
|
if (this._pollId) {
|
|
@@ -163,40 +210,13 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
163
210
|
}
|
|
164
211
|
return await super.stopHandler();
|
|
165
212
|
}
|
|
166
|
-
async attachArchivistEvents() {
|
|
167
|
-
const archivist = await this.getArchivistInstance();
|
|
168
|
-
const mapPromise = this.getSafeMap();
|
|
169
|
-
archivist.on("inserted", async ({ payloads }) => {
|
|
170
|
-
const map = await mapPromise;
|
|
171
|
-
const thumbnails = (0, import_lodash.compact)(payloads.filter((payload) => payload.schema === import_image_thumbnail_payload_plugin2.ImageThumbnailSchema));
|
|
172
|
-
await Promise.all(thumbnails.map(async (payload) => map[payload.sourceUrl] = await import_core.PayloadHasher.hashAsync(payload)));
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
async getSafeMap() {
|
|
176
|
-
let mapRetry = 100;
|
|
177
|
-
let map = this._map;
|
|
178
|
-
while (!map) {
|
|
179
|
-
await (0, import_delay.delay)(100);
|
|
180
|
-
mapRetry = mapRetry - 1;
|
|
181
|
-
if (mapRetry === 0) {
|
|
182
|
-
throw Error("Map Not Loaded");
|
|
183
|
-
}
|
|
184
|
-
map = this._map;
|
|
185
|
-
}
|
|
186
|
-
return map;
|
|
187
|
-
}
|
|
188
213
|
async poll() {
|
|
189
214
|
if (await this.started()) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
await this.poll();
|
|
196
|
-
}, pollFrequency);
|
|
197
|
-
} else {
|
|
198
|
-
await this.loadMap();
|
|
199
|
-
}
|
|
215
|
+
this._pollId = setTimeout(async () => {
|
|
216
|
+
this._pollId = void 0;
|
|
217
|
+
await this.backgroundDivine();
|
|
218
|
+
await this.poll();
|
|
219
|
+
}, this.pollFrequency);
|
|
200
220
|
}
|
|
201
221
|
}
|
|
202
222
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/Diviner/Diviner.ts","../../../src/Diviner/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { delay } from '@xylabs/delay'\nimport { compact } from '@xylabs/lodash'\nimport { AbstractDiviner } from '@xyo-network/abstract-diviner'\nimport { ArchivistInstance, asArchivistInstance } from '@xyo-network/archivist-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { asDivinerInstance, DivinerConfigSchema, DivinerInstance } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { ImageThumbnail, ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\nimport { UrlPayload } from '@xyo-network/url-payload-plugin'\n\nimport { ImageThumbnailDivinerConfigSchema } from './Config'\nimport { ImageThumbnailDivinerParams } from './Params'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _archivistInstance: Promise<ArchivistInstance> | undefined\n private _initializeArchivistConnectionIfNeededPromise: Promise<void> | undefined\n private _map: Record<string, string> | undefined\n private _payloadDivinerInstance: Promise<DivinerInstance> | undefined\n private _pollId?: string | number | NodeJS.Timeout\n\n // static override get configSchema() {\n // return ImageThumbnailDivinerConfigSchema\n // }\n\n get archivist() {\n return this.config.archivist\n }\n\n get payloadDiviner() {\n return this.config.payloadDiviner\n }\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 10000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency\n }\n\n //using promise as mutex\n async getArchivistInstance(): Promise<ArchivistInstance> {\n //if previously checked, but not found, clear promise\n if (this._archivistInstance && !(await this._archivistInstance)) {\n this._archivistInstance = undefined\n }\n this._archivistInstance =\n this._archivistInstance ??\n (async () => {\n const module = this.archivist ? await this.resolve(this.archivist) : undefined\n return asArchivistInstance(module, 'Provided archivist address did not resolve to an Archivist')\n })()\n return this._archivistInstance\n }\n\n //using promise as mutex\n async getPayloadDivinerInstance(): Promise<DivinerInstance | undefined> {\n const payloadDivinerAddress = this.payloadDiviner\n if (payloadDivinerAddress) {\n //if previously checked, but not found, clear promise\n if (this._payloadDivinerInstance && !(await this._payloadDivinerInstance)) {\n this._payloadDivinerInstance = undefined\n }\n this._payloadDivinerInstance =\n this._payloadDivinerInstance ??\n (async () => {\n const module = await this.resolve(payloadDivinerAddress)\n return asDivinerInstance(module, 'Provided payload diviner address did not resolve to a Diviner')\n })()\n\n return this._payloadDivinerInstance\n }\n }\n\n protected override async divineHandler(payloads: UrlPayload[] = []): Promise<ImageThumbnail[]> {\n await this.initializeArchivistConnectionIfNeeded()\n const urls = payloads.map((urlPayload) => urlPayload.url)\n const map = await this.getSafeMap()\n const archivist = await this.getArchivistInstance()\n const hashes = compact(urls.map((url) => map?.[url]))\n return (await archivist.get(hashes)).filter((payload): payload is ImageThumbnail => payload.schema === ImageThumbnailSchema)\n }\n\n //using promise as mutex\n protected initializeArchivistConnectionIfNeeded() {\n this._initializeArchivistConnectionIfNeededPromise =\n this._initializeArchivistConnectionIfNeededPromise ??\n (async () => {\n if (!this._map) {\n await this.attachArchivistEvents()\n console.log('initializeArchivistConnectionIfNeeded: attachArchivistEvents done')\n await this.poll()\n console.log('initializeArchivistConnectionIfNeeded: poll done')\n }\n })()\n return this._initializeArchivistConnectionIfNeededPromise\n }\n\n protected async loadMap() {\n if (this.payloadDiviner) {\n return await this.loadMapWithPayloadDiviner()\n } else {\n return await this.loadMapWithAll()\n }\n }\n\n protected async loadMapWithAll() {\n if (await this.started()) {\n const archivist = await this.getArchivistInstance()\n assertEx(archivist.all, \"Archivist does not support 'all'\")\n const allPayloads = (await archivist.all?.()) ?? []\n const imagePayloadPairs = await Promise.all(\n allPayloads\n .filter((payload): payload is ImageThumbnail => payload.schema === ImageThumbnailSchema)\n .map<Promise<[string, ImageThumbnail]>>(async (payload) => [await PayloadHasher.hashAsync(payload), payload]),\n )\n this._map = imagePayloadPairs.reduce<Record<string, string>>((prev, [hash, payload]) => {\n prev[payload.sourceUrl] = hash\n return prev\n }, {})\n }\n }\n\n protected async loadMapWithPayloadDiviner() {\n console.log('loadMapWithPayloadDiviner: started')\n if (await this.started()) {\n const diviner = await this.getPayloadDivinerInstance()\n let offset: number | undefined = undefined\n let moreAvailable = true\n if (diviner) {\n const newMap: Record<string, string> = {}\n while (moreAvailable) {\n const payloadDivinerQuery: PayloadDivinerQueryPayload = {\n limit: this.payloadDivinerLimit,\n offset,\n schema: PayloadDivinerQuerySchema,\n schemas: [ImageThumbnailSchema],\n }\n const payloads = await diviner.divine([payloadDivinerQuery])\n offset = (offset ?? 0) + payloads.length\n moreAvailable = payloads.length > 0\n console.log(`loadMapWithPayloadDiviner.offset: ${offset}`)\n console.log(`loadMapWithPayloadDiviner.moreAvailable: ${moreAvailable}`)\n const imagePayloadPairs = await Promise.all(\n payloads\n .filter((payload): payload is ImageThumbnail => payload.schema === ImageThumbnailSchema)\n .map<Promise<[string, ImageThumbnail]>>(async (payload) => [await PayloadHasher.hashAsync(payload), payload]),\n )\n imagePayloadPairs.forEach(([hash, payload]) => (newMap[payload.sourceUrl] = hash))\n }\n this._map = newMap\n }\n }\n }\n\n protected override async stopHandler(_timeout?: number | undefined): Promise<boolean> {\n if (this._pollId) {\n clearTimeout(this._pollId)\n this._pollId = undefined\n }\n return await super.stopHandler()\n }\n\n private async attachArchivistEvents() {\n const archivist = await this.getArchivistInstance()\n const mapPromise = this.getSafeMap()\n archivist.on('inserted', async ({ payloads }) => {\n const map = await mapPromise\n const thumbnails = compact(payloads.filter((payload): payload is ImageThumbnail => payload.schema === ImageThumbnailSchema))\n await Promise.all(thumbnails.map(async (payload) => (map[payload.sourceUrl] = await PayloadHasher.hashAsync(payload))))\n })\n }\n\n private async getSafeMap() {\n let mapRetry = 100 //10 seconds max\n let map = this._map\n while (!map) {\n await delay(100)\n mapRetry = mapRetry - 1\n if (mapRetry === 0) {\n throw Error('Map Not Loaded')\n }\n map = this._map\n }\n return map\n }\n\n private async poll() {\n if (await this.started()) {\n const pollFrequency = this.pollFrequency\n if (pollFrequency) {\n this._pollId = setTimeout(async () => {\n this._pollId = undefined\n await this.loadMap()\n await this.poll()\n }, pollFrequency)\n } else {\n await this.loadMap()\n }\n }\n }\n}\n","import { DivinerConfig } from '@xyo-network/diviner-model'\nimport { ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\n\nexport const ImageThumbnailDivinerConfigSchema = `${ImageThumbnailSchema}.diviner.config` as const\nexport type ImageThumbnailDivinerConfigSchema = typeof ImageThumbnailDivinerConfigSchema\n\nexport type ImageThumbnailDivinerConfig = DivinerConfig<{\n archivist?: string\n payloadDiviner?: string\n payloadDivinerLimit?: number\n pollFrequency?: number\n schema: ImageThumbnailDivinerConfigSchema\n}>\n"],"mappings":"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","names":["import_image_thumbnail_payload_plugin","module"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/Diviner/Diviner.ts","../../../src/Diviner/Config.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { AbstractDiviner } from '@xyo-network/abstract-diviner'\nimport { asArchivistInstance, withArchivistModule } from '@xyo-network/archivist-model'\nimport { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { asDivinerInstance, DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport { ImageThumbnailSchema, isImageThumbnail } from '@xyo-network/image-thumbnail-payload-plugin'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { isPayloadOfSchemaType, Payload } from '@xyo-network/payload-model'\nimport { isUrlPayload } from '@xyo-network/url-payload-plugin'\nimport { isTimestamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nimport { ImageThumbnailDivinerConfig, ImageThumbnailDivinerConfigSchema } from './Config'\nimport { ImageThumbnailDivinerParams } from './Params'\n\n/**\n * TODO: Once the shape settles, make a generic payload so that it\n * can be used for other modules\n */\ninterface State<T> {\n state: T\n}\n\ninterface ImageThumbnailDivinerState {\n offset: number\n}\n\nconst ModuleStateSchema = 'network.xyo.module.state' as const\ntype ModuleStateSchema = typeof ModuleStateSchema\n\ntype ModuleState = Payload<State<ImageThumbnailDivinerState>, ModuleStateSchema>\n\nconst isModuleState = isPayloadOfSchemaType<ModuleState>(ModuleStateSchema)\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\nconst ImageThumbnailResultIndexSchema = `${ImageThumbnailSchema}.index` as const\ntype ImageThumbnailResultIndexSchema = typeof ImageThumbnailResultIndexSchema\n\ninterface ImageThumbnailResultInfo {\n sources: string[]\n // TODO: Something richer than HTTP status code that allows for info about failure modes\n status: number\n timestamp: number\n url: string\n}\n\ntype ImageThumbnailResult = Payload<ImageThumbnailResultInfo, ImageThumbnailResultIndexSchema>\n\nconst isImageThumbnailResult = isPayloadOfSchemaType<ImageThumbnailResult>(ImageThumbnailResultIndexSchema)\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n const imageThumbnailTimestampTuples = batch\n .filter(isBoundWitness)\n .map((bw) => {\n const imageThumbnailIndex = bw.payload_schemas?.findIndex((schema) => schema === ImageThumbnailSchema)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndex || !timestampIndex) return undefined\n const imageThumbnail = bw.payload_hashes?.[imageThumbnailIndex]\n const timestamp = bw.payload_hashes?.[timestampIndex]\n return [imageThumbnail, timestamp] as const\n })\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n const payloadTuples = (\n await Promise.all(\n imageThumbnailTimestampTuples.map(async ([imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results\n const indexedResults = payloadTuples.map(([thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status ?? -1\n const sources = [thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .build()\n return result\n })\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexedResults)\n // Update state\n const nextOffset = offset + batch.length + 1\n const currentState = { ...lastState, offset: nextOffset }\n await this.commitState(currentState)\n }\n\n /**\n * Commit the internal state of the Diviner process. This is similar\n * to a transaction completion in a database and should only be called\n * when results have been successfully persisted to the appropriate\n * external stores.\n */\n protected async commitState(state: ImageThumbnailDivinerState) {\n const stateStore = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`)\n const module = assertEx(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`)\n await withArchivistModule(module, async (archivist) => {\n const mod = ArchivistWrapper.wrap(archivist, this.account)\n const payload = new PayloadBuilder<ModuleState>({ schema: ModuleStateSchema }).fields({ state }).build()\n await mod.insert([payload])\n })\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isUrlPayload).map((urlPayload) => urlPayload.url)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (url) => {\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL\n .fields({ limit: 1, offset: 0, order: 'desc', url })\n .build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.archivist not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`)\n return wrap\n ? ArchivistWrapper.wrap(mod, this.account)\n : asArchivistInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not an Archivist`)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`)\n return wrap\n ? DivinerWrapper.wrap(mod, this.account)\n : asDivinerInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`)\n return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`)\n }\n\n /**\n * Retrieves the last state of the Diviner process. Used to recover state after\n * preemptions, reboots, etc.\n */\n protected async retrieveState(): Promise<ImageThumbnailDivinerState | undefined> {\n let hash: string = ''\n const diviner = await this.getBoundWitnessDivinerForStore('stateStore')\n const query = new PayloadBuilder<PayloadDivinerQueryPayload>({ schema: PayloadDivinerQuerySchema }).fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n schemas: [ImageThumbnailSchema],\n })\n const boundWitnesses = await diviner.divine([query])\n if (boundWitnesses.length > 0) {\n const boundWitness = boundWitnesses[0]\n if (isBoundWitness(boundWitness)) {\n // Find the index for this address in the BoundWitness that is a ModuleState\n hash = boundWitness.addresses\n .map((address, index) => ({ address, index }))\n .filter(({ address }) => address === this.account.address)\n .reduce(\n (prev, curr) => (boundWitness.payload_schemas?.[curr?.index] === ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev),\n '',\n )\n }\n }\n\n // If we able to located the last state\n if (hash) {\n // Get last state\n const stateStoreArchivist = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`)\n await withArchivistModule(\n assertEx(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),\n async (mod) => {\n const archivist = ArchivistWrapper.wrap(mod, this.account)\n const payloads = await archivist.get([hash])\n if (payloads.length > 0) {\n const payload = payloads[0]\n if (isModuleState(payload)) {\n return payload.state\n }\n }\n },\n )\n }\n return undefined\n }\n\n protected override async stopHandler(_timeout?: number | undefined): Promise<boolean> {\n if (this._pollId) {\n clearTimeout(this._pollId)\n this._pollId = undefined\n }\n return await super.stopHandler()\n }\n\n private async poll() {\n if (await this.started()) {\n this._pollId = setTimeout(async () => {\n this._pollId = undefined\n await this.backgroundDivine()\n await this.poll()\n }, this.pollFrequency)\n }\n }\n}\n","import { DivinerConfig } from '@xyo-network/diviner-model'\nimport { ImageThumbnailSchema } from '@xyo-network/image-thumbnail-payload-plugin'\n\nexport const ImageThumbnailDivinerConfigSchema = `${ImageThumbnailSchema}.diviner.config` as const\nexport type ImageThumbnailDivinerConfigSchema = typeof ImageThumbnailDivinerConfigSchema\n\n/**\n * Describes an Archivist/Diviner combination\n * that enables searching signed payloads\n */\nexport interface SearchableStorage {\n archivist: string\n boundWitnessDiviner: string\n payloadDiviner: string\n}\n\nexport type ImageThumbnailDivinerConfig = DivinerConfig<{\n /** @deprecated Use appropriate Storage */\n archivist?: string\n /**\n * Where the diviner should store it's index\n */\n indexStore?: SearchableStorage\n /** @deprecated Use appropriate Storage */\n payloadDiviner?: string\n payloadDivinerLimit?: number\n pollFrequency?: number\n schema: ImageThumbnailDivinerConfigSchema\n /**\n * Where the diviner should persist its internal state\n */\n stateStore?: SearchableStorage\n /**\n * Where the diviner should look for stored thumbnails\n */\n thumbnailStore?: SearchableStorage\n}>\n"],"mappings":"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","names":["import_image_thumbnail_payload_plugin","module","_a"]}
|