forgot a file
This commit is contained in:
parent
04ab14a066
commit
e0138c4164
|
|
@ -0,0 +1,111 @@
|
|||
import { Innertube } from 'youtubei.js'
|
||||
|
||||
interface InnertubePoolSlot {
|
||||
client: Promise<Innertube>
|
||||
busy?: boolean
|
||||
}
|
||||
|
||||
export interface InnertubeLease {
|
||||
innertube: Innertube
|
||||
refresh: () => Promise<Innertube>
|
||||
release: () => void
|
||||
}
|
||||
|
||||
export function createInnertubePool(size = 4) {
|
||||
const pool = Array.from({ length: Math.max(1, size) }, () => ({
|
||||
client: Innertube.create()
|
||||
})) as InnertubePoolSlot[]
|
||||
const waiters: Array<(lease: InnertubeLease) => void> = []
|
||||
|
||||
function getSlot(index: number) {
|
||||
const slot = pool[index]
|
||||
|
||||
if (!slot) {
|
||||
throw new Error(`Innertube slot ${index} not found`)
|
||||
}
|
||||
|
||||
return slot
|
||||
}
|
||||
|
||||
async function load(index: number) {
|
||||
const slot = getSlot(index)
|
||||
|
||||
try {
|
||||
return await slot.client
|
||||
} catch {
|
||||
slot.client = Innertube.create()
|
||||
return await slot.client
|
||||
}
|
||||
}
|
||||
|
||||
async function refresh(index: number) {
|
||||
const slot = getSlot(index)
|
||||
|
||||
slot.client = Innertube.create()
|
||||
return await slot.client
|
||||
}
|
||||
|
||||
function release(index: number) {
|
||||
const next = waiters.shift()
|
||||
|
||||
if (next) {
|
||||
void load(index).then((innertube) => next(createLease(index, innertube)))
|
||||
return
|
||||
}
|
||||
|
||||
delete getSlot(index).busy
|
||||
}
|
||||
|
||||
function createLease(index: number, innertube: Innertube): InnertubeLease {
|
||||
const lease: InnertubeLease = {
|
||||
innertube,
|
||||
refresh: async () => {
|
||||
lease.innertube = await refresh(index)
|
||||
return lease.innertube
|
||||
},
|
||||
release: () => release(index)
|
||||
}
|
||||
|
||||
return lease
|
||||
}
|
||||
|
||||
async function acquire() {
|
||||
const index = pool.findIndex((slot) => !slot.busy)
|
||||
|
||||
if (index === -1) {
|
||||
return await new Promise<InnertubeLease>((resolve) => {
|
||||
waiters.push(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
getSlot(index).busy = true
|
||||
return createLease(index, await load(index))
|
||||
}
|
||||
|
||||
async function use<T>(callback: (innertube: Innertube) => Promise<T>, retries = 5) {
|
||||
const lease = await acquire()
|
||||
|
||||
try {
|
||||
for (let attempt = 0; attempt < retries; attempt++) {
|
||||
try {
|
||||
return await callback(lease.innertube)
|
||||
} catch (error) {
|
||||
if (attempt === retries - 1) {
|
||||
throw error
|
||||
}
|
||||
|
||||
await lease.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Innertube retries exhausted')
|
||||
} finally {
|
||||
lease.release()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
acquire,
|
||||
use
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue