This repository has been archived by the owner on Feb 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.ts
80 lines (72 loc) · 2.08 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { pLimit } from "https://deno.land/x/p_limit@v1.0.0/mod.ts";
import { Arg } from "./types.ts";
import { Lock } from "https://deno.land/x/async@v1.2.0/mod.ts";
/**
* identity returns the same value as it receives.
*/
export const identity = <T>(val: T): T => {
return val;
};
/**
* withConcurrency returns a wrapped function using the specified concurrency as a limiter.
*/
export const withConcurrency = <TArgs extends Arg = Arg, TResult = unknown>(
concurrency: number,
f: (...args: [...TArgs]) => TResult,
): (...args: [...TArgs]) => Promise<TResult> => {
const limiter = pLimit(concurrency);
return (...args) => {
return limiter(() => f(...args));
};
};
/**
* safeApply applies the given function to the parameter in case of the parameter is not undefined.
*/
export const tryApply =
<T, U>(f: (v: T) => U) => (v: T | undefined): U | undefined => {
return v !== undefined ? f(v) : undefined;
};
/**
* parses the given integer if not undefined.
*/
export const tryParseInt = tryApply(parseInt);
export const tryParseBool = tryApply((v) => v === "true");
export const apply = <T, TResult>(param: T) => (f: (p: T) => TResult) => {
return f(param);
};
interface SingleFlight<T> {
do: (key: string, f: () => Promise<T>) => Promise<T>;
}
export const singleFlight = <T>(): SingleFlight<T> => {
const mu = new Lock();
const active: Record<string, Promise<T>> = {};
return {
do: async (key: string, f: () => Promise<T>) => {
let promise = active[key];
if (promise !== undefined) {
return promise;
}
await mu.acquire();
promise = active[key];
if (promise !== undefined) {
mu.release();
return promise;
}
promise = f();
active[key] = promise.finally(async () => {
await mu.acquire();
delete active[key];
mu.release();
});
mu.release();
return promise;
},
};
};
export const setIntervalFlight = (
f: () => Promise<void>,
interval: number,
): number => {
const sf = singleFlight();
return setInterval(() => sf.do("single", f), interval);
};