Skip to content

Commit 2f54e02

Browse files
committed
v7.4.1: fix race conditions
1 parent 19aff6d commit 2f54e02

File tree

13 files changed

+756
-592
lines changed

13 files changed

+756
-592
lines changed

dist/esm/index.evm.js

Lines changed: 82 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -130,44 +130,32 @@ const sortPriorities = (priorities, a,b)=>{
130130
return 0
131131
};
132132

133+
const promiseWithTimeout = (promise, timeout = 10000) => {
134+
return Promise.race([
135+
promise,
136+
new Promise((resolve) => setTimeout(() => resolve(null), timeout)) // Resolve with null on timeout
137+
]);
138+
};
139+
133140
var dripAssets = async (options) => {
134141
if(options === undefined) { options = { accounts: {}, priority: [] }; }
135142

136143
let assets = [];
137144
let dripped = [];
138145
let promises = [];
139-
let priorities = _optionalChain([options, 'optionalAccess', _ => _.priority, 'optionalAccess', _2 => _2.map, 'call', _3 => _3((priority)=>[priority.blockchain, priority.address.toLowerCase()].join(''))]);
140-
let drippedIndex = 0;
141-
let dripQueue = [];
146+
let priorities = Array.isArray(options.priority) ? options.priority.map(priority => [priority.blockchain, priority.address.toLowerCase()].join('')) : [];
142147

143-
const drip = (asset, recursive = true)=>{
144-
if(typeof options.drip !== 'function') { return }
148+
const drip = (asset)=>{
149+
if (!asset || typeof options.drip !== 'function') { return } // Ensure asset is valid
145150
const assetAsKey = [asset.blockchain, asset.address.toLowerCase()].join('');
146151
if(dripped.indexOf(assetAsKey) > -1) { return }
147-
if(priorities && priorities.length && priorities.indexOf(assetAsKey) === drippedIndex) {
148-
dripped.push(assetAsKey);
149-
options.drip(asset);
150-
drippedIndex += 1;
151-
if(!recursive){ return }
152-
dripQueue.forEach((asset)=>drip(asset, false));
153-
} else if(!priorities || priorities.length === 0 || drippedIndex >= priorities.length) {
154-
if(!priorities || priorities.length === 0 || priorities.indexOf(assetAsKey) === -1) {
155-
dripped.push(assetAsKey);
156-
options.drip(asset);
157-
} else if (drippedIndex >= priorities.length) {
158-
dripped.push(assetAsKey);
159-
options.drip(asset);
160-
}
161-
} else if(!dripQueue.find((queued)=>queued.blockchain === asset.blockchain && queued.address.toLowerCase() === asset.address.toLowerCase())) {
162-
dripQueue.push(asset);
163-
dripQueue.sort((a,b)=>sortPriorities(priorities, a, b));
164-
}
152+
dripped.push(assetAsKey);
153+
options.drip(asset);
165154
};
166155

167156
// Prioritized Assets
168-
169157
promises = promises.concat((options.priority || []).map((asset)=>{
170-
return new Promise(async (resolve, reject)=>{
158+
return promiseWithTimeout(new Promise(async (resolve) => {
171159
try {
172160
let token = new Token(asset);
173161
let completedAsset = Object.assign({},
@@ -181,85 +169,105 @@ var dripAssets = async (options) => {
181169
}
182170
);
183171
if(completedAsset.balance != '0') {
184-
if(exists({ assets, asset })) { return resolve() }
172+
if(exists({ assets, asset })) { return resolve(null) } // Resolve with null if already exists
185173
assets.push(completedAsset);
186-
drip(completedAsset);
187174
resolve(completedAsset);
188175
} else {
189-
resolve();
176+
resolve(null);
190177
}
191-
} catch (e) {
192-
resolve();
178+
} catch (error) {
179+
console.error('Error fetching prioritized asset:', asset, error);
180+
resolve(null); // Resolve with null to prevent blocking
193181
}
194-
})
182+
}))
195183
}));
196-
Promise.all(promises).then(()=>{
197-
drippedIndex = _optionalChain([priorities, 'optionalAccess', _4 => _4.length]) || 0;
198-
dripQueue.forEach((asset)=>drip(asset, false));
199-
});
200-
184+
201185
// Major Tokens
202-
203186
let majorTokens = [];
204187
for (var blockchain in options.accounts){
205188
Blockchains.findByName(blockchain).tokens.forEach((token)=>{
206189
if(isFiltered({ options, address: token.address, blockchain })){ return }
207-
if(_optionalChain([options, 'optionalAccess', _5 => _5.priority, 'optionalAccess', _6 => _6.find, 'call', _7 => _7((priority)=>priority.blockchain === blockchain && priority.address.toLowerCase() === token.address.toLowerCase())])){ return }
190+
if(_optionalChain([options, 'optionalAccess', _ => _.priority, 'optionalAccess', _2 => _2.find, 'call', _3 => _3((priority)=>priority.blockchain === blockchain && priority.address.toLowerCase() === token.address.toLowerCase())])){ return }
208191
majorTokens.push(Object.assign({}, token, { blockchain }));
209192
});
210193
}
194+
211195
promises = promises.concat((majorTokens.map((asset)=>{
212-
return new Promise((resolve, reject)=>{
196+
return promiseWithTimeout(new Promise((resolve) => {
213197
new Token(asset).balance(options.accounts[asset.blockchain])
214198
.then((balance)=>{
215-
if(exists({ assets, asset })) { return resolve() }
199+
if(exists({ assets, asset })) { return resolve(null) } // Resolve with null if already exists
216200
const assetWithBalance = reduceAssetWithBalance(asset, balance);
217201
if(assetWithBalance.balance != '0') {
218202
assets.push(assetWithBalance);
219-
drip(assetWithBalance);
220203
resolve(assetWithBalance);
221204
} else {
222-
resolve();
223-
}}).catch(()=>{ resolve(); });
224-
})
205+
resolve(null);
206+
}}).catch((error)=>{
207+
console.error('Error fetching major token balance:', asset, error);
208+
resolve(null); // Resolve with null on error
209+
});
210+
}))
225211
})));
226212

227213
// All other assets
228-
229214
if(options.only == undefined || Object.keys(options.only).every((list)=>list.length == 0)) {
230-
let allAssets = await getAssets(options);
231-
promises = promises.concat((allAssets.map((asset)=>{
232-
return new Promise((resolve, reject)=>{
233-
const token = new Token(asset);
234-
return token.balance(options.accounts[asset.blockchain])
235-
.then(async(balance)=>{
236-
if(exists({ assets, asset })) { return resolve() }
237-
const assetWithBalance = reduceAssetWithBalance(asset, balance);
238-
if(assetWithBalance.balance != '0') {
239-
if(assetWithBalance.name === undefined) {
240-
assetWithBalance.name = await token.name();
241-
}
242-
if(assetWithBalance.symbol === undefined) {
243-
assetWithBalance.symbol = await token.symbol();
244-
}
245-
if(assetWithBalance.decimals === undefined) {
246-
assetWithBalance.decimals = await token.decimals();
247-
}
248-
assets.push(assetWithBalance);
249-
drip(assetWithBalance);
250-
resolve(assetWithBalance);
251-
} else {
252-
resolve();
253-
}}).catch(()=>{ resolve(); })
254-
})
255-
})));
215+
try {
216+
let allAssets = await getAssets(options);
217+
promises = promises.concat((allAssets.map((asset)=>{
218+
return promiseWithTimeout(new Promise((resolve) => {
219+
const token = new Token(asset);
220+
return token.balance(options.accounts[asset.blockchain])
221+
.then(async(balance)=>{
222+
if(exists({ assets, asset })) { return resolve(null) } // Resolve with null if already exists
223+
const assetWithBalance = reduceAssetWithBalance(asset, balance);
224+
if(assetWithBalance.balance != '0') {
225+
if(assetWithBalance.name === undefined) {
226+
assetWithBalance.name = await token.name();
227+
}
228+
if(assetWithBalance.symbol === undefined) {
229+
assetWithBalance.symbol = await token.symbol();
230+
}
231+
if(assetWithBalance.decimals === undefined) {
232+
assetWithBalance.decimals = await token.decimals();
233+
}
234+
assets.push(assetWithBalance);
235+
resolve(assetWithBalance);
236+
} else {
237+
resolve(null);
238+
}}).catch((error)=>{
239+
console.error('Error fetching asset balance:', asset, error);
240+
resolve(null); // Resolve with null on error
241+
})
242+
}))
243+
})));
244+
} catch (error) {
245+
console.error('Error fetching all assets:', error);
246+
}
256247
}
257248

258-
await Promise.all(promises);
249+
// Ensure all promises are resolved
250+
const resolvedAssets = await Promise.all(promises);
259251

260-
assets.sort((a,b)=>sortPriorities(priorities, a, b));
252+
// Drip prioritized assets first in their defined order
253+
priorities.forEach(priorityKey => {
254+
const asset = resolvedAssets.find(a => a && [a.blockchain, a.address.toLowerCase()].join('') === priorityKey); // Ensure valid asset
255+
if (asset) {
256+
drip(asset);
257+
}
258+
});
259+
260+
// Drip non-prioritized assets
261+
resolvedAssets.forEach(asset => {
262+
if (!asset) return // Ensure valid asset
263+
const assetKey = [asset.blockchain, asset.address.toLowerCase()].join('');
264+
if (!priorities.includes(assetKey)) {
265+
drip(asset);
266+
}
267+
});
261268

262-
dripQueue.forEach((asset)=>drip(asset, false));
269+
// Sort assets based on priorities before returning
270+
assets.sort((a,b)=>sortPriorities(priorities, a, b));
263271

264272
return assets
265273
};

0 commit comments

Comments
 (0)