Skip to content

Commit

Permalink
Add: glob in fetch delay (#361)
Browse files Browse the repository at this point in the history
* Add: glob in fetch delay

* Fix: escape special chars

* Update readme

* Update readme

* Update readme
  • Loading branch information
eight04 authored Nov 19, 2024
1 parent 3272660 commit 02deb22
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@ http://example.com 10
- The origin of the image.
- The delay (in seconds).

After v0.19.0, you can use wildcard in the origin. This also allows you to set a default delay for all images. For example, set a default delay to 10s and 5s for imgur:

```
https://*.imgur.com 5
* 10
```

Note that rules are applied from top to bottom. The first matched rule will be used.

Retry on failure
----------------

Expand Down
32 changes: 23 additions & 9 deletions src/lib/fetch-delay.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,48 @@ pref.ready().then(() => {
});

const lock = createLockPool({maxActiveReader: 3});
let meta = new Map;
let rules = [];

function update() {
const newMeta = new Map;
const newRules = [];
for (const lines of parseText(pref.get('fetchDelay'))) {
const [origin, delay] = lines[0].trim().split(/\s+/);
const delayMs = Number(delay) * 1000;
newMeta.set(origin, {
...meta.get(origin),
const oldRule = rules.find(rule => rule.origin === origin);
newRules.push({
...oldRule,
origin,
delayMs
});
}
meta = newMeta;
rules = newRules;
}

function matchGlob(pattern, string) {
if (!pattern.includes("*")) {
return pattern === string;
}
// compile a glob pattern to a regular expression, also escape special characters
const rx = new RegExp(`^${pattern.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&").replace(/\*/g, ".*")}$`);
return rx.test(string);
}

export async function fetchDelay(url, cb) {
const origin = new URL(url).origin;
if (meta.has(origin)) {
return await lock.write([origin], async () => {
const t = (meta.get(origin).lastFetch || 0) + meta.get(origin).delayMs - Date.now();
const rule = rules.find(rule => matchGlob(rule.origin, origin));
// calculate the delay if there is a matching rule
if (rule) {
return await lock.write([rule.origin], async () => {
const t = (rule.lastFetch || 0) + rule.delayMs - Date.now();
await delay(t > 0 ? t : 0);
try {
return await cb();
} finally {
meta.get(origin).lastFetch = Date.now();
rule.lastFetch = Date.now();
}
});
}
// no matching rule, just fetch, still restricted by the maxActiveReader
return await lock.read([origin], cb);
}

Expand Down

0 comments on commit 02deb22

Please sign in to comment.