mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 09:49:24 +02:00
refactor(adb): add web streams fallback detection
This commit is contained in:
parent
6398ad86cd
commit
68774620c3
11 changed files with 335 additions and 189 deletions
23
common/config/rush/pnpm-lock.yaml
generated
23
common/config/rush/pnpm-lock.yaml
generated
|
@ -28,7 +28,7 @@ specifiers:
|
|||
'@types/bluebird': ^3.5.36
|
||||
'@types/dom-webcodecs': ^0.1.3
|
||||
'@types/jest': ^27.4.0
|
||||
'@types/node': ^16.11.19
|
||||
'@types/node': ^17.0.17
|
||||
'@types/react': 17.0.27
|
||||
'@types/w3c-web-usb': ^1.0.4
|
||||
'@yume-chan/async': ^2.1.4
|
||||
|
@ -87,7 +87,7 @@ dependencies:
|
|||
'@types/bluebird': 3.5.36
|
||||
'@types/dom-webcodecs': 0.1.3
|
||||
'@types/jest': 27.4.0
|
||||
'@types/node': 16.11.19
|
||||
'@types/node': 17.0.17
|
||||
'@types/react': 17.0.27
|
||||
'@types/w3c-web-usb': 1.0.5
|
||||
'@yume-chan/async': 2.1.4
|
||||
|
@ -3585,8 +3585,8 @@ packages:
|
|||
resolution: {integrity: sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw==}
|
||||
dev: false
|
||||
|
||||
/@types/node/16.11.19:
|
||||
resolution: {integrity: sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng==}
|
||||
/@types/node/17.0.17:
|
||||
resolution: {integrity: sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==}
|
||||
dev: false
|
||||
|
||||
/@types/normalize-package-data/2.4.1:
|
||||
|
@ -13094,10 +13094,11 @@ packages:
|
|||
dev: false
|
||||
|
||||
file:projects/adb.tgz:
|
||||
resolution: {integrity: sha512-ERJiC9hMtOFRZhGBqQ76HXFVsjsGHajyWrPoHqOrAW4LqTdHf8jJueqhzPt6e9asmTuxcOynqz4MzbYnahcTtA==, tarball: file:projects/adb.tgz}
|
||||
resolution: {integrity: sha512-g2UseeMAhatJMFHZFEzJLFPricrQdJeHKXH5KE9XBDIoNla+2aB5UlZRLC+a/WKIa+WBQBD6bWT/3Ydwm5iexA==, tarball: file:projects/adb.tgz}
|
||||
name: '@rush-temp/adb'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/node': 17.0.17
|
||||
'@yume-chan/async': 2.1.4
|
||||
jest: 26.6.3
|
||||
tslib: 2.3.1
|
||||
|
@ -13111,7 +13112,7 @@ packages:
|
|||
dev: false
|
||||
|
||||
file:projects/android-bin.tgz:
|
||||
resolution: {integrity: sha512-+POm1mf4P1s+NhgwA6IHN+GBBmc00lDi7k+geCc04ts836duRlnJfkIEeIIJmjQHVwDz36BONp8rCXAaX4U/fA==, tarball: file:projects/android-bin.tgz}
|
||||
resolution: {integrity: sha512-a9dJWWGGdirHzDz7FAQKrdIMTur0zWJyWro6kR95IiK0zgVEHiP/uTVBgSo1u2q/NnNSYDkSxAbc9/4iEK12Uw==, tarball: file:projects/android-bin.tgz}
|
||||
name: '@rush-temp/android-bin'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
|
@ -13136,7 +13137,7 @@ packages:
|
|||
dev: false
|
||||
|
||||
file:projects/demo.tgz_@mdx-js+react@1.6.22:
|
||||
resolution: {integrity: sha512-hFRRD46g/+PJxCxycluFpde7A7hQqkVN2zoy+kKd2/oF75IGYI93yxr8wPsLr2h5emhQD/QXxbR04O5fpItURQ==, tarball: file:projects/demo.tgz}
|
||||
resolution: {integrity: sha512-Np2YG0x2SP6d561O/JW305uxFsEbG59HfJrlEh/SoiZeB5S1prxUoYKbs3oVLEcnJ9RlzNpxDwqT4sBGIgu1sA==, tarball: file:projects/demo.tgz}
|
||||
id: file:projects/demo.tgz
|
||||
name: '@rush-temp/demo'
|
||||
version: 0.0.0
|
||||
|
@ -13217,13 +13218,13 @@ packages:
|
|||
dev: false
|
||||
|
||||
file:projects/struct.tgz:
|
||||
resolution: {integrity: sha512-wwxTo3944Sm1NwHmKgWLTp4cEdl/WF+ogy7vTu46xJfYZgzXUdI9lWPI9J3CpL34pGXnhIdRdRBmFlB8WWy1Hg==, tarball: file:projects/struct.tgz}
|
||||
resolution: {integrity: sha512-GIonPLiFxCzf5pJ2FJUexA7X6NsvDlfcBCwqgvXsUSFShEvEl6+zKmCtz0onmPAFhF5ac43boK4GgwDxL0T75w==, tarball: file:projects/struct.tgz}
|
||||
name: '@rush-temp/struct'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/bluebird': 3.5.36
|
||||
'@types/jest': 27.4.0
|
||||
'@types/node': 16.11.19
|
||||
'@types/node': 17.0.17
|
||||
bluebird: 3.7.2
|
||||
jest: 26.6.3
|
||||
tslib: 2.3.1
|
||||
|
@ -13237,12 +13238,12 @@ packages:
|
|||
dev: false
|
||||
|
||||
file:projects/ts-package-builder.tgz:
|
||||
resolution: {integrity: sha512-EKE72WCmD/Gkx/d5IU0i1BApSo+DjvxTn9WyWeiq8VkVYw9MyXceD4Zio6Cntm7z2QHhaGkLkuCWhC0/h9XkQg==, tarball: file:projects/ts-package-builder.tgz}
|
||||
resolution: {integrity: sha512-irxxnPRuP5NCXvjpjdAbU4eAwz0gMBP/OTxyv/iLrxeiUIE2BT9ES+4OGKcIVCUEGHx5QgDNQsT5g/YHtPtF6A==, tarball: file:projects/ts-package-builder.tgz}
|
||||
name: '@rush-temp/ts-package-builder'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/jest': 27.4.0
|
||||
'@types/node': 16.11.19
|
||||
'@types/node': 17.0.17
|
||||
json5: 2.2.0
|
||||
typescript: 4.5.5
|
||||
dev: false
|
||||
|
|
|
@ -38,8 +38,12 @@
|
|||
"tslib": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.17",
|
||||
"jest": "^26.6.3",
|
||||
"typescript": "^4.5.5",
|
||||
"@yume-chan/ts-package-builder": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^17.0.17"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { AutoDisposable } from '@yume-chan/event';
|
||||
import { AdbBackend } from '../backend';
|
||||
import { AdbCommand } from '../packet';
|
||||
import { AutoResetEvent, chunkArrayLike } from '../utils';
|
||||
import { CloseEventEmitter } from './close-event-emitter';
|
||||
import { DataEventEmitter } from './data-event-emitter';
|
||||
import { AutoResetEvent, chunkArrayLike, TransformStream, WritableStream, WritableStreamDefaultWriter } from '../utils';
|
||||
import { AdbPacketDispatcher } from './dispatcher';
|
||||
|
||||
export interface AdbSocketInfo {
|
||||
|
@ -28,6 +26,8 @@ export interface AdbSocketConstructionOptions {
|
|||
localCreated: boolean;
|
||||
|
||||
serviceString: string;
|
||||
|
||||
highWaterMark?: number | undefined;
|
||||
}
|
||||
|
||||
export class AdbSocketController extends AutoDisposable implements AdbSocketInfo {
|
||||
|
@ -42,17 +42,40 @@ export class AdbSocketController extends AutoDisposable implements AdbSocketInfo
|
|||
public readonly localCreated!: boolean;
|
||||
public readonly serviceString!: string;
|
||||
|
||||
public readonly dataEvent = this.addDisposable(new DataEventEmitter<ArrayBuffer>());
|
||||
private readonly _transform: TransformStream<ArrayBuffer, ArrayBuffer>;
|
||||
private readonly _transformWriter: WritableStreamDefaultWriter<ArrayBuffer>;
|
||||
public get readable() { return this._transform.readable; }
|
||||
|
||||
public readonly writable: WritableStream<ArrayBuffer>;
|
||||
|
||||
private _closed = false;
|
||||
public get closed() { return this._closed; }
|
||||
|
||||
private readonly closeEvent = this.addDisposable(new CloseEventEmitter());
|
||||
public get onClose() { return this.closeEvent.event; }
|
||||
|
||||
public constructor(options: AdbSocketConstructionOptions) {
|
||||
super();
|
||||
Object.assign(this, options);
|
||||
|
||||
this._transform = new TransformStream({}, {
|
||||
highWaterMark: options.highWaterMark ?? 16 * 1024,
|
||||
size(chunk) { return chunk.byteLength; }
|
||||
});
|
||||
this._transformWriter = this._transform.writable.getWriter();
|
||||
|
||||
this.writable = new WritableStream({
|
||||
write: (chunk) => {
|
||||
return this.write(chunk);
|
||||
},
|
||||
close: () => {
|
||||
this.close();
|
||||
},
|
||||
}, {
|
||||
highWaterMark: options.highWaterMark ?? 16 * 1024,
|
||||
size(chunk) { return chunk.byteLength; }
|
||||
});
|
||||
}
|
||||
|
||||
public enqueue(packet: ArrayBuffer) {
|
||||
return this._transformWriter.write(packet);
|
||||
}
|
||||
|
||||
private async writeChunk(data: ArrayBuffer): Promise<void> {
|
||||
|
@ -88,18 +111,22 @@ export class AdbSocketController extends AutoDisposable implements AdbSocketInfo
|
|||
|
||||
public async close(): Promise<void> {
|
||||
if (!this._closed) {
|
||||
// prevent nested calls
|
||||
this._closed = true;
|
||||
|
||||
// Immediately cancel all pending writes
|
||||
this.writeLock.dispose();
|
||||
this.writeChunkLock.dispose();
|
||||
|
||||
await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
|
||||
this._closed = true;
|
||||
this._transform.writable.close();
|
||||
this.writable.close();
|
||||
}
|
||||
}
|
||||
|
||||
public override dispose() {
|
||||
this._closed = true;
|
||||
this.closeEvent.fire();
|
||||
this.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ReadableStream, WritableStream } from "../utils";
|
||||
import { AdbSocketController, AdbSocketInfo } from './controller';
|
||||
|
||||
export class AdbSocket implements AdbSocketInfo {
|
||||
|
@ -9,19 +10,13 @@ export class AdbSocket implements AdbSocketInfo {
|
|||
public get localCreated() { return this.controller.localCreated; }
|
||||
public get serviceString() { return this.controller.serviceString; }
|
||||
|
||||
public get closed() { return this.controller.closed; }
|
||||
|
||||
public get onData() { return this.controller.dataEvent.event; }
|
||||
public get onClose() { return this.controller.onClose; }
|
||||
public get readable(): ReadableStream<ArrayBuffer> { return this.controller.readable; }
|
||||
public get writable(): WritableStream<ArrayBuffer> { return this.controller.writable; }
|
||||
|
||||
public constructor(controller: AdbSocketController) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public write(data: ArrayBuffer): Promise<void> {
|
||||
return this.controller.write(data);
|
||||
}
|
||||
|
||||
public close(): Promise<void> {
|
||||
return this.controller.close();
|
||||
}
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
import { PromiseResolver } from '@yume-chan/async';
|
||||
import { EventEmitter } from '@yume-chan/event';
|
||||
|
||||
export interface EventQueueOptions {
|
||||
maxWaitCount: number;
|
||||
|
||||
highWaterMark: number;
|
||||
|
||||
lowWaterMark: number;
|
||||
}
|
||||
|
||||
export const EventQueueDefaultOptions: EventQueueOptions = {
|
||||
maxWaitCount: Infinity,
|
||||
highWaterMark: 10,
|
||||
lowWaterMark: 0,
|
||||
};
|
||||
|
||||
interface LinkedListItem<T> {
|
||||
value: T;
|
||||
|
||||
next?: LinkedListItem<T>;
|
||||
}
|
||||
|
||||
class LinkedList<T>{
|
||||
private head?: LinkedListItem<T> | undefined;
|
||||
|
||||
private tail?: LinkedListItem<T> | undefined;
|
||||
|
||||
private _length = 0;
|
||||
public get length() { return this._length; }
|
||||
|
||||
public push(value: T): void {
|
||||
const item: LinkedListItem<T> = { value };
|
||||
|
||||
if (this._length === 0) {
|
||||
this.head = item;
|
||||
} else {
|
||||
this.tail!.next = item;
|
||||
}
|
||||
|
||||
this._length += 1;
|
||||
this.tail = item;
|
||||
}
|
||||
|
||||
public shift(): T | undefined {
|
||||
if (this._length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { next, value } = this.head!;
|
||||
if (!next) {
|
||||
this.tail = undefined;
|
||||
}
|
||||
|
||||
this.head = next;
|
||||
this._length -= 1;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventQueueEndedError extends Error {
|
||||
public constructor() {
|
||||
super('Event queue ended');
|
||||
|
||||
// Fix Error's prototype chain when compiling to ES5
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basically an object-mode ReadableStream with Promise-based API
|
||||
*
|
||||
* It's called `EventQueue` because it usually converts events ("push system") to "pull system"
|
||||
*
|
||||
* https://github.com/nodejs/node/blob/master/lib/internal/streams/readable.js
|
||||
*/
|
||||
export class EventQueue<T> {
|
||||
// Use linked lists for faster shift operation.
|
||||
|
||||
/** Already buffered data ready to be served to consumers */
|
||||
private buffers = new LinkedList<[value: T, size: number]>();
|
||||
|
||||
/** Waiting consumers because lack of data */
|
||||
private awaiters = new LinkedList<PromiseResolver<T>>();
|
||||
|
||||
private options: EventQueueOptions;
|
||||
|
||||
private ended = false;
|
||||
|
||||
private _length = 0;
|
||||
public get length() { return this._length; }
|
||||
|
||||
private _needDrain = false;
|
||||
public get needDrain() { return this._needDrain; }
|
||||
|
||||
private readonly drainEvent = new EventEmitter<void>();
|
||||
public readonly onDrain = this.drainEvent.event;
|
||||
|
||||
public constructor(options?: Partial<EventQueueOptions>) {
|
||||
this.options = { ...EventQueueDefaultOptions, ...options };
|
||||
}
|
||||
|
||||
public enqueue(value: T, length = 1): boolean {
|
||||
if (this.ended) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.awaiters.length) {
|
||||
this.awaiters.shift()!.resolve(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.buffers.push([value, length]);
|
||||
this._length += length;
|
||||
if (this._length < this.options.highWaterMark) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this._needDrain = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public dequeue(): Promise<T> {
|
||||
if (this.buffers.length) {
|
||||
const [value, size] = this.buffers.shift()!;
|
||||
this._length -= size;
|
||||
if (this._needDrain &&
|
||||
this._length <= this.options.lowWaterMark) {
|
||||
this.drainEvent.fire();
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
|
||||
if (this.ended) {
|
||||
return Promise.reject(new EventQueueEndedError());
|
||||
}
|
||||
|
||||
if (this.awaiters.length === this.options.maxWaitCount - 1) {
|
||||
throw new Error('Max wait count exceeded');
|
||||
}
|
||||
|
||||
const resolver = new PromiseResolver<T>();
|
||||
this.awaiters.push(resolver);
|
||||
return resolver.promise;
|
||||
}
|
||||
|
||||
public end(): void {
|
||||
this.ended = true;
|
||||
let item: PromiseResolver<T> | undefined;
|
||||
while (item = this.awaiters.shift()) {
|
||||
item.reject(new Error('The EventQueue has already ended'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,4 +2,4 @@ export * from './auto-reset-event';
|
|||
export * from './base64';
|
||||
export * from './chunk';
|
||||
export * from './encoding';
|
||||
export * from './event-queue';
|
||||
export * from './stream';
|
||||
|
|
276
libraries/adb/src/utils/stream.ts
Normal file
276
libraries/adb/src/utils/stream.ts
Normal file
|
@ -0,0 +1,276 @@
|
|||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L1194-L1206
|
||||
export interface QueuingStrategy<T = any> {
|
||||
highWaterMark?: number;
|
||||
size?: QueuingStrategySize<T>;
|
||||
}
|
||||
|
||||
export interface QueuingStrategyInit {
|
||||
/**
|
||||
* Creates a new ByteLengthQueuingStrategy with the provided high water mark.
|
||||
*
|
||||
* Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting ByteLengthQueuingStrategy will cause the corresponding stream constructor to throw.
|
||||
*/
|
||||
highWaterMark: number;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L1450-L1468
|
||||
export interface ReadableStreamDefaultReadDoneResult {
|
||||
done: true;
|
||||
value?: undefined;
|
||||
}
|
||||
|
||||
export interface ReadableStreamDefaultReadValueResult<T> {
|
||||
done: false;
|
||||
value: T;
|
||||
}
|
||||
|
||||
export interface ReadableWritablePair<R = any, W = any> {
|
||||
readable: ReadableStream<R>;
|
||||
/**
|
||||
* Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use.
|
||||
*
|
||||
* Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
|
||||
*/
|
||||
writable: WritableStream<W>;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L1636
|
||||
export interface StreamPipeOptions {
|
||||
preventAbort?: boolean;
|
||||
preventCancel?: boolean;
|
||||
/**
|
||||
* Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered.
|
||||
*
|
||||
* Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
|
||||
*
|
||||
* Errors and closures of the source and destination streams propagate as follows:
|
||||
*
|
||||
* An error in this source readable stream will abort destination, unless preventAbort is truthy. The returned promise will be rejected with the source's error, or with any error that occurs during aborting the destination.
|
||||
*
|
||||
* An error in destination will cancel this source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination's error, or with any error that occurs during canceling the source.
|
||||
*
|
||||
* When this source readable stream closes, destination will be closed, unless preventClose is truthy. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error.
|
||||
*
|
||||
* If destination starts out closed or closing, this source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source.
|
||||
*
|
||||
* The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set.
|
||||
*/
|
||||
preventClose?: boolean;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L1710
|
||||
export interface Transformer<I = any, O = any> {
|
||||
flush?: TransformerFlushCallback<O>;
|
||||
readableType?: undefined;
|
||||
start?: TransformerStartCallback<O>;
|
||||
transform?: TransformerTransformCallback<I, O>;
|
||||
writableType?: undefined;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L11132-L11172
|
||||
/** This Streams API interface represents a readable stream of byte data. The Fetch API offers a concrete instance of a ReadableStream through the body property of a Response object. */
|
||||
export interface ReadableStream<R = any> {
|
||||
readonly locked: boolean;
|
||||
cancel(reason?: any): Promise<void>;
|
||||
getReader(): ReadableStreamDefaultReader<R>;
|
||||
pipeThrough<T>(transform: ReadableWritablePair<T, R>, options?: StreamPipeOptions): ReadableStream<T>;
|
||||
pipeTo(destination: WritableStream<R>, options?: StreamPipeOptions): Promise<void>;
|
||||
tee(): [ReadableStream<R>, ReadableStream<R>];
|
||||
}
|
||||
|
||||
export let ReadableStream: {
|
||||
prototype: ReadableStream;
|
||||
new <R = any>(underlyingSource?: UnderlyingSource<R>, strategy?: QueuingStrategy<R>): ReadableStream<R>;
|
||||
};
|
||||
|
||||
export interface ReadableStreamDefaultController<R = any> {
|
||||
readonly desiredSize: number | null;
|
||||
close(): void;
|
||||
enqueue(chunk?: R): void;
|
||||
error(e?: any): void;
|
||||
}
|
||||
|
||||
export let ReadableStreamDefaultController: {
|
||||
prototype: ReadableStreamDefaultController;
|
||||
new(): ReadableStreamDefaultController;
|
||||
};
|
||||
|
||||
export interface ReadableStreamDefaultReader<R = any> extends ReadableStreamGenericReader {
|
||||
read(): Promise<ReadableStreamDefaultReadResult<R>>;
|
||||
releaseLock(): void;
|
||||
}
|
||||
|
||||
export let ReadableStreamDefaultReader: {
|
||||
prototype: ReadableStreamDefaultReader;
|
||||
new <R = any>(stream: ReadableStream<R>): ReadableStreamDefaultReader<R>;
|
||||
};
|
||||
|
||||
export interface ReadableStreamGenericReader {
|
||||
readonly closed: Promise<undefined>;
|
||||
cancel(reason?: any): Promise<void>;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L13924-L13944
|
||||
export interface TransformStream<I = any, O = any> {
|
||||
readonly readable: ReadableStream<O>;
|
||||
readonly writable: WritableStream<I>;
|
||||
}
|
||||
|
||||
export let TransformStream: {
|
||||
prototype: TransformStream;
|
||||
new <I = any, O = any>(transformer?: Transformer<I, O>, writableStrategy?: QueuingStrategy<I>, readableStrategy?: QueuingStrategy<O>): TransformStream<I, O>;
|
||||
};
|
||||
|
||||
export interface TransformStreamDefaultController<O = any> {
|
||||
readonly desiredSize: number | null;
|
||||
enqueue(chunk?: O): void;
|
||||
error(reason?: any): void;
|
||||
terminate(): void;
|
||||
}
|
||||
|
||||
export let TransformStreamDefaultController: {
|
||||
prototype: TransformStreamDefaultController;
|
||||
new(): TransformStreamDefaultController;
|
||||
};
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L16509-L16546
|
||||
/** This Streams API interface provides a standard abstraction for writing streaming data to a destination, known as a sink. This object comes with built-in backpressure and queuing. */
|
||||
export interface WritableStream<W = any> {
|
||||
readonly locked: boolean;
|
||||
abort(reason?: any): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
getWriter(): WritableStreamDefaultWriter<W>;
|
||||
}
|
||||
|
||||
export let WritableStream: {
|
||||
prototype: WritableStream;
|
||||
new <W = any>(underlyingSink?: UnderlyingSink<W>, strategy?: QueuingStrategy<W>): WritableStream<W>;
|
||||
};
|
||||
|
||||
/** This Streams API interface represents a controller allowing control of a WritableStream's state. When constructing a WritableStream, the underlying sink is given a corresponding WritableStreamDefaultController instance to manipulate. */
|
||||
export interface WritableStreamDefaultController {
|
||||
error(e?: any): void;
|
||||
}
|
||||
|
||||
export let WritableStreamDefaultController: {
|
||||
prototype: WritableStreamDefaultController;
|
||||
new(): WritableStreamDefaultController;
|
||||
};
|
||||
|
||||
/** This Streams API interface is the object returned by WritableStream.getWriter() and once created locks the < writer to the WritableStream ensuring that no other streams can write to the underlying sink. */
|
||||
export interface WritableStreamDefaultWriter<W = any> {
|
||||
readonly closed: Promise<undefined>;
|
||||
readonly desiredSize: number | null;
|
||||
readonly ready: Promise<undefined>;
|
||||
abort(reason?: any): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
releaseLock(): void;
|
||||
write(chunk?: W): Promise<void>;
|
||||
}
|
||||
|
||||
export let WritableStreamDefaultWriter: {
|
||||
prototype: WritableStreamDefaultWriter;
|
||||
new <W = any>(stream: WritableStream<W>): WritableStreamDefaultWriter<W>;
|
||||
};
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L17045
|
||||
export interface QueuingStrategySize<T = any> {
|
||||
(chunk: T): number;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L17065-L17103
|
||||
export interface TransformerFlushCallback<O> {
|
||||
(controller: TransformStreamDefaultController<O>): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface TransformerStartCallback<O> {
|
||||
(controller: TransformStreamDefaultController<O>): any;
|
||||
}
|
||||
|
||||
export interface TransformerTransformCallback<I, O> {
|
||||
(chunk: I, controller: TransformStreamDefaultController<O>): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSink<W = any> {
|
||||
abort?: UnderlyingSinkAbortCallback;
|
||||
close?: UnderlyingSinkCloseCallback;
|
||||
start?: UnderlyingSinkStartCallback;
|
||||
type?: undefined;
|
||||
write?: UnderlyingSinkWriteCallback<W>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSource<R = any> {
|
||||
cancel?: UnderlyingSourceCancelCallback;
|
||||
pull?: UnderlyingSourcePullCallback<R>;
|
||||
start?: UnderlyingSourceStartCallback<R>;
|
||||
type?: undefined;
|
||||
}
|
||||
|
||||
export interface UnderlyingSinkAbortCallback {
|
||||
(reason?: any): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSinkCloseCallback {
|
||||
(): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSinkStartCallback {
|
||||
(controller: WritableStreamDefaultController): any;
|
||||
}
|
||||
|
||||
export interface UnderlyingSinkWriteCallback<W> {
|
||||
(chunk: W, controller: WritableStreamDefaultController): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSourceCancelCallback {
|
||||
(reason?: any): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSourcePullCallback<R> {
|
||||
(controller: ReadableStreamController<R>): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface UnderlyingSourceStartCallback<R> {
|
||||
(controller: ReadableStreamController<R>): any;
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/11d922f302743cb3fcee9ab59b03d40074a2965c/baselines/dom.generated.d.ts#L17796-L17798
|
||||
export type ReadableStreamController<T> = ReadableStreamDefaultController<T>;
|
||||
export type ReadableStreamDefaultReadResult<T> = ReadableStreamDefaultReadValueResult<T> | ReadableStreamDefaultReadDoneResult;
|
||||
export type ReadableStreamReader<T> = ReadableStreamDefaultReader<T>;
|
||||
|
||||
// Extra
|
||||
export interface ReadableStream<R> {
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<R>;
|
||||
}
|
||||
|
||||
try {
|
||||
if ('ReadableStream' in globalThis && 'WritableStream' in globalThis && 'TransformStream' in globalThis) {
|
||||
({
|
||||
ReadableStream,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
TransformStream,
|
||||
TransformStreamDefaultController,
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
} = globalThis as any);
|
||||
} else {
|
||||
({
|
||||
ReadableStream,
|
||||
ReadableStreamDefaultController,
|
||||
ReadableStreamDefaultReader,
|
||||
// @ts-expect-error `@types/node` is slightly different from `@types/web`
|
||||
TransformStream,
|
||||
TransformStreamDefaultController,
|
||||
// @ts-expect-error `@types/node` is slightly different from `@types/web`
|
||||
WritableStream,
|
||||
WritableStreamDefaultController,
|
||||
WritableStreamDefaultWriter,
|
||||
} = await import('stream/web'));
|
||||
}
|
||||
} catch {
|
||||
throw new Error('Web Streams API is not available');
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
{
|
||||
"extends": "./node_modules/@yume-chan/ts-package-builder/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2016",
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../event/tsconfig.json"
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
"typescript": "^4.5.5",
|
||||
"@yume-chan/ts-package-builder": "^1.0.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/node": "^16.11.19",
|
||||
"@types/node": "^17.0.17",
|
||||
"@types/bluebird": "^3.5.36"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.19"
|
||||
"@types/node": "^17.0.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": "^2.2.0",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"composite": true,
|
||||
/* Basic Options */
|
||||
"target": "ES2015", // /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"target": "ESNext", // /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "ESNext", // /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"lib": [ // /* Specify library files to be included in the compilation. */
|
||||
"ESNext"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue