import { IncomingHttpHeaders } from 'http'; import url from 'url'; export function namespaceHash(namespace: string, hash: string) { return `${namespace}/${hash}`; } export function fname(lv: number) { return `f${lv}`; } export function connectFactor(...args: string[]) { return args.join('-'); } export function valueFactory(obj: url.URLSearchParams | IncomingHttpHeaders) { if (obj instanceof url.URLSearchParams) { return function (key: string) { return obj.get(key); }; } else { return function (key: string) { const value = obj[key]; if (Array.isArray(value)) { return value.join(','); } return value; }; } } export function getTime([s, ns]: [number, number]): number { return Math.floor(s * 1e3 + ns / 1e6); } const RE_START_IN_HEAD = //; export function cacheAddition(html: string, hash: string) { const additionHtml = html.replace( RE_START_IN_HEAD, ``, ); return additionHtml; } type CoalescedInvoke = { isOrigin: boolean; value: T; }; type UnwrapPromise = T extends Promise ? U : T; const globalInvokeCache = new Map>>(); export function withCoalescedInvoke Promise>( func: F, ): ( key: string, args: Parameters, ) => Promise>>> { return async function (key: string, args: Parameters) { const entry = globalInvokeCache.get(key); if (entry) { return entry.then(res => ({ isOrigin: false, value: res.value as UnwrapPromise>, })); } function __wrapper() { return func(...args); } const future = __wrapper() .then(res => { globalInvokeCache.delete(key); return { isOrigin: true, value: res as UnwrapPromise> }; }) .catch(err => { globalInvokeCache.delete(key); throw err; }); globalInvokeCache.set(key, future); return future; }; } export function maybeSync(fn: () => Promise) { return (sync: boolean) => { if (sync) { return fn(); } else { fn(); return Promise.resolve(); } }; }