Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | 5x 5x 13x 1100x 1100x 1100x 1100x 1100x 430x 430x 430x 430x 430x 413x 154x 154x 154x 154x 426x 4x 422x 422x 422x 435x 5x 430x 430x 430x 430x 414x 417x 417x 11x 406x 406x 406x 95x 88x 7x 5x 7x 93x 1x 92x 92x 4x 92x 137x 1x 136x 136x 136x 4x 136x 2x | import type { SessionResponse } from '@ydbjs/api/coordination'
export type Deferred<T> = {
promise: Promise<T>
resolve(value: T | PromiseLike<T>): void
reject(reason?: unknown): void
}
export class SessionReconnectError extends Error {
constructor() {
super('Session reconnecting')
this.name = 'SessionReconnectError'
}
}
export let createDeferred = function createDeferred<T>(): Deferred<T> {
let resolve!: (value: T | PromiseLike<T>) => void
let reject!: (reason?: unknown) => void
let promise = new Promise<T>((res, rej) => {
resolve = res
reject = rej
})
// Prevent UnhandledPromiseRejection when rejected before anyone awaits.
promise.catch(() => {})
return { promise, resolve, reject }
}
export class PendingRequest implements Disposable {
#registry: SessionRequestRegistry
#reqId: bigint
promise: Promise<SessionResponse>
resolve: (value: SessionResponse | PromiseLike<SessionResponse>) => void
reject: (reason?: unknown) => void
constructor(
registry: SessionRequestRegistry,
reqId: bigint,
deferred: Deferred<SessionResponse>
) {
this.#registry = registry
this.#reqId = reqId
this.promise = deferred.promise
this.resolve = deferred.resolve
this.reject = deferred.reject
}
[Symbol.dispose](): void {
this.#registry.delete(this.#reqId)
}
}
export class SessionRequestRegistry implements Disposable {
#nextReqId = 1n
#closed = false
#destroyed = false
#pending = new Map<bigint, PendingRequest>()
nextReqId(): bigint {
if (this.#closed || this.#destroyed) {
throw new Error('Session request registry is closed')
}
let reqId = this.#nextReqId
this.#nextReqId += 1n
return reqId
}
register(reqId: bigint): PendingRequest {
if (this.#closed || this.#destroyed) {
throw new Error('Session request registry is closed')
}
let deferred = createDeferred<SessionResponse>()
let pending = new PendingRequest(this, reqId, deferred)
this.#pending.set(reqId, pending)
return pending
}
delete(reqId: bigint): void {
this.#pending.delete(reqId)
}
resolve(reqId: bigint, response: SessionResponse): boolean {
let pending = this.#pending.get(reqId)
if (!pending) {
return false
}
this.#pending.delete(reqId)
pending.resolve(response)
return true
}
reconnect(): void {
if (this.#closed || this.#destroyed) {
return
}
for (let [, pending] of this.#pending) {
pending.reject(new SessionReconnectError())
}
this.#pending.clear()
}
close(): void {
if (this.#closed || this.#destroyed) {
return
}
this.#closed = true
for (let [, pending] of this.#pending) {
pending.reject(new Error('Session closed'))
}
this.#pending.clear()
}
destroy(reason: unknown): void {
if (this.#destroyed) {
return
}
this.#destroyed = true
this.#closed = true
for (let [, pending] of this.#pending) {
pending.reject(reason)
}
this.#pending.clear()
}
[Symbol.dispose](): void {
this.destroy(new Error('Session request registry disposed'))
}
}
|