(
method: string,
params: Record<string, unknown> = {},
timeout = CALL_TIMEOUT_MS,
)
| 112 | } |
| 113 | |
| 114 | async call<T = unknown>( |
| 115 | method: string, |
| 116 | params: Record<string, unknown> = {}, |
| 117 | timeout = CALL_TIMEOUT_MS, |
| 118 | ): Promise<T> { |
| 119 | await this.opened |
| 120 | const id = nextId() |
| 121 | const payload = JSON.stringify({ |
| 122 | jsonrpc: '2.0', |
| 123 | method, |
| 124 | params: { token: this.token, ...params }, |
| 125 | id, |
| 126 | }) |
| 127 | const queued = this.ws?.readyState !== WebSocket.OPEN |
| 128 | log(this.name, `→ ${method} ${queued ? '(queued)' : ''} ${payload.length}B`) |
| 129 | |
| 130 | return new Promise<T>((resolve, reject) => { |
| 131 | const timer = setTimeout(() => { |
| 132 | this.pending.delete(id) |
| 133 | warn(this.name, `× ${method} timeout ${timeout}ms`) |
| 134 | reject(new Error(`${method} 超时`)) |
| 135 | }, timeout) |
| 136 | this.pending.set(id, { |
| 137 | method, |
| 138 | sentAt: performance.now(), |
| 139 | resolve: resolve as (v: unknown) => void, |
| 140 | reject, |
| 141 | timer, |
| 142 | }) |
| 143 | if (queued) this.outbox.push(payload) |
| 144 | else this.ws!.send(payload) |
| 145 | }) |
| 146 | } |
| 147 | |
| 148 | close() { |
| 149 | this.closed = true |
no test coverage detected