@my-packages-changeit/abstract-scanner 2.0.3
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/CHANGELOG.md +135 -0
- package/README.md +49 -0
- package/dist/entities/blockEntity.d.ts +17 -0
- package/dist/entities/blockEntity.d.ts.map +1 -0
- package/dist/entities/blockEntity.js +78 -0
- package/dist/entities/extractorStatusEntity.d.ts +7 -0
- package/dist/entities/extractorStatusEntity.d.ts.map +1 -0
- package/dist/entities/extractorStatusEntity.js +37 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +31 -0
- package/dist/migrations/postgres/1688545690867-migration.d.ts +7 -0
- package/dist/migrations/postgres/1688545690867-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1688545690867-migration.js +30 -0
- package/dist/migrations/postgres/1713803486477-migration.d.ts +7 -0
- package/dist/migrations/postgres/1713803486477-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1713803486477-migration.js +20 -0
- package/dist/migrations/postgres/1718789786123-migration.d.ts +7 -0
- package/dist/migrations/postgres/1718789786123-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1718789786123-migration.js +12 -0
- package/dist/migrations/postgres/1722697954558-migration.d.ts +7 -0
- package/dist/migrations/postgres/1722697954558-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1722697954558-migration.js +52 -0
- package/dist/migrations/postgres/1746701087567-migration.d.ts +7 -0
- package/dist/migrations/postgres/1746701087567-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1746701087567-migration.js +32 -0
- package/dist/migrations/postgres/1747657653564-migration.d.ts +7 -0
- package/dist/migrations/postgres/1747657653564-migration.d.ts.map +1 -0
- package/dist/migrations/postgres/1747657653564-migration.js +134 -0
- package/dist/migrations/sqlite/1688555497475-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1688555497475-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1688555497475-migration.js +29 -0
- package/dist/migrations/sqlite/1713786682123-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1713786682123-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1713786682123-migration.js +20 -0
- package/dist/migrations/sqlite/1718789744123-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1718789744123-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1718789744123-migration.js +12 -0
- package/dist/migrations/sqlite/1722697111974-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1722697111974-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1722697111974-migration.js +112 -0
- package/dist/migrations/sqlite/1746701087234-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1746701087234-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1746701087234-migration.js +32 -0
- package/dist/migrations/sqlite/1747655941239-migration.d.ts +7 -0
- package/dist/migrations/sqlite/1747655941239-migration.d.ts.map +1 -0
- package/dist/migrations/sqlite/1747655941239-migration.js +134 -0
- package/dist/scanner/abstract/generalScanner.d.ts +78 -0
- package/dist/scanner/abstract/generalScanner.d.ts.map +1 -0
- package/dist/scanner/abstract/generalScanner.js +210 -0
- package/dist/scanner/abstract/scanner.d.ts +49 -0
- package/dist/scanner/abstract/scanner.d.ts.map +1 -0
- package/dist/scanner/abstract/scanner.js +142 -0
- package/dist/scanner/abstract/webSocketScanner.d.ts +29 -0
- package/dist/scanner/abstract/webSocketScanner.d.ts.map +1 -0
- package/dist/scanner/abstract/webSocketScanner.js +90 -0
- package/dist/scanner/action.d.ts +83 -0
- package/dist/scanner/action.d.ts.map +1 -0
- package/dist/scanner/action.js +251 -0
- package/dist/scanner/interfaces.d.ts +13 -0
- package/dist/scanner/interfaces.d.ts.map +1 -0
- package/dist/scanner/interfaces.js +2 -0
- package/dist/scanner/network/connectorSelectionStrategies.d.ts +27 -0
- package/dist/scanner/network/connectorSelectionStrategies.d.ts.map +1 -0
- package/dist/scanner/network/connectorSelectionStrategies.js +22 -0
- package/dist/scanner/network/networkConnectorManager.d.ts +65 -0
- package/dist/scanner/network/networkConnectorManager.d.ts.map +1 -0
- package/dist/scanner/network/networkConnectorManager.js +126 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { DummyLogger } from '@rosen-bridge/abstract-logger';
|
|
2
|
+
import { MoreThanOrEqual, In, } from '@rosen-bridge/extended-typeorm';
|
|
3
|
+
import { BlockEntity, PROCEED, PROCESSING } from '../entities/blockEntity';
|
|
4
|
+
import { ExtractorStatusEntity } from '../entities/extractorStatusEntity';
|
|
5
|
+
export class BlockDbAction {
|
|
6
|
+
blockRepository;
|
|
7
|
+
extractorStatusRepository;
|
|
8
|
+
dataSource;
|
|
9
|
+
scannerName;
|
|
10
|
+
logger;
|
|
11
|
+
constructor(dataSource, scannerName, logger) {
|
|
12
|
+
this.blockRepository = dataSource.getRepository(BlockEntity);
|
|
13
|
+
this.extractorStatusRepository = dataSource.getRepository(ExtractorStatusEntity);
|
|
14
|
+
this.dataSource = dataSource;
|
|
15
|
+
this.scannerName = scannerName;
|
|
16
|
+
this.logger = logger ? logger : new DummyLogger();
|
|
17
|
+
}
|
|
18
|
+
name = () => this.scannerName;
|
|
19
|
+
/**
|
|
20
|
+
* get last saved block
|
|
21
|
+
* @return Promise<BlockEntity or undefined>
|
|
22
|
+
*/
|
|
23
|
+
getLastSavedBlock = async () => {
|
|
24
|
+
const lastBlock = await this.blockRepository.find({
|
|
25
|
+
where: { status: PROCEED, scanner: this.name() },
|
|
26
|
+
order: { height: 'DESC' },
|
|
27
|
+
take: 1,
|
|
28
|
+
});
|
|
29
|
+
if (lastBlock.length !== 0) {
|
|
30
|
+
return lastBlock[0];
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* get last n stored blocks in database
|
|
38
|
+
* @param skip
|
|
39
|
+
* @param count
|
|
40
|
+
*/
|
|
41
|
+
getLastSavedBlocks = async (skip, count) => {
|
|
42
|
+
return await this.blockRepository.find({
|
|
43
|
+
where: { status: PROCEED, scanner: this.name() },
|
|
44
|
+
order: { height: 'DESC' },
|
|
45
|
+
skip: skip,
|
|
46
|
+
take: count,
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* get first saved block
|
|
51
|
+
* @return Promise<BlockEntity or undefined>
|
|
52
|
+
*/
|
|
53
|
+
getFirstSavedBlock = async () => {
|
|
54
|
+
const lastBlock = await this.blockRepository.find({
|
|
55
|
+
where: { status: PROCEED, scanner: this.name() },
|
|
56
|
+
order: { height: 'ASC' },
|
|
57
|
+
take: 1,
|
|
58
|
+
});
|
|
59
|
+
if (lastBlock.length !== 0) {
|
|
60
|
+
return lastBlock[0];
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* get block hash and height
|
|
68
|
+
* @param height
|
|
69
|
+
* @param status
|
|
70
|
+
* @return Promise<BlockEntity|undefined>
|
|
71
|
+
*/
|
|
72
|
+
getBlockAtHeight = async (height, status = PROCEED) => {
|
|
73
|
+
const block = await this.blockRepository.findOneBy({
|
|
74
|
+
status: status,
|
|
75
|
+
height: height,
|
|
76
|
+
scanner: this.name(),
|
|
77
|
+
});
|
|
78
|
+
if (block !== null) {
|
|
79
|
+
return block;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* get block with entered blockhash
|
|
87
|
+
* @param hash
|
|
88
|
+
* @param status
|
|
89
|
+
*/
|
|
90
|
+
getBlockWithHash = async (hash, status = PROCEED) => {
|
|
91
|
+
return this.blockRepository.findOneBy({
|
|
92
|
+
hash: hash,
|
|
93
|
+
status: status,
|
|
94
|
+
scanner: this.name(),
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* it deletes every block that more than or equal height
|
|
99
|
+
* @param height
|
|
100
|
+
* @return Promise<DeleteResult>
|
|
101
|
+
*/
|
|
102
|
+
removeBlocksFromHeight = async (height) => {
|
|
103
|
+
this.logger.debug(`Removing blocks from height ${height}`);
|
|
104
|
+
return await this.blockRepository.delete({
|
|
105
|
+
height: MoreThanOrEqual(height),
|
|
106
|
+
scanner: this.name(),
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* store a block into database.
|
|
111
|
+
* @param block
|
|
112
|
+
*/
|
|
113
|
+
saveBlock = async (block) => {
|
|
114
|
+
try {
|
|
115
|
+
const instance = await this.blockRepository.findOneBy({
|
|
116
|
+
height: block.height,
|
|
117
|
+
scanner: this.name(),
|
|
118
|
+
});
|
|
119
|
+
const date = new Date(block.timestamp * 1000);
|
|
120
|
+
const blockInfo = {
|
|
121
|
+
height: block.height,
|
|
122
|
+
hash: block.hash,
|
|
123
|
+
parentHash: block.parentHash,
|
|
124
|
+
status: PROCESSING,
|
|
125
|
+
scanner: this.name(),
|
|
126
|
+
extra: block.extra,
|
|
127
|
+
timestamp: block.timestamp,
|
|
128
|
+
year: date.getFullYear(),
|
|
129
|
+
month: date.getMonth() + 1,
|
|
130
|
+
day: date.getDate(),
|
|
131
|
+
};
|
|
132
|
+
if (!instance) {
|
|
133
|
+
this.logger.debug(`Inserting block with info: ${JSON.stringify(blockInfo)}`);
|
|
134
|
+
await this.blockRepository.insert(blockInfo);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.logger.debug(`Updating block with info: ${JSON.stringify(blockInfo)}`);
|
|
138
|
+
await this.blockRepository.update({ height: block.height, scanner: this.name() }, blockInfo);
|
|
139
|
+
}
|
|
140
|
+
const res = await this.blockRepository.findOneBy({
|
|
141
|
+
height: block.height,
|
|
142
|
+
scanner: this.name(),
|
|
143
|
+
});
|
|
144
|
+
return res ? res : false;
|
|
145
|
+
}
|
|
146
|
+
catch (exp) {
|
|
147
|
+
this.logger.error(`An error occurred during save new block: ${exp}`);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Update status of a block to proceed
|
|
153
|
+
* @param height: height of expected block
|
|
154
|
+
*/
|
|
155
|
+
updateBlockStatus = async (height, blockHash, extractorIds) => {
|
|
156
|
+
let success = true;
|
|
157
|
+
this.logger.debug(`Block at height ${height} has been proceed in scanner ${this.name()}, updating status`);
|
|
158
|
+
const runner = this.dataSource.createQueryRunner();
|
|
159
|
+
await runner.connect();
|
|
160
|
+
await runner.startTransaction();
|
|
161
|
+
try {
|
|
162
|
+
await runner.manager.getRepository(BlockEntity).update({
|
|
163
|
+
height: height,
|
|
164
|
+
status: PROCESSING,
|
|
165
|
+
scanner: this.name(),
|
|
166
|
+
}, {
|
|
167
|
+
status: PROCEED,
|
|
168
|
+
});
|
|
169
|
+
this.logger.debug('Updating extractors status', {
|
|
170
|
+
extractorIds,
|
|
171
|
+
});
|
|
172
|
+
await runner.manager
|
|
173
|
+
.getRepository(ExtractorStatusEntity)
|
|
174
|
+
.update({ extractorId: In(extractorIds), scannerId: this.name() }, { updateHeight: height, updateBlockHash: blockHash });
|
|
175
|
+
await runner.commitTransaction();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
await runner.rollbackTransaction();
|
|
179
|
+
success = false;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
await runner.release();
|
|
183
|
+
}
|
|
184
|
+
return success;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Update status of a block to processing in case of fork
|
|
188
|
+
* @param height: height of expected block
|
|
189
|
+
*/
|
|
190
|
+
revertBlockStatus = async (height, parentHash, extractorIds) => {
|
|
191
|
+
let success = true;
|
|
192
|
+
const runner = this.dataSource.createQueryRunner();
|
|
193
|
+
await runner.connect();
|
|
194
|
+
await runner.startTransaction();
|
|
195
|
+
try {
|
|
196
|
+
this.logger.debug(`Reverting block status at height ${height}`);
|
|
197
|
+
await runner.manager.getRepository(BlockEntity).update({
|
|
198
|
+
height: height,
|
|
199
|
+
status: PROCEED,
|
|
200
|
+
scanner: this.name(),
|
|
201
|
+
}, {
|
|
202
|
+
status: PROCESSING,
|
|
203
|
+
});
|
|
204
|
+
this.logger.debug(`Reverting extractors update height to previous block at height ${height - 1}`);
|
|
205
|
+
await runner.manager
|
|
206
|
+
.getRepository(ExtractorStatusEntity)
|
|
207
|
+
.update({ extractorId: In(extractorIds), scannerId: this.name() }, { updateHeight: height - 1, updateBlockHash: parentHash });
|
|
208
|
+
await runner.commitTransaction();
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
this.logger.warn(`An Error occurred while reverting block status: ${e}`);
|
|
212
|
+
await runner.rollbackTransaction();
|
|
213
|
+
success = false;
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
await runner.release();
|
|
217
|
+
}
|
|
218
|
+
return success;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Insert a newly initialized extractor or update an existing extractor status
|
|
222
|
+
* @param extractorId
|
|
223
|
+
* @param height
|
|
224
|
+
* @returns
|
|
225
|
+
*/
|
|
226
|
+
updateOrInsertExtractorStatus = async (extractorId, height, blockHash) => {
|
|
227
|
+
this.logger.debug('Inserting new extractor status or Updating existing resynced extractor status', {
|
|
228
|
+
extractorId,
|
|
229
|
+
height,
|
|
230
|
+
blockHash,
|
|
231
|
+
});
|
|
232
|
+
return await this.extractorStatusRepository.save({
|
|
233
|
+
scannerId: this.name(),
|
|
234
|
+
extractorId,
|
|
235
|
+
updateHeight: height,
|
|
236
|
+
updateBlockHash: blockHash,
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Return extractors` status specified by id
|
|
241
|
+
* @param extractorIds
|
|
242
|
+
* @returns extractors` status
|
|
243
|
+
*/
|
|
244
|
+
getExtractorsStatus = async (extractorIds) => {
|
|
245
|
+
return await this.extractorStatusRepository.findBy({
|
|
246
|
+
scannerId: this.name(),
|
|
247
|
+
extractorId: In(extractorIds),
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL3NjYW5uZXIvYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBa0IsV0FBVyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDNUUsT0FBTyxFQUdMLGVBQWUsRUFFZixFQUFFLEdBQ0gsTUFBTSxnQ0FBZ0MsQ0FBQztBQUd4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMzRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUUxRSxNQUFNLE9BQU8sYUFBYTtJQUNmLGVBQWUsQ0FBMEI7SUFDekMseUJBQXlCLENBQW9DO0lBQzdELFVBQVUsQ0FBYTtJQUN2QixXQUFXLENBQVM7SUFDcEIsTUFBTSxDQUFpQjtJQUVoQyxZQUNFLFVBQXNCLEVBQ3RCLFdBQW1CLEVBQ25CLE1BQXVCO1FBRXZCLElBQUksQ0FBQyxlQUFlLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM3RCxJQUFJLENBQUMseUJBQXlCLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FDdkQscUJBQXFCLENBQ3RCLENBQUM7UUFDRixJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUMvQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDO0lBQ3BELENBQUM7SUFFUSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUV2Qzs7O09BR0c7SUFDSCxpQkFBaUIsR0FBRyxLQUFLLElBQXNDLEVBQUU7UUFDL0QsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFD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LE9BQU8sQ0FBQztJQUNqQixDQUFDLENBQUM7SUFFRjs7Ozs7T0FLRztJQUNILDZCQUE2QixHQUFHLEtBQUssRUFDbkMsV0FBbUIsRUFDbkIsTUFBYyxFQUNkLFNBQWlCLEVBQ2pCLEVBQUU7UUFDRixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FDZiwrRUFBK0UsRUFDL0U7WUFDRSxXQUFXO1lBQ1gsTUFBTTtZQUNOLFNBQVM7U0FDVixDQUNGLENBQUM7UUFDRixPQUFPLE1BQU0sSUFBSSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQztZQUMvQyxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRTtZQUN0QixXQUFXO1lBQ1gsWUFBWSxFQUFFLE1BQU07WUFDcEIsZUFBZSxFQUFFLFNBQVM7U0FDM0IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0lBRUY7Ozs7T0FJRztJQUNILG1CQUFtQixHQUFHLEtBQUssRUFDekIsWUFBc0IsRUFDWSxFQUFFO1FBQ3BDLE9BQU8sTUFBTSxJQUFJLENBQUMseUJBQXlCLENBQUMsTUFBTSxDQUFDO1lBQ2pELFNBQVMsRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ3RCLFdBQVcsRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDO1NBQzlCLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQztDQUNIIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWJzdHJhY3RMb2dnZXIsIER1bW15TG9nZ2VyIH0gZnJvbSAnQHJvc2VuLWJyaWRnZS9hYnN0cmFjdC1sb2dnZXInO1xuaW1wb3J0IHtcbiAgRGF0YVNvdXJjZSxcbiAgRGVsZXRlUmVzdWx0LFxuICBNb3JlVGhhbk9yRXF1YWwsXG4gIFJlcG9zaXRvcnksXG4gIEluLFxufSBmcm9tICdAcm9zZW4tYnJpZGdlL2V4dGVuZGVkLXR5cGVvcm0nO1xuaW1wb3J0IHsgQmxvY2sgfSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5cbmltcG9ydCB7IEJsb2NrRW50aXR5LCBQUk9DRUVELCBQUk9DRVNTSU5HIH0gZnJvbSAnLi4vZW50aXRpZXMvYmxvY2tFbnRpdHknO1xuaW1wb3J0IHsgRXh0cmFjdG9yU3RhdHVzRW50aXR5IH0gZnJvbSAnLi4vZW50aXRpZXMvZXh0cmFjdG9yU3RhdHVzRW50aXR5JztcblxuZXhwb3J0IGNsYXNzIEJsb2NrRGJBY3Rpb24ge1xuICByZWFkb25seSBibG9ja1JlcG9zaXRvcnk6IFJlcG9zaXRvcnk8QmxvY2tFbnRpdHk+O1xuICByZWFkb25seSBleHRyYWN0b3JTdGF0dXNSZXBvc2l0b3J5OiBSZXBvc2l0b3J5PEV4dHJhY3RvclN0YXR1c0VudGl0eT47XG4gIHJlYWRvbmx5IGRhdGFTb3VyY2U6IERhdGFTb3VyY2U7XG4gIHJlYWRvbmx5IHNjYW5uZXJOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxvZ2dlcjogQWJzdHJhY3RMb2dnZXI7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgZGF0YVNvdXJjZTogRGF0YVNvdXJjZSxcbiAgICBzY2FubmVyTmFtZTogc3RyaW5nLFxuICAgIGxvZ2dlcj86IEFic3RyYWN0TG9nZ2VyLFxuICApIHtcbiAgICB0aGlzLmJsb2NrUmVwb3NpdG9yeSA9IGRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShCbG9ja0VudGl0eSk7XG4gICAgdGhpcy5leHRyYWN0b3JTdGF0dXNSZXBvc2l0b3J5ID0gZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KFxuICAgICAgRXh0cmFjdG9yU3RhdHVzRW50aXR5LFxuICAgICk7XG4gICAgdGhpcy5kYXRhU291cmNlID0gZGF0YVNvdXJjZTtcbiAgICB0aGlzLnNjYW5uZXJOYW1lID0gc2Nhbm5lck5hbWU7XG4gICAgdGhpcy5sb2dnZXIgPSBsb2dnZXIgPyBsb2dnZXIgOiBuZXcgRHVtbXlMb2dnZXIoKTtcbiAgfVxuXG4gIHJlYWRvbmx5IG5hbWUgPSAoKSA9PiB0aGlzLnNjYW5uZXJOYW1lO1xuXG4gIC8qKlxuICAgKiBnZXQgbGFzdCBzYXZlZCBibG9ja1xuICAgKiBAcmV0dXJuIFByb21pc2U8QmxvY2tFbnRpdHkgb3IgdW5kZWZpbmVkPlxuICAgKi9cbiAgZ2V0TGFzdFNhdmVkQmxvY2sgPSBhc3luYyAoKTogUHJvbWlzZTxCbG9ja0VudGl0eSB8IHVuZGVmaW5lZD4gPT4ge1xuICAgIGNvbnN0IGxhc3RCbG9jayA9IGF3YWl0IHRoaXMuYmxvY2tSZXBvc2l0b3J5LmZpbmQoe1xuICAgICAgd2hlcmU6IHsgc3RhdHVzOiBQUk9DRUVELCBzY2FubmVyOiB0aGlzLm5hbWUoKSB9LFxuICAgICAgb3JkZXI6IHsgaGVpZ2h0OiAnREVTQycgfSxcbiAgICAgIHRha2U6IDEsXG4gICAgfSk7XG4gICAgaWYgKGxhc3RCbG9jay5sZW5ndGggIT09IDApIHtcbiAgICAgIHJldHVybiBsYXN0QmxvY2tbMF07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9O1xuXG4gIC8qKlxuICAgKiBnZXQgbGFzdCBuIHN0b3JlZCBibG9ja3MgaW4gZGF0YWJhc2VcbiAgICogQHBhcmFtIHNraXBcbiAgICogQHBhcmFtIGNvdW50XG4gICAqL1xuICBnZXRMYXN0U2F2ZWRCbG9ja3MgPSBhc3luYyAoXG4gICAgc2tpcDogbnVtYmVyLFxuICAgIGNvdW50OiBudW1iZXIsXG4gICk6IFByb21pc2U8QXJyYXk8QmxvY2tFbnRpdHk+PiA9PiB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuYmxvY2tSZXBvc2l0b3J5LmZpbmQoe1xuICAgICAgd2hlcmU6IHsgc3RhdHVzOiBQUk9DRUVELCBzY2FubmVyOiB0aGlzLm5hbWUoKSB9LFxuICAgICAgb3JkZXI6IHsgaGVpZ2h0OiAnREVTQycgfSxcbiAgICAgIHNraXA6IHNraXAsXG4gICAgICB0YWtlOiBjb3VudCxcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogZ2V0IGZpcnN0IHNhdmVkIGJsb2NrXG4gICAqIEByZXR1cm4gUHJvbWlzZTxCbG9ja0VudGl0eSBvciB1bmRlZmluZWQ+XG4gICAqL1xuICBnZXRGaXJzdFNhdmVkQmxvY2sgPSBhc3luYyAoKTogUHJvbWlzZTxCbG9ja0VudGl0eSB8IHVuZGVmaW5lZD4gPT4ge1xuICAgIGNvbnN0IGxhc3RCbG9jayA9IGF3YWl0IHRoaXMuYmxvY2tSZXBvc2l0b3J5LmZpbmQoe1xuICAgICAgd2hlcmU6IHsgc3RhdHVzOiBQUk9DRUVELCBzY2FubmVyOiB0aGlzLm5hbWUoKSB9LFxuICAgICAgb3JkZXI6IHsgaGVpZ2h0OiAnQVNDJyB9LFxuICAgICAgdGFrZTogMSxcbiAgICB9KTtcbiAgICBpZiAobGFzdEJsb2NrLmxlbmd0aCAhPT0gMCkge1xuICAgICAgcmV0dXJuIGxhc3RCbG9ja1swXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIGdldCBibG9jayBoYXNoIGFuZCBoZWlnaHRcbiAgICogQHBhcmFtIGhlaWdodFxuICAgKiBAcGFyYW0gc3RhdHVzXG4gICAqIEByZXR1cm4gUHJvbWlzZTxCbG9ja0VudGl0eXx1bmRlZmluZWQ+XG4gICAqL1xuICBnZXRCbG9ja0F0SGVpZ2h0ID0gYXN5bmMgKFxuICAgIGhlaWdodDogbnVtYmVyLFxuICAgIHN0YXR1czogc3RyaW5nID0gUFJPQ0VFRCxcbiAgKTogUHJvbWlzZTxCbG9ja0VudGl0eSB8IHVuZGVmaW5lZD4gPT4ge1xuICAgIGNvbnN0IGJsb2NrID0gYXdhaXQgdGhpcy5ibG9ja1JlcG9zaXRvcnkuZmluZE9uZUJ5KHtcbiAgICAgIHN0YXR1czogc3RhdHVzLFxuICAgICAgaGVpZ2h0OiBoZWlnaHQsXG4gICAgICBzY2FubmVyOiB0aGlzLm5hbWUoKSxcbiAgICB9KTtcbiAgICBpZiAoYmxvY2sgIT09IG51bGwpIHtcbiAgICAgIHJldHVybiBibG9jaztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIGdldCBibG9jayB3aXRoIGVudGVyZWQgYmxvY2toYXNoXG4gICAqIEBwYXJhbSBoYXNoXG4gICAqIEBwYXJhbSBzdGF0dXNcbiAgICovXG4gIGdldEJsb2NrV2l0aEhhc2ggPSBhc3luYyAoaGFzaDogc3RyaW5nLCBzdGF0dXM6IHN0cmluZyA9IFBST0NFRUQpID0+IHtcbiAgICByZXR1cm4gdGhpcy5ibG9ja1JlcG9zaXRvcnkuZmluZE9uZUJ5KHtcbiAgICAgIGhhc2g6IGhhc2gsXG4gICAgICBzdGF0dXM6IHN0YXR1cyxcbiAgICAgIHNjYW5uZXI6IHRoaXMubmFtZSgpLFxuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBpdCBkZWxldGVzIGV2ZXJ5IGJsb2NrIHRoYXQgbW9yZSB0aGFuIG9yIGVxdWFsIGhlaWdodFxuICAgKiBAcGFyYW0gaGVpZ2h0XG4gICAqIEByZXR1cm4gUHJvbWlzZTxEZWxldGVSZXN1bHQ+XG4gICAqL1xuICByZW1vdmVCbG9ja3NGcm9tSGVpZ2h0ID0gYXN5bmMgKGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxEZWxldGVSZXN1bHQ+ID0+IHtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhgUmVtb3ZpbmcgYmxvY2tzIGZyb20gaGVpZ2h0ICR7aGVpZ2h0fWApO1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmJsb2NrUmVwb3NpdG9yeS5kZWxldGUoe1xuICAgICAgaGVpZ2h0OiBNb3JlVGhhbk9yRXF1YWwoaGVpZ2h0KSxcbiAgICAgIHNjYW5uZXI6IHRoaXMubmFtZSgpLFxuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBzdG9yZSBhIGJsb2NrIGludG8gZGF0YWJhc2UuXG4gICAqIEBwYXJhbSBibG9ja1xuICAgKi9cbiAgc2F2ZUJsb2NrID0gYXN5bmMgKGJsb2NrOiBCbG9jayk6IFByb21pc2U8QmxvY2tFbnRpdHkgfCBib29sZWFuPiA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGluc3RhbmNlID0gYXdhaXQgdGhpcy5ibG9ja1JlcG9zaXRvcnkuZmluZE9uZUJ5KHtcbiAgICAgICAgaGVpZ2h0OiBibG9jay5oZWlnaHQsXG4gICAgICAgIHNjYW5uZXI6IHRoaXMubmFtZSgpLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoYmxvY2sudGltZXN0YW1wICogMTAwMCk7XG4gICAgICBjb25zdCBibG9ja0luZm8gPSB7XG4gICAgICAgIGhlaWdodDogYmxvY2suaGVpZ2h0LFxuICAgICAgICBoYXNoOiBibG9jay5oYXNoLFxuICAgICAgICBwYXJlbnRIYXNoOiBibG9jay5wYXJlbnRIYXNoLFxuICAgICAgICBzdGF0dXM6IFBST0NFU1NJTkcsXG4gICAgICAgIHNjYW5uZXI6IHRoaXMubmFtZSgpLFxuICAgICAgICBleHRyYTogYmxvY2suZXh0cmEsXG4gICAgICAgIHRpbWVzdGFtcDogYmxvY2sudGltZXN0YW1wLFxuICAgICAgICB5ZWFyOiBkYXRlLmdldEZ1bGxZZWFyKCksXG4gICAgICAgIG1vbnRoOiBkYXRlLmdldE1vbnRoKCkgKyAxLFxuICAgICAgICBkYXk6IGRhdGUuZ2V0RGF0ZSgpLFxuICAgICAgfTtcbiAgICAgIGlmICghaW5zdGFuY2UpIHtcbiAgICAgICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICAgICAgYEluc2VydGluZyBibG9jayB3aXRoIGluZm86ICR7SlNPTi5zdHJpbmdpZnkoYmxvY2tJbmZvKX1gLFxuICAgICAgICApO1xuICAgICAgICBhd2FpdCB0aGlzLmJsb2NrUmVwb3NpdG9yeS5pbnNlcnQoYmxvY2tJbmZvKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFxuICAgICAgICAgIGBVcGRhdGluZyBibG9jayB3aXRoIGluZm86ICR7SlNPTi5zdHJpbmdpZnkoYmxvY2tJbmZvKX1gLFxuICAgICAgICApO1xuICAgICAgICBhd2FpdCB0aGlzLmJsb2NrUmVwb3NpdG9yeS51cGRhdGUoXG4gICAgICAgICAgeyBoZWlnaHQ6IGJsb2NrLmhlaWdodCwgc2Nhbm5lcjogdGhpcy5uYW1lKCkgfSxcbiAgICAgICAgICBibG9ja0luZm8sXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLmJsb2NrUmVwb3NpdG9yeS5maW5kT25lQnkoe1xuICAgICAgICBoZWlnaHQ6IGJsb2NrLmhlaWdodCxcbiAgICAgICAgc2Nhbm5lcjogdGhpcy5uYW1lKCksXG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXMgPyByZXMgOiBmYWxzZTtcbiAgICB9IGNhdGNoIChleHApIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGBBbiBlcnJvciBvY2N1cnJlZCBkdXJpbmcgc2F2ZSBuZXcgYmxvY2s6ICR7ZXhwfWApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogVXBkYXRlIHN0YXR1cyBvZiBhIGJsb2NrIHRvIHByb2NlZWRcbiAgICogQHBhcmFtIGhlaWdodDogaGVpZ2h0IG9mIGV4cGVjdGVkIGJsb2NrXG4gICAqL1xuICB1cGRhdGVCbG9ja1N0YXR1cyA9IGFzeW5jIChcbiAgICBoZWlnaHQ6IG51bWJlcixcbiAgICBibG9ja0hhc2g6IHN0cmluZyxcbiAgICBleHRyYWN0b3JJZHM6IHN0cmluZ1tdLFxuICApOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgICBsZXQgc3VjY2VzcyA9IHRydWU7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICBgQmxvY2sgYXQgaGVpZ2h0ICR7aGVpZ2h0fSBoYXMgYmVlbiBwcm9jZWVkIGluIHNjYW5uZXIgJHt0aGlzLm5hbWUoKX0sIHVwZGF0aW5nIHN0YXR1c2AsXG4gICAgKTtcbiAgICBjb25zdCBydW5uZXIgPSB0aGlzLmRhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIoKTtcbiAgICBhd2FpdCBydW5uZXIuY29ubmVjdCgpO1xuICAgIGF3YWl0IHJ1bm5lci5zdGFydFRyYW5zYWN0aW9uKCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHJ1bm5lci5tYW5hZ2VyLmdldFJlcG9zaXRvcnkoQmxvY2tFbnRpdHkpLnVwZGF0ZShcbiAgICAgICAge1xuICAgICAgICAgIGhlaWdodDogaGVpZ2h0LFxuICAgICAgICAgIHN0YXR1czogUFJPQ0VTU0lORyxcbiAgICAgICAgICBzY2FubmVyOiB0aGlzLm5hbWUoKSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHN0YXR1czogUFJPQ0VFRCxcbiAgICAgICAgfSxcbiAgICAgICk7XG5cbiAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKCdVcGRhdGluZyBleHRyYWN0b3JzIHN0YXR1cycsIHtcbiAgICAgICAgZXh0cmFjdG9ySWRzLFxuICAgICAgfSk7XG4gICAgICBhd2FpdCBydW5uZXIubWFuYWdlclxuICAgICAgICAuZ2V0UmVwb3NpdG9yeShFeHRyYWN0b3JTdGF0dXNFbnRpdHkpXG4gICAgICAgIC51cGRhdGUoXG4gICAgICAgICAgeyBleHRyYWN0b3JJZDogSW4oZXh0cmFjdG9ySWRzKSwgc2Nhbm5lcklkOiB0aGlzLm5hbWUoKSB9LFxuICAgICAgICAgIHsgdXBkYXRlSGVpZ2h0OiBoZWlnaHQsIHVwZGF0ZUJsb2NrSGFzaDogYmxvY2tIYXNoIH0sXG4gICAgICAgICk7XG4gICAgICBhd2FpdCBydW5uZXIuY29tbWl0VHJhbnNhY3Rpb24oKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIGF3YWl0IHJ1bm5lci5yb2xsYmFja1RyYW5zYWN0aW9uKCk7XG4gICAgICBzdWNjZXNzID0gZmFsc2U7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHJ1bm5lci5yZWxlYXNlKCk7XG4gICAgfVxuICAgIHJldHVybiBzdWNjZXNzO1xuICB9O1xuXG4gIC8qKlxuICAgKiBVcGRhdGUgc3RhdHVzIG9mIGEgYmxvY2sgdG8gcHJvY2Vzc2luZyBpbiBjYXNlIG9mIGZvcmtcbiAgICogQHBhcmFtIGhlaWdodDogaGVpZ2h0IG9mIGV4cGVjdGVkIGJsb2NrXG4gICAqL1xuICByZXZlcnRCbG9ja1N0YXR1cyA9IGFzeW5jIChcbiAgICBoZWlnaHQ6IG51bWJlcixcbiAgICBwYXJlbnRIYXNoOiBzdHJpbmcsXG4gICAgZXh0cmFjdG9ySWRzOiBzdHJpbmdbXSxcbiAgKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgbGV0IHN1Y2Nlc3MgPSB0cnVlO1xuICAgIGNvbnN0IHJ1bm5lciA9IHRoaXMuZGF0YVNvdXJjZS5jcmVhdGVRdWVyeVJ1bm5lcigpO1xuICAgIGF3YWl0IHJ1bm5lci5jb25uZWN0KCk7XG4gICAgYXdhaXQgcnVubmVyLnN0YXJ0VHJhbnNhY3Rpb24oKTtcbiAgICB0cnkge1xuICAgICAgdGhpcy5sb2dnZXIuZGVidWcoYFJldmVydGluZyBibG9jayBzdGF0dXMgYXQgaGVpZ2h0ICR7aGVpZ2h0fWApO1xuICAgICAgYXdhaXQgcnVubmVyLm1hbmFnZXIuZ2V0UmVwb3NpdG9yeShCbG9ja0VudGl0eSkudXBkYXRlKFxuICAgICAgICB7XG4gICAgICAgICAgaGVpZ2h0OiBoZWlnaHQsXG4gICAgICAgICAgc3RhdHVzOiBQUk9DRUVELFxuICAgICAgICAgIHNjYW5uZXI6IHRoaXMubmFtZSgpLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgc3RhdHVzOiBQUk9DRVNTSU5HLFxuICAgICAgICB9LFxuICAgICAgKTtcblxuICAgICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICAgIGBSZXZlcnRpbmcgZXh0cmFjdG9ycyB1cGRhdGUgaGVpZ2h0IHRvIHByZXZpb3VzIGJsb2NrIGF0IGhlaWdodCAke1xuICAgICAgICAgIGhlaWdodCAtIDFcbiAgICAgICAgfWAsXG4gICAgICApO1xuICAgICAgYXdhaXQgcnVubmVyLm1hbmFnZXJcbiAgICAgICAgLmdldFJlcG9zaXRvcnkoRXh0cmFjdG9yU3RhdHVzRW50aXR5KVxuICAgICAgICAudXBkYXRlKFxuICAgICAgICAgIHsgZXh0cmFjdG9ySWQ6IEluKGV4dHJhY3RvcklkcyksIHNjYW5uZXJJZDogdGhpcy5uYW1lKCkgfSxcbiAgICAgICAgICB7IHVwZGF0ZUhlaWdodDogaGVpZ2h0IC0gMSwgdXBkYXRlQmxvY2tIYXNoOiBwYXJlbnRIYXNoIH0sXG4gICAgICAgICk7XG4gICAgICBhd2FpdCBydW5uZXIuY29tbWl0VHJhbnNhY3Rpb24oKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKGBBbiBFcnJvciBvY2N1cnJlZCB3aGlsZSByZXZlcnRpbmcgYmxvY2sgc3RhdHVzOiAke2V9YCk7XG4gICAgICBhd2FpdCBydW5uZXIucm9sbGJhY2tUcmFuc2FjdGlvbigpO1xuICAgICAgc3VjY2VzcyA9IGZhbHNlO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCBydW5uZXIucmVsZWFzZSgpO1xuICAgIH1cbiAgICByZXR1cm4gc3VjY2VzcztcbiAgfTtcblxuICAvKipcbiAgICogSW5zZXJ0IGEgbmV3bHkgaW5pdGlhbGl6ZWQgZXh0cmFjdG9yIG9yIHVwZGF0ZSBhbiBleGlzdGluZyBleHRyYWN0b3Igc3RhdHVzXG4gICAqIEBwYXJhbSBleHRyYWN0b3JJZFxuICAgKiBAcGFyYW0gaGVpZ2h0XG4gICAqIEByZXR1cm5zXG4gICAqL1xuICB1cGRhdGVPckluc2VydEV4dHJhY3RvclN0YXR1cyA9IGFzeW5jIChcbiAgICBleHRyYWN0b3JJZDogc3RyaW5nLFxuICAgIGhlaWdodDogbnVtYmVyLFxuICAgIGJsb2NrSGFzaDogc3RyaW5nLFxuICApID0+IHtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcbiAgICAgICdJbnNlcnRpbmcgbmV3IGV4dHJhY3RvciBzdGF0dXMgb3IgVXBkYXRpbmcgZXhpc3RpbmcgcmVzeW5jZWQgZXh0cmFjdG9yIHN0YXR1cycsXG4gICAgICB7XG4gICAgICAgIGV4dHJhY3RvcklkLFxuICAgICAgICBoZWlnaHQsXG4gICAgICAgIGJsb2NrSGFzaCxcbiAgICAgIH0sXG4gICAgKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5leHRyYWN0b3JTdGF0dXNSZXBvc2l0b3J5LnNhdmUoe1xuICAgICAgc2Nhbm5lcklkOiB0aGlzLm5hbWUoKSxcbiAgICAgIGV4dHJhY3RvcklkLFxuICAgICAgdXBkYXRlSGVpZ2h0OiBoZWlnaHQsXG4gICAgICB1cGRhdGVCbG9ja0hhc2g6IGJsb2NrSGFzaCxcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogUmV0dXJuIGV4dHJhY3RvcnNgIHN0YXR1cyBzcGVjaWZpZWQgYnkgaWRcbiAgICogQHBhcmFtIGV4dHJhY3Rvcklkc1xuICAgKiBAcmV0dXJucyBleHRyYWN0b3JzYCBzdGF0dXNcbiAgICovXG4gIGdldEV4dHJhY3RvcnNTdGF0dXMgPSBhc3luYyAoXG4gICAgZXh0cmFjdG9ySWRzOiBzdHJpbmdbXSxcbiAgKTogUHJvbWlzZTxFeHRyYWN0b3JTdGF0dXNFbnRpdHlbXT4gPT4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmV4dHJhY3RvclN0YXR1c1JlcG9zaXRvcnkuZmluZEJ5KHtcbiAgICAgIHNjYW5uZXJJZDogdGhpcy5uYW1lKCksXG4gICAgICBleHRyYWN0b3JJZDogSW4oZXh0cmFjdG9ySWRzKSxcbiAgICB9KTtcbiAgfTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractLogger } from '@rosen-bridge/abstract-logger';
|
|
2
|
+
import { DataSource } from '@rosen-bridge/extended-typeorm';
|
|
3
|
+
import { AbstractNetworkConnector } from '@rosen-bridge/scanner-interfaces';
|
|
4
|
+
export interface ScannerConfig<TransactionType> {
|
|
5
|
+
dataSource: DataSource;
|
|
6
|
+
initialHeight: number;
|
|
7
|
+
network: AbstractNetworkConnector<TransactionType>;
|
|
8
|
+
blockRetrieveGap?: number;
|
|
9
|
+
suffix?: string;
|
|
10
|
+
heightGap?: number;
|
|
11
|
+
logger?: AbstractLogger;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../lib/scanner/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,WAAW,aAAa,CAAC,eAAe;IAC5C,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,wBAAwB,CAAC,eAAe,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9zY2FubmVyL2ludGVyZmFjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFic3RyYWN0TG9nZ2VyIH0gZnJvbSAnQHJvc2VuLWJyaWRnZS9hYnN0cmFjdC1sb2dnZXInO1xuaW1wb3J0IHsgRGF0YVNvdXJjZSB9IGZyb20gJ0Byb3Nlbi1icmlkZ2UvZXh0ZW5kZWQtdHlwZW9ybSc7XG5pbXBvcnQgeyBBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3IgfSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2Nhbm5lckNvbmZpZzxUcmFuc2FjdGlvblR5cGU+IHtcbiAgZGF0YVNvdXJjZTogRGF0YVNvdXJjZTtcbiAgaW5pdGlhbEhlaWdodDogbnVtYmVyO1xuICBuZXR3b3JrOiBBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3I8VHJhbnNhY3Rpb25UeXBlPjtcbiAgYmxvY2tSZXRyaWV2ZUdhcD86IG51bWJlcjtcbiAgc3VmZml4Pzogc3RyaW5nO1xuICBoZWlnaHRHYXA/OiBudW1iZXI7XG4gIGxvZ2dlcj86IEFic3RyYWN0TG9nZ2VyO1xufVxuIl19
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AbstractNetworkConnector } from '@rosen-bridge/scanner-interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for connector selection strategies
|
|
4
|
+
*/
|
|
5
|
+
export interface ConnectorSelectionStrategy<TransactionType> {
|
|
6
|
+
/**
|
|
7
|
+
* Select the next connector to use
|
|
8
|
+
* @param connectors Array of available connectors
|
|
9
|
+
* @param currentIndex Current connector index
|
|
10
|
+
* @param lastError Error from the last operation, if any
|
|
11
|
+
* @returns The index of the next connector to use
|
|
12
|
+
*/
|
|
13
|
+
selectNextConnector(connectors: Array<AbstractNetworkConnector<TransactionType>>, currentIndex: number, lastError?: Error): number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Failover strategy - switches to next connector only on failure
|
|
17
|
+
*/
|
|
18
|
+
export declare class FailoverStrategy<TransactionType> implements ConnectorSelectionStrategy<TransactionType> {
|
|
19
|
+
selectNextConnector(connectors: Array<AbstractNetworkConnector<TransactionType>>, currentIndex: number, lastError?: Error): number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Round-robin strategy - switches to next connector after each operation
|
|
23
|
+
*/
|
|
24
|
+
export declare class RoundRobinStrategy<TransactionType> implements ConnectorSelectionStrategy<TransactionType> {
|
|
25
|
+
selectNextConnector(connectors: Array<AbstractNetworkConnector<TransactionType>>, currentIndex: number): number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=connectorSelectionStrategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectorSelectionStrategies.d.ts","sourceRoot":"","sources":["../../../lib/scanner/network/connectorSelectionStrategies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,0BAA0B,CAAC,eAAe;IACzD;;;;;;OAMG;IACH,mBAAmB,CACjB,UAAU,EAAE,KAAK,CAAC,wBAAwB,CAAC,eAAe,CAAC,CAAC,EAC5D,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,KAAK,GAChB,MAAM,CAAC;CACX;AAED;;GAEG;AACH,qBAAa,gBAAgB,CAAC,eAAe,CAC3C,YAAW,0BAA0B,CAAC,eAAe,CAAC;IAEtD,mBAAmB,CACjB,UAAU,EAAE,KAAK,CAAC,wBAAwB,CAAC,eAAe,CAAC,CAAC,EAC5D,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,KAAK,GAChB,MAAM;CAQV;AAED;;GAEG;AACH,qBAAa,kBAAkB,CAAC,eAAe,CAC7C,YAAW,0BAA0B,CAAC,eAAe,CAAC;IAEtD,mBAAmB,CACjB,UAAU,EAAE,KAAK,CAAC,wBAAwB,CAAC,eAAe,CAAC,CAAC,EAC5D,YAAY,EAAE,MAAM,GACnB,MAAM;CAGV"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failover strategy - switches to next connector only on failure
|
|
3
|
+
*/
|
|
4
|
+
export class FailoverStrategy {
|
|
5
|
+
selectNextConnector(connectors, currentIndex, lastError) {
|
|
6
|
+
// If there was an error, try the next connector
|
|
7
|
+
if (lastError) {
|
|
8
|
+
return (currentIndex + 1) % connectors.length;
|
|
9
|
+
}
|
|
10
|
+
// Otherwise stay with current connector
|
|
11
|
+
return currentIndex;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Round-robin strategy - switches to next connector after each operation
|
|
16
|
+
*/
|
|
17
|
+
export class RoundRobinStrategy {
|
|
18
|
+
selectNextConnector(connectors, currentIndex) {
|
|
19
|
+
return (currentIndex + 1) % connectors.length;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdG9yU2VsZWN0aW9uU3RyYXRlZ2llcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9zY2FubmVyL25ldHdvcmsvY29ubmVjdG9yU2VsZWN0aW9uU3RyYXRlZ2llcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkE7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBRzNCLG1CQUFtQixDQUNqQixVQUE0RCxFQUM1RCxZQUFvQixFQUNwQixTQUFpQjtRQUVqQixnREFBZ0Q7UUFDaEQsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNkLE9BQU8sQ0FBQyxZQUFZLEdBQUcsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQztRQUNoRCxDQUFDO1FBQ0Qsd0NBQXdDO1FBQ3hDLE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGtCQUFrQjtJQUc3QixtQkFBbUIsQ0FDakIsVUFBNEQsRUFDNUQsWUFBb0I7UUFFcEIsT0FBTyxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDO0lBQ2hELENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvciB9IGZyb20gJ0Byb3Nlbi1icmlkZ2Uvc2Nhbm5lci1pbnRlcmZhY2VzJztcblxuLyoqXG4gKiBJbnRlcmZhY2UgZm9yIGNvbm5lY3RvciBzZWxlY3Rpb24gc3RyYXRlZ2llc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWd5PFRyYW5zYWN0aW9uVHlwZT4ge1xuICAvKipcbiAgICogU2VsZWN0IHRoZSBuZXh0IGNvbm5lY3RvciB0byB1c2VcbiAgICogQHBhcmFtIGNvbm5lY3RvcnMgQXJyYXkgb2YgYXZhaWxhYmxlIGNvbm5lY3RvcnNcbiAgICogQHBhcmFtIGN1cnJlbnRJbmRleCBDdXJyZW50IGNvbm5lY3RvciBpbmRleFxuICAgKiBAcGFyYW0gbGFzdEVycm9yIEVycm9yIGZyb20gdGhlIGxhc3Qgb3BlcmF0aW9uLCBpZiBhbnlcbiAgICogQHJldHVybnMgVGhlIGluZGV4IG9mIHRoZSBuZXh0IGNvbm5lY3RvciB0byB1c2VcbiAgICovXG4gIHNlbGVjdE5leHRDb25uZWN0b3IoXG4gICAgY29ubmVjdG9yczogQXJyYXk8QWJzdHJhY3ROZXR3b3JrQ29ubmVjdG9yPFRyYW5zYWN0aW9uVHlwZT4+LFxuICAgIGN1cnJlbnRJbmRleDogbnVtYmVyLFxuICAgIGxhc3RFcnJvcj86IEVycm9yLFxuICApOiBudW1iZXI7XG59XG5cbi8qKlxuICogRmFpbG92ZXIgc3RyYXRlZ3kgLSBzd2l0Y2hlcyB0byBuZXh0IGNvbm5lY3RvciBvbmx5IG9uIGZhaWx1cmVcbiAqL1xuZXhwb3J0IGNsYXNzIEZhaWxvdmVyU3RyYXRlZ3k8VHJhbnNhY3Rpb25UeXBlPlxuICBpbXBsZW1lbnRzIENvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWd5PFRyYW5zYWN0aW9uVHlwZT5cbntcbiAgc2VsZWN0TmV4dENvbm5lY3RvcihcbiAgICBjb25uZWN0b3JzOiBBcnJheTxBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3I8VHJhbnNhY3Rpb25UeXBlPj4sXG4gICAgY3VycmVudEluZGV4OiBudW1iZXIsXG4gICAgbGFzdEVycm9yPzogRXJyb3IsXG4gICk6IG51bWJlciB7XG4gICAgLy8gSWYgdGhlcmUgd2FzIGFuIGVycm9yLCB0cnkgdGhlIG5leHQgY29ubmVjdG9yXG4gICAgaWYgKGxhc3RFcnJvcikge1xuICAgICAgcmV0dXJuIChjdXJyZW50SW5kZXggKyAxKSAlIGNvbm5lY3RvcnMubGVuZ3RoO1xuICAgIH1cbiAgICAvLyBPdGhlcndpc2Ugc3RheSB3aXRoIGN1cnJlbnQgY29ubmVjdG9yXG4gICAgcmV0dXJuIGN1cnJlbnRJbmRleDtcbiAgfVxufVxuXG4vKipcbiAqIFJvdW5kLXJvYmluIHN0cmF0ZWd5IC0gc3dpdGNoZXMgdG8gbmV4dCBjb25uZWN0b3IgYWZ0ZXIgZWFjaCBvcGVyYXRpb25cbiAqL1xuZXhwb3J0IGNsYXNzIFJvdW5kUm9iaW5TdHJhdGVneTxUcmFuc2FjdGlvblR5cGU+XG4gIGltcGxlbWVudHMgQ29ubmVjdG9yU2VsZWN0aW9uU3RyYXRlZ3k8VHJhbnNhY3Rpb25UeXBlPlxue1xuICBzZWxlY3ROZXh0Q29ubmVjdG9yKFxuICAgIGNvbm5lY3RvcnM6IEFycmF5PEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvcjxUcmFuc2FjdGlvblR5cGU+PixcbiAgICBjdXJyZW50SW5kZXg6IG51bWJlcixcbiAgKTogbnVtYmVyIHtcbiAgICByZXR1cm4gKGN1cnJlbnRJbmRleCArIDEpICUgY29ubmVjdG9ycy5sZW5ndGg7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AbstractLogger } from '@rosen-bridge/abstract-logger';
|
|
2
|
+
import { AbstractNetworkConnector, Block } from '@rosen-bridge/scanner-interfaces';
|
|
3
|
+
import { ConnectorSelectionStrategy } from './connectorSelectionStrategies';
|
|
4
|
+
/**
|
|
5
|
+
* Network connector manager that can handle multiple connectors
|
|
6
|
+
* for a single network with pluggable selection strategy
|
|
7
|
+
*/
|
|
8
|
+
export declare class NetworkConnectorManager<TransactionType> implements AbstractNetworkConnector<TransactionType> {
|
|
9
|
+
private strategy;
|
|
10
|
+
private logger;
|
|
11
|
+
private connectors;
|
|
12
|
+
private currentConnectorIndex;
|
|
13
|
+
constructor(strategy?: ConnectorSelectionStrategy<TransactionType>, logger?: AbstractLogger);
|
|
14
|
+
/**
|
|
15
|
+
* Add a new connector to the manager
|
|
16
|
+
* @param connector The network connector instance
|
|
17
|
+
*/
|
|
18
|
+
addConnector(connector: AbstractNetworkConnector<TransactionType>): void;
|
|
19
|
+
/**
|
|
20
|
+
* Get the current active connector
|
|
21
|
+
* @returns The current network connector instance
|
|
22
|
+
* @throws Error if no connectors are available
|
|
23
|
+
*/
|
|
24
|
+
getCurrentConnector(): AbstractNetworkConnector<TransactionType>;
|
|
25
|
+
/**
|
|
26
|
+
* Execute an operation using the configured strategy
|
|
27
|
+
* @param operation The operation to execute
|
|
28
|
+
* @returns The result of the operation
|
|
29
|
+
*/
|
|
30
|
+
private executeWithStrategy;
|
|
31
|
+
/**
|
|
32
|
+
* Set the strategy to use for connector selection
|
|
33
|
+
* @param strategy The strategy to use
|
|
34
|
+
*/
|
|
35
|
+
setStrategy(strategy: ConnectorSelectionStrategy<TransactionType>): void;
|
|
36
|
+
/**
|
|
37
|
+
* Get a block at a specific height
|
|
38
|
+
* @param height The height of the block to get
|
|
39
|
+
* @returns The block at the specified height
|
|
40
|
+
*/
|
|
41
|
+
getBlockAtHeight: (height: number) => Promise<Block>;
|
|
42
|
+
/**
|
|
43
|
+
* Get the current height of the blockchain
|
|
44
|
+
* @returns The current height
|
|
45
|
+
*/
|
|
46
|
+
getCurrentHeight: () => Promise<number>;
|
|
47
|
+
/**
|
|
48
|
+
* Get all transactions in a block
|
|
49
|
+
* @param blockHash The hash of the block to get transactions from
|
|
50
|
+
* @param height The height of the block to get transactions from
|
|
51
|
+
* @returns Array of transactions in the block
|
|
52
|
+
*/
|
|
53
|
+
getBlockTxs: (blockHash: string, height: number) => Promise<Array<TransactionType>>;
|
|
54
|
+
/**
|
|
55
|
+
* Get the number of available connectors
|
|
56
|
+
* @returns The number of connectors
|
|
57
|
+
*/
|
|
58
|
+
getConnectorCount(): number;
|
|
59
|
+
/**
|
|
60
|
+
* Remove a connector at the specified index
|
|
61
|
+
* @param index The index of the connector to remove
|
|
62
|
+
*/
|
|
63
|
+
removeConnector(index: number): void;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=networkConnectorManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"networkConnectorManager.d.ts","sourceRoot":"","sources":["../../../lib/scanner/network/networkConnectorManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAe,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EACL,wBAAwB,EACxB,KAAK,EACN,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,0BAA0B,EAE3B,MAAM,gCAAgC,CAAC;AAExC;;;GAGG;AACH,qBAAa,uBAAuB,CAAC,eAAe,CAClD,YAAW,wBAAwB,CAAC,eAAe,CAAC;IAMlD,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,UAAU,CAAmD;IACrE,OAAO,CAAC,qBAAqB,CAAS;gBAG5B,QAAQ,GAAE,0BAA0B,CAAC,eAAe,CAA2C,EAC/F,MAAM,GAAE,cAAkC;IAQpD;;;OAGG;IACI,YAAY,CACjB,SAAS,EAAE,wBAAwB,CAAC,eAAe,CAAC,GACnD,IAAI;IAOP;;;;OAIG;IACH,mBAAmB,IAAI,wBAAwB,CAAC,eAAe,CAAC;IAQhE;;;;OAIG;YACW,mBAAmB;IA8CjC;;;OAGG;IACI,WAAW,CAChB,QAAQ,EAAE,0BAA0B,CAAC,eAAe,CAAC,GACpD,IAAI;IAKP;;;;OAIG;IACH,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CAIvD;IAEF;;;OAGG;IACH,gBAAgB,QAAa,OAAO,CAAC,MAAM,CAAC,CAI1C;IAEF;;;;;OAKG;IACH,WAAW,GACT,WAAW,MAAM,EACjB,QAAQ,MAAM,KACb,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAIhC;IAEF;;;OAGG;IACI,iBAAiB,IAAI,MAAM;IAMlC;;;OAGG;IACI,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAU5C"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { DummyLogger } from '@rosen-bridge/abstract-logger';
|
|
2
|
+
import { FailoverStrategy, } from './connectorSelectionStrategies';
|
|
3
|
+
/**
|
|
4
|
+
* Network connector manager that can handle multiple connectors
|
|
5
|
+
* for a single network with pluggable selection strategy
|
|
6
|
+
*/
|
|
7
|
+
export class NetworkConnectorManager {
|
|
8
|
+
strategy;
|
|
9
|
+
logger;
|
|
10
|
+
connectors;
|
|
11
|
+
currentConnectorIndex;
|
|
12
|
+
constructor(strategy = new FailoverStrategy(), logger = new DummyLogger()) {
|
|
13
|
+
this.strategy = strategy;
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.connectors = [];
|
|
16
|
+
this.currentConnectorIndex = 0;
|
|
17
|
+
this.strategy = strategy;
|
|
18
|
+
this.logger.debug('NetworkConnectorManager initialized');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Add a new connector to the manager
|
|
22
|
+
* @param connector The network connector instance
|
|
23
|
+
*/
|
|
24
|
+
addConnector(connector) {
|
|
25
|
+
this.connectors.push(connector);
|
|
26
|
+
this.logger.info(`Added new connector. Total connectors: ${this.connectors.length}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the current active connector
|
|
30
|
+
* @returns The current network connector instance
|
|
31
|
+
* @throws Error if no connectors are available
|
|
32
|
+
*/
|
|
33
|
+
getCurrentConnector() {
|
|
34
|
+
if (this.connectors.length === 0) {
|
|
35
|
+
throw new Error('No connectors available');
|
|
36
|
+
}
|
|
37
|
+
this.logger.debug(`Using connector at index ${this.currentConnectorIndex}`);
|
|
38
|
+
return this.connectors[this.currentConnectorIndex];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Execute an operation using the configured strategy
|
|
42
|
+
* @param operation The operation to execute
|
|
43
|
+
* @returns The result of the operation
|
|
44
|
+
*/
|
|
45
|
+
async executeWithStrategy(operation) {
|
|
46
|
+
if (this.connectors.length === 0) {
|
|
47
|
+
throw new Error('No connectors available for operation');
|
|
48
|
+
}
|
|
49
|
+
let lastError;
|
|
50
|
+
let attempts = 0;
|
|
51
|
+
const maxAttempts = this.connectors.length;
|
|
52
|
+
while (attempts < maxAttempts) {
|
|
53
|
+
try {
|
|
54
|
+
const connector = this.connectors[this.currentConnectorIndex];
|
|
55
|
+
this.logger.debug(`Attempt ${attempts + 1}/${maxAttempts} with connector at index ${this.currentConnectorIndex}`);
|
|
56
|
+
const result = await operation(connector);
|
|
57
|
+
this.currentConnectorIndex = this.strategy.selectNextConnector(this.connectors, this.currentConnectorIndex);
|
|
58
|
+
this.logger.debug(`Operation successful, next connector index: ${this.currentConnectorIndex}`);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
lastError = error;
|
|
63
|
+
this.logger.warn(`Operation failed with connector at index ${this.currentConnectorIndex}: ${lastError.message}`);
|
|
64
|
+
this.currentConnectorIndex = this.strategy.selectNextConnector(this.connectors, this.currentConnectorIndex, lastError);
|
|
65
|
+
attempts++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw lastError || new Error('All connectors failed');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Set the strategy to use for connector selection
|
|
72
|
+
* @param strategy The strategy to use
|
|
73
|
+
*/
|
|
74
|
+
setStrategy(strategy) {
|
|
75
|
+
this.logger.info('Setting new connector selection strategy');
|
|
76
|
+
this.strategy = strategy;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a block at a specific height
|
|
80
|
+
* @param height The height of the block to get
|
|
81
|
+
* @returns The block at the specified height
|
|
82
|
+
*/
|
|
83
|
+
getBlockAtHeight = async (height) => {
|
|
84
|
+
return this.executeWithStrategy((connector) => connector.getBlockAtHeight(height));
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Get the current height of the blockchain
|
|
88
|
+
* @returns The current height
|
|
89
|
+
*/
|
|
90
|
+
getCurrentHeight = async () => {
|
|
91
|
+
return this.executeWithStrategy((connector) => connector.getCurrentHeight());
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Get all transactions in a block
|
|
95
|
+
* @param blockHash The hash of the block to get transactions from
|
|
96
|
+
* @param height The height of the block to get transactions from
|
|
97
|
+
* @returns Array of transactions in the block
|
|
98
|
+
*/
|
|
99
|
+
getBlockTxs = async (blockHash, height) => {
|
|
100
|
+
return this.executeWithStrategy((connector) => connector.getBlockTxs(blockHash, height));
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Get the number of available connectors
|
|
104
|
+
* @returns The number of connectors
|
|
105
|
+
*/
|
|
106
|
+
getConnectorCount() {
|
|
107
|
+
const count = this.connectors.length;
|
|
108
|
+
this.logger.debug(`Current connector count: ${count}`);
|
|
109
|
+
return count;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Remove a connector at the specified index
|
|
113
|
+
* @param index The index of the connector to remove
|
|
114
|
+
*/
|
|
115
|
+
removeConnector(index) {
|
|
116
|
+
if (index < 0 || index >= this.connectors.length) {
|
|
117
|
+
throw new Error('Invalid connector index');
|
|
118
|
+
}
|
|
119
|
+
this.logger.info(`Removing connector at index ${index}`);
|
|
120
|
+
this.connectors.splice(index, 1);
|
|
121
|
+
if (this.currentConnectorIndex >= this.connectors.length) {
|
|
122
|
+
this.currentConnectorIndex = 0;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29ya0Nvbm5lY3Rvck1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvc2Nhbm5lci9uZXR3b3JrL25ldHdvcmtDb25uZWN0b3JNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBa0IsV0FBVyxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFNNUUsT0FBTyxFQUVMLGdCQUFnQixHQUNqQixNQUFNLGdDQUFnQyxDQUFDO0FBRXhDOzs7R0FHRztBQUNILE1BQU0sT0FBTyx1QkFBdUI7SUFPeEI7SUFDQTtJQUxGLFVBQVUsQ0FBbUQ7SUFDN0QscUJBQXFCLENBQVM7SUFFdEMsWUFDVSxXQUF3RCxJQUFJLGdCQUFnQixFQUFtQixFQUMvRixTQUF5QixJQUFJLFdBQVcsRUFBRTtRQUQxQyxhQUFRLEdBQVIsUUFBUSxDQUF1RjtRQUMvRixXQUFNLEdBQU4sTUFBTSxDQUFvQztRQUVsRCxJQUFJLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMscUJBQXFCLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVEOzs7T0FHRztJQUNJLFlBQVksQ0FDakIsU0FBb0Q7UUFFcEQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ2QsMENBQTBDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQ25FLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILG1CQUFtQjtRQUNqQixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUM3QyxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLENBQUM7UUFDNUUsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssS0FBSyxDQUFDLG1CQUFtQixDQUMvQixTQUVlO1FBRWYsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNqQyxNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUVELElBQUksU0FBNEIsQ0FBQztRQUNqQyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7UUFDakIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFFM0MsT0FBTyxRQUFRLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDO2dCQUNILE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUM7Z0JBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUNmLFdBQVcsUUFBUSxHQUFHLENBQUMsSUFBSSxXQUFXLDRCQUNwQyxJQUFJLENBQUMscUJBQ1AsRUFBRSxDQUNILENBQUM7Z0JBQ0YsTUFBTSxNQUFNLEdBQUcsTUFBTSxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQzFDLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUM1RCxJQUFJLENBQUMsVUFBVSxFQUNmLElBQUksQ0FBQyxxQkFBcUIsQ0FDM0IsQ0FBQztnQkFDRixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FDZiwrQ0FBK0MsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQzVFLENBQUM7Z0JBQ0YsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsU0FBUyxHQUFHLEtBQWMsQ0FBQztnQkFDM0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ2QsNENBQTRDLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQy9GLENBQUM7Z0JBQ0YsSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQzVELElBQUksQ0FBQyxVQUFVLEVBQ2YsSUFBSSxDQUFDLHFCQUFxQixFQUMxQixTQUFTLENBQ1YsQ0FBQztnQkFDRixRQUFRLEVBQUUsQ0FBQztZQUNiLENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxTQUFTLElBQUksSUFBSSxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksV0FBVyxDQUNoQixRQUFxRDtRQUVyRCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1FBQzdELElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsZ0JBQWdCLEdBQUcsS0FBSyxFQUFFLE1BQWMsRUFBa0IsRUFBRTtRQUMxRCxPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQzVDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FDbkMsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGOzs7T0FHRztJQUNILGdCQUFnQixHQUFHLEtBQUssSUFBcUIsRUFBRTtRQUM3QyxPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQzVDLFNBQVMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUM3QixDQUFDO0lBQ0osQ0FBQyxDQUFDO0lBRUY7Ozs7O09BS0c7SUFDSCxXQUFXLEdBQUcsS0FBSyxFQUNqQixTQUFpQixFQUNqQixNQUFjLEVBQ21CLEVBQUU7UUFDbkMsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUM1QyxTQUFTLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FDekMsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUVGOzs7T0FHRztJQUNJLGlCQUFpQjtRQUN0QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQztRQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN2RCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7O09BR0c7SUFDSSxlQUFlLENBQUMsS0FBYTtRQUNsQyxJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakQsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQywrQkFBK0IsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN6RCxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDakMsSUFBSSxJQUFJLENBQUMscUJBQXFCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUN6RCxJQUFJLENBQUMscUJBQXFCLEdBQUcsQ0FBQyxDQUFDO1FBQ2pDLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBYnN0cmFjdExvZ2dlciwgRHVtbXlMb2dnZXIgfSBmcm9tICdAcm9zZW4tYnJpZGdlL2Fic3RyYWN0LWxvZ2dlcic7XG5pbXBvcnQge1xuICBBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3IsXG4gIEJsb2NrLFxufSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5cbmltcG9ydCB7XG4gIENvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWd5LFxuICBGYWlsb3ZlclN0cmF0ZWd5LFxufSBmcm9tICcuL2Nvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWdpZXMnO1xuXG4vKipcbiAqIE5ldHdvcmsgY29ubmVjdG9yIG1hbmFnZXIgdGhhdCBjYW4gaGFuZGxlIG11bHRpcGxlIGNvbm5lY3RvcnNcbiAqIGZvciBhIHNpbmdsZSBuZXR3b3JrIHdpdGggcGx1Z2dhYmxlIHNlbGVjdGlvbiBzdHJhdGVneVxuICovXG5leHBvcnQgY2xhc3MgTmV0d29ya0Nvbm5lY3Rvck1hbmFnZXI8VHJhbnNhY3Rpb25UeXBlPlxuICBpbXBsZW1lbnRzIEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvcjxUcmFuc2FjdGlvblR5cGU+XG57XG4gIHByaXZhdGUgY29ubmVjdG9yczogQXJyYXk8QWJzdHJhY3ROZXR3b3JrQ29ubmVjdG9yPFRyYW5zYWN0aW9uVHlwZT4+O1xuICBwcml2YXRlIGN1cnJlbnRDb25uZWN0b3JJbmRleDogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc3RyYXRlZ3k6IENvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWd5PFRyYW5zYWN0aW9uVHlwZT4gPSBuZXcgRmFpbG92ZXJTdHJhdGVneTxUcmFuc2FjdGlvblR5cGU+KCksXG4gICAgcHJpdmF0ZSBsb2dnZXI6IEFic3RyYWN0TG9nZ2VyID0gbmV3IER1bW15TG9nZ2VyKCksXG4gICkge1xuICAgIHRoaXMuY29ubmVjdG9ycyA9IFtdO1xuICAgIHRoaXMuY3VycmVudENvbm5lY3RvckluZGV4ID0gMDtcbiAgICB0aGlzLnN0cmF0ZWd5ID0gc3RyYXRlZ3k7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoJ05ldHdvcmtDb25uZWN0b3JNYW5hZ2VyIGluaXRpYWxpemVkJyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbmV3IGNvbm5lY3RvciB0byB0aGUgbWFuYWdlclxuICAgKiBAcGFyYW0gY29ubmVjdG9yIFRoZSBuZXR3b3JrIGNvbm5lY3RvciBpbnN0YW5jZVxuICAgKi9cbiAgcHVibGljIGFkZENvbm5lY3RvcihcbiAgICBjb25uZWN0b3I6IEFic3RyYWN0TmV0d29ya0Nvbm5lY3RvcjxUcmFuc2FjdGlvblR5cGU+LFxuICApOiB2b2lkIHtcbiAgICB0aGlzLmNvbm5lY3RvcnMucHVzaChjb25uZWN0b3IpO1xuICAgIHRoaXMubG9nZ2VyLmluZm8oXG4gICAgICBgQWRkZWQgbmV3IGNvbm5lY3Rvci4gVG90YWwgY29ubmVjdG9yczogJHt0aGlzLmNvbm5lY3RvcnMubGVuZ3RofWAsXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgYWN0aXZlIGNvbm5lY3RvclxuICAgKiBAcmV0dXJucyBUaGUgY3VycmVudCBuZXR3b3JrIGNvbm5lY3RvciBpbnN0YW5jZVxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vIGNvbm5lY3RvcnMgYXJlIGF2YWlsYWJsZVxuICAgKi9cbiAgZ2V0Q3VycmVudENvbm5lY3RvcigpOiBBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3I8VHJhbnNhY3Rpb25UeXBlPiB7XG4gICAgaWYgKHRoaXMuY29ubmVjdG9ycy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gY29ubmVjdG9ycyBhdmFpbGFibGUnKTtcbiAgICB9XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoYFVzaW5nIGNvbm5lY3RvciBhdCBpbmRleCAke3RoaXMuY3VycmVudENvbm5lY3RvckluZGV4fWApO1xuICAgIHJldHVybiB0aGlzLmNvbm5lY3RvcnNbdGhpcy5jdXJyZW50Q29ubmVjdG9ySW5kZXhdO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgYW4gb3BlcmF0aW9uIHVzaW5nIHRoZSBjb25maWd1cmVkIHN0cmF0ZWd5XG4gICAqIEBwYXJhbSBvcGVyYXRpb24gVGhlIG9wZXJhdGlvbiB0byBleGVjdXRlXG4gICAqIEByZXR1cm5zIFRoZSByZXN1bHQgb2YgdGhlIG9wZXJhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlV2l0aFN0cmF0ZWd5PFQ+KFxuICAgIG9wZXJhdGlvbjogKFxuICAgICAgY29ubmVjdG9yOiBBYnN0cmFjdE5ldHdvcmtDb25uZWN0b3I8VHJhbnNhY3Rpb25UeXBlPixcbiAgICApID0+IFByb21pc2U8VD4sXG4gICk6IFByb21pc2U8VD4ge1xuICAgIGlmICh0aGlzLmNvbm5lY3RvcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGNvbm5lY3RvcnMgYXZhaWxhYmxlIGZvciBvcGVyYXRpb24nKTtcbiAgICB9XG5cbiAgICBsZXQgbGFzdEVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICBsZXQgYXR0ZW1wdHMgPSAwO1xuICAgIGNvbnN0IG1heEF0dGVtcHRzID0gdGhpcy5jb25uZWN0b3JzLmxlbmd0aDtcblxuICAgIHdoaWxlIChhdHRlbXB0cyA8IG1heEF0dGVtcHRzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb25uZWN0b3IgPSB0aGlzLmNvbm5lY3RvcnNbdGhpcy5jdXJyZW50Q29ubmVjdG9ySW5kZXhdO1xuICAgICAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICBgQXR0ZW1wdCAke2F0dGVtcHRzICsgMX0vJHttYXhBdHRlbXB0c30gd2l0aCBjb25uZWN0b3IgYXQgaW5kZXggJHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudENvbm5lY3RvckluZGV4XG4gICAgICAgICAgfWAsXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG9wZXJhdGlvbihjb25uZWN0b3IpO1xuICAgICAgICB0aGlzLmN1cnJlbnRDb25uZWN0b3JJbmRleCA9IHRoaXMuc3RyYXRlZ3kuc2VsZWN0TmV4dENvbm5lY3RvcihcbiAgICAgICAgICB0aGlzLmNvbm5lY3RvcnMsXG4gICAgICAgICAgdGhpcy5jdXJyZW50Q29ubmVjdG9ySW5kZXgsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFxuICAgICAgICAgIGBPcGVyYXRpb24gc3VjY2Vzc2Z1bCwgbmV4dCBjb25uZWN0b3IgaW5kZXg6ICR7dGhpcy5jdXJyZW50Q29ubmVjdG9ySW5kZXh9YCxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxhc3RFcnJvciA9IGVycm9yIGFzIEVycm9yO1xuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxuICAgICAgICAgIGBPcGVyYXRpb24gZmFpbGVkIHdpdGggY29ubmVjdG9yIGF0IGluZGV4ICR7dGhpcy5jdXJyZW50Q29ubmVjdG9ySW5kZXh9OiAke2xhc3RFcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuY3VycmVudENvbm5lY3RvckluZGV4ID0gdGhpcy5zdHJhdGVneS5zZWxlY3ROZXh0Q29ubmVjdG9yKFxuICAgICAgICAgIHRoaXMuY29ubmVjdG9ycyxcbiAgICAgICAgICB0aGlzLmN1cnJlbnRDb25uZWN0b3JJbmRleCxcbiAgICAgICAgICBsYXN0RXJyb3IsXG4gICAgICAgICk7XG4gICAgICAgIGF0dGVtcHRzKys7XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IGxhc3RFcnJvciB8fCBuZXcgRXJyb3IoJ0FsbCBjb25uZWN0b3JzIGZhaWxlZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgc3RyYXRlZ3kgdG8gdXNlIGZvciBjb25uZWN0b3Igc2VsZWN0aW9uXG4gICAqIEBwYXJhbSBzdHJhdGVneSBUaGUgc3RyYXRlZ3kgdG8gdXNlXG4gICAqL1xuICBwdWJsaWMgc2V0U3RyYXRlZ3koXG4gICAgc3RyYXRlZ3k6IENvbm5lY3RvclNlbGVjdGlvblN0cmF0ZWd5PFRyYW5zYWN0aW9uVHlwZT4sXG4gICk6IHZvaWQge1xuICAgIHRoaXMubG9nZ2VyLmluZm8oJ1NldHRpbmcgbmV3IGNvbm5lY3RvciBzZWxlY3Rpb24gc3RyYXRlZ3knKTtcbiAgICB0aGlzLnN0cmF0ZWd5ID0gc3RyYXRlZ3k7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgYmxvY2sgYXQgYSBzcGVjaWZpYyBoZWlnaHRcbiAgICogQHBhcmFtIGhlaWdodCBUaGUgaGVpZ2h0IG9mIHRoZSBibG9jayB0byBnZXRcbiAgICogQHJldHVybnMgVGhlIGJsb2NrIGF0IHRoZSBzcGVjaWZpZWQgaGVpZ2h0XG4gICAqL1xuICBnZXRCbG9ja0F0SGVpZ2h0ID0gYXN5bmMgKGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxCbG9jaz4gPT4ge1xuICAgIHJldHVybiB0aGlzLmV4ZWN1dGVXaXRoU3RyYXRlZ3koKGNvbm5lY3RvcikgPT5cbiAgICAgIGNvbm5lY3Rvci5nZXRCbG9ja0F0SGVpZ2h0KGhlaWdodCksXG4gICAgKTtcbiAgfTtcblxuICAvKipcbiAgICogR2V0IHRoZSBjdXJyZW50IGhlaWdodCBvZiB0aGUgYmxvY2tjaGFpblxuICAgKiBAcmV0dXJucyBUaGUgY3VycmVudCBoZWlnaHRcbiAgICovXG4gIGdldEN1cnJlbnRIZWlnaHQgPSBhc3luYyAoKTogUHJvbWlzZTxudW1iZXI+ID0+IHtcbiAgICByZXR1cm4gdGhpcy5leGVjdXRlV2l0aFN0cmF0ZWd5KChjb25uZWN0b3IpID0+XG4gICAgICBjb25uZWN0b3IuZ2V0Q3VycmVudEhlaWdodCgpLFxuICAgICk7XG4gIH07XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgdHJhbnNhY3Rpb25zIGluIGEgYmxvY2tcbiAgICogQHBhcmFtIGJsb2NrSGFzaCBUaGUgaGFzaCBvZiB0aGUgYmxvY2sgdG8gZ2V0IHRyYW5zYWN0aW9ucyBmcm9tXG4gICAqIEBwYXJhbSBoZWlnaHQgVGhlIGhlaWdodCBvZiB0aGUgYmxvY2sgdG8gZ2V0IHRyYW5zYWN0aW9ucyBmcm9tXG4gICAqIEByZXR1cm5zIEFycmF5IG9mIHRyYW5zYWN0aW9ucyBpbiB0aGUgYmxvY2tcbiAgICovXG4gIGdldEJsb2NrVHhzID0gYXN5bmMgKFxuICAgIGJsb2NrSGFzaDogc3RyaW5nLFxuICAgIGhlaWdodDogbnVtYmVyLFxuICApOiBQcm9taXNlPEFycmF5PFRyYW5zYWN0aW9uVHlwZT4+ID0+IHtcbiAgICByZXR1cm4gdGhpcy5leGVjdXRlV2l0aFN0cmF0ZWd5KChjb25uZWN0b3IpID0+XG4gICAgICBjb25uZWN0b3IuZ2V0QmxvY2tUeHMoYmxvY2tIYXNoLCBoZWlnaHQpLFxuICAgICk7XG4gIH07XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbnVtYmVyIG9mIGF2YWlsYWJsZSBjb25uZWN0b3JzXG4gICAqIEByZXR1cm5zIFRoZSBudW1iZXIgb2YgY29ubmVjdG9yc1xuICAgKi9cbiAgcHVibGljIGdldENvbm5lY3RvckNvdW50KCk6IG51bWJlciB7XG4gICAgY29uc3QgY291bnQgPSB0aGlzLmNvbm5lY3RvcnMubGVuZ3RoO1xuICAgIHRoaXMubG9nZ2VyLmRlYnVnKGBDdXJyZW50IGNvbm5lY3RvciBjb3VudDogJHtjb3VudH1gKTtcbiAgICByZXR1cm4gY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGEgY29ubmVjdG9yIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXhcbiAgICogQHBhcmFtIGluZGV4IFRoZSBpbmRleCBvZiB0aGUgY29ubmVjdG9yIHRvIHJlbW92ZVxuICAgKi9cbiAgcHVibGljIHJlbW92ZUNvbm5lY3RvcihpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSB0aGlzLmNvbm5lY3RvcnMubGVuZ3RoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29ubmVjdG9yIGluZGV4Jyk7XG4gICAgfVxuICAgIHRoaXMubG9nZ2VyLmluZm8oYFJlbW92aW5nIGNvbm5lY3RvciBhdCBpbmRleCAke2luZGV4fWApO1xuICAgIHRoaXMuY29ubmVjdG9ycy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIGlmICh0aGlzLmN1cnJlbnRDb25uZWN0b3JJbmRleCA+PSB0aGlzLmNvbm5lY3RvcnMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmN1cnJlbnRDb25uZWN0b3JJbmRleCA9IDA7XG4gICAgfVxuICB9XG59XG4iXX0=
|