mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 09:49:24 +02:00
refactor: remove TypeScript enum and namespace to improve tree-shaking
This commit is contained in:
parent
b1787e8ef4
commit
2c8912e9ac
34 changed files with 744 additions and 619 deletions
|
@ -1,11 +1,13 @@
|
||||||
import type { AdbFeature } from "./features.js";
|
import type { AdbFeature } from "./features.js";
|
||||||
|
|
||||||
export enum AdbBannerKey {
|
export const AdbBannerKey = {
|
||||||
Product = "ro.product.name",
|
Product: "ro.product.name",
|
||||||
Model = "ro.product.model",
|
Model: "ro.product.model",
|
||||||
Device = "ro.product.device",
|
Device: "ro.product.device",
|
||||||
Features = "features",
|
Features: "features",
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AdbBannerKey = (typeof AdbBannerKey)[keyof typeof AdbBannerKey];
|
||||||
|
|
||||||
export class AdbBanner {
|
export class AdbBanner {
|
||||||
static parse(banner: string) {
|
static parse(banner: string) {
|
||||||
|
|
|
@ -3,40 +3,46 @@ import Struct, { StructEmptyError } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { Adb } from "../adb.js";
|
import type { Adb } from "../adb.js";
|
||||||
|
|
||||||
const Version = new Struct({ littleEndian: true }).uint32("version");
|
const Version =
|
||||||
|
/* #__PURE__ */
|
||||||
|
new Struct({ littleEndian: true }).uint32("version");
|
||||||
|
|
||||||
export const AdbFrameBufferV1 = new Struct({ littleEndian: true })
|
export const AdbFrameBufferV1 =
|
||||||
.uint32("bpp")
|
/* #__PURE__ */
|
||||||
.uint32("size")
|
new Struct({ littleEndian: true })
|
||||||
.uint32("width")
|
.uint32("bpp")
|
||||||
.uint32("height")
|
.uint32("size")
|
||||||
.uint32("red_offset")
|
.uint32("width")
|
||||||
.uint32("red_length")
|
.uint32("height")
|
||||||
.uint32("blue_offset")
|
.uint32("red_offset")
|
||||||
.uint32("blue_length")
|
.uint32("red_length")
|
||||||
.uint32("green_offset")
|
.uint32("blue_offset")
|
||||||
.uint32("green_length")
|
.uint32("blue_length")
|
||||||
.uint32("alpha_offset")
|
.uint32("green_offset")
|
||||||
.uint32("alpha_length")
|
.uint32("green_length")
|
||||||
.uint8Array("data", { lengthField: "size" });
|
.uint32("alpha_offset")
|
||||||
|
.uint32("alpha_length")
|
||||||
|
.uint8Array("data", { lengthField: "size" });
|
||||||
|
|
||||||
export type AdbFrameBufferV1 = (typeof AdbFrameBufferV1)["TDeserializeResult"];
|
export type AdbFrameBufferV1 = (typeof AdbFrameBufferV1)["TDeserializeResult"];
|
||||||
|
|
||||||
export const AdbFrameBufferV2 = new Struct({ littleEndian: true })
|
export const AdbFrameBufferV2 =
|
||||||
.uint32("bpp")
|
/* #__PURE__ */
|
||||||
.uint32("colorSpace")
|
new Struct({ littleEndian: true })
|
||||||
.uint32("size")
|
.uint32("bpp")
|
||||||
.uint32("width")
|
.uint32("colorSpace")
|
||||||
.uint32("height")
|
.uint32("size")
|
||||||
.uint32("red_offset")
|
.uint32("width")
|
||||||
.uint32("red_length")
|
.uint32("height")
|
||||||
.uint32("blue_offset")
|
.uint32("red_offset")
|
||||||
.uint32("blue_length")
|
.uint32("red_length")
|
||||||
.uint32("green_offset")
|
.uint32("blue_offset")
|
||||||
.uint32("green_length")
|
.uint32("blue_length")
|
||||||
.uint32("alpha_offset")
|
.uint32("green_offset")
|
||||||
.uint32("alpha_length")
|
.uint32("green_length")
|
||||||
.uint8Array("data", { lengthField: "size" });
|
.uint32("alpha_offset")
|
||||||
|
.uint32("alpha_length")
|
||||||
|
.uint8Array("data", { lengthField: "size" });
|
||||||
|
|
||||||
export type AdbFrameBufferV2 = (typeof AdbFrameBufferV2)["TDeserializeResult"];
|
export type AdbFrameBufferV2 = (typeof AdbFrameBufferV2)["TDeserializeResult"];
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,11 @@ export interface AdbForwardListener {
|
||||||
remoteName: string;
|
remoteName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdbReverseStringResponse = new Struct()
|
const AdbReverseStringResponse =
|
||||||
.string("length", { length: 4 })
|
/* #__PURE__ */
|
||||||
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
new Struct()
|
||||||
|
.string("length", { length: 4 })
|
||||||
|
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
||||||
|
|
||||||
export class AdbReverseError extends Error {
|
export class AdbReverseError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
|
@ -33,9 +35,9 @@ export class AdbReverseNotSupportedError extends AdbReverseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdbReverseErrorResponse = new Struct()
|
const AdbReverseErrorResponse =
|
||||||
.concat(AdbReverseStringResponse)
|
/* #__PURE__ */
|
||||||
.postDeserialize((value) => {
|
new Struct().concat(AdbReverseStringResponse).postDeserialize((value) => {
|
||||||
// https://issuetracker.google.com/issues/37066218
|
// https://issuetracker.google.com/issues/37066218
|
||||||
// ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
|
// ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
|
||||||
// and returns this confusing "more than one device/emulator" error.
|
// and returns this confusing "more than one device/emulator" error.
|
||||||
|
|
|
@ -19,20 +19,25 @@ import { encodeUtf8 } from "../../../utils/index.js";
|
||||||
|
|
||||||
import type { AdbSubprocessProtocol } from "./types.js";
|
import type { AdbSubprocessProtocol } from "./types.js";
|
||||||
|
|
||||||
export enum AdbShellProtocolId {
|
export const AdbShellProtocolId = {
|
||||||
Stdin,
|
Stdin: 0,
|
||||||
Stdout,
|
Stdout: 1,
|
||||||
Stderr,
|
Stderr: 2,
|
||||||
Exit,
|
Exit: 3,
|
||||||
CloseStdin,
|
CloseStdin: 4,
|
||||||
WindowSizeChange,
|
WindowSizeChange: 5,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AdbShellProtocolId =
|
||||||
|
(typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
|
||||||
|
|
||||||
// This packet format is used in both directions.
|
// This packet format is used in both directions.
|
||||||
export const AdbShellProtocolPacket = new Struct({ littleEndian: true })
|
export const AdbShellProtocolPacket =
|
||||||
.uint8("id", placeholder<AdbShellProtocolId>())
|
/* #__PURE__ */
|
||||||
.uint32("length")
|
new Struct({ littleEndian: true })
|
||||||
.uint8Array("data", { lengthField: "length" });
|
.uint8("id", placeholder<AdbShellProtocolId>())
|
||||||
|
.uint32("length")
|
||||||
|
.uint8Array("data", { lengthField: "length" });
|
||||||
|
|
||||||
type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
|
type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
|
||||||
|
|
||||||
|
|
|
@ -14,18 +14,22 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
|
export const AdbSyncEntryResponse =
|
||||||
.concat(AdbSyncLstatResponse)
|
/* #__PURE__ */
|
||||||
.uint32("nameLength")
|
new Struct({ littleEndian: true })
|
||||||
.string("name", { lengthField: "nameLength" });
|
.concat(AdbSyncLstatResponse)
|
||||||
|
.uint32("nameLength")
|
||||||
|
.string("name", { lengthField: "nameLength" });
|
||||||
|
|
||||||
export type AdbSyncEntryResponse =
|
export type AdbSyncEntryResponse =
|
||||||
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
||||||
|
|
||||||
export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
|
export const AdbSyncEntry2Response =
|
||||||
.concat(AdbSyncStatResponse)
|
/* #__PURE__ */
|
||||||
.uint32("nameLength")
|
new Struct({ littleEndian: true })
|
||||||
.string("name", { lengthField: "nameLength" });
|
.concat(AdbSyncStatResponse)
|
||||||
|
.uint32("nameLength")
|
||||||
|
.string("name", { lengthField: "nameLength" });
|
||||||
|
|
||||||
export type AdbSyncEntry2Response =
|
export type AdbSyncEntry2Response =
|
||||||
(typeof AdbSyncEntry2Response)["TDeserializeResult"];
|
(typeof AdbSyncEntry2Response)["TDeserializeResult"];
|
||||||
|
|
|
@ -6,9 +6,11 @@ import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
||||||
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
||||||
import type { AdbSyncSocket } from "./socket.js";
|
import type { AdbSyncSocket } from "./socket.js";
|
||||||
|
|
||||||
export const AdbSyncDataResponse = new Struct({ littleEndian: true })
|
export const AdbSyncDataResponse =
|
||||||
.uint32("dataLength")
|
/* #__PURE__ */
|
||||||
.uint8Array("data", { lengthField: "dataLength" });
|
new Struct({ littleEndian: true })
|
||||||
|
.uint32("dataLength")
|
||||||
|
.uint8Array("data", { lengthField: "dataLength" });
|
||||||
|
|
||||||
export type AdbSyncDataResponse =
|
export type AdbSyncDataResponse =
|
||||||
(typeof AdbSyncDataResponse)["TDeserializeResult"];
|
(typeof AdbSyncDataResponse)["TDeserializeResult"];
|
||||||
|
|
|
@ -25,9 +25,9 @@ export interface AdbSyncPushV1Options {
|
||||||
packetSize?: number;
|
packetSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
export const AdbSyncOkResponse =
|
||||||
"unused",
|
/* #__PURE__ */
|
||||||
);
|
new Struct({ littleEndian: true }).uint32("unused");
|
||||||
|
|
||||||
async function pipeFileData(
|
async function pipeFileData(
|
||||||
locked: AdbSyncSocketLocked,
|
locked: AdbSyncSocketLocked,
|
||||||
|
@ -86,19 +86,22 @@ export async function adbSyncPushV1({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AdbSyncSendV2Flags {
|
export const AdbSyncSendV2Flags = {
|
||||||
None = 0,
|
None: 0,
|
||||||
Brotli = 1,
|
Brotli: 1,
|
||||||
/**
|
/**
|
||||||
* 2
|
* 2
|
||||||
*/
|
*/
|
||||||
Lz4 = 1 << 1,
|
Lz4: 1 << 1,
|
||||||
/**
|
/**
|
||||||
* 4
|
* 4
|
||||||
*/
|
*/
|
||||||
Zstd = 1 << 2,
|
Zstd: 1 << 2,
|
||||||
DryRun = 0x80000000,
|
DryRun: 0x80000000,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AdbSyncSendV2Flags =
|
||||||
|
(typeof AdbSyncSendV2Flags)[keyof typeof AdbSyncSendV2Flags];
|
||||||
|
|
||||||
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
||||||
/**
|
/**
|
||||||
|
@ -110,10 +113,12 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
|
export const AdbSyncSendV2Request =
|
||||||
.uint32("id")
|
/* #__PURE__ */
|
||||||
.uint32("mode")
|
new Struct({ littleEndian: true })
|
||||||
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
.uint32("id")
|
||||||
|
.uint32("mode")
|
||||||
|
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
||||||
|
|
||||||
export async function adbSyncPushV2({
|
export async function adbSyncPushV2({
|
||||||
socket,
|
socket,
|
||||||
|
|
|
@ -4,22 +4,22 @@ import { encodeUtf8 } from "../../utils/index.js";
|
||||||
|
|
||||||
import { adbSyncEncodeId } from "./response.js";
|
import { adbSyncEncodeId } from "./response.js";
|
||||||
|
|
||||||
export namespace AdbSyncRequestId {
|
export const AdbSyncRequestId = {
|
||||||
export const List = adbSyncEncodeId("LIST");
|
List: adbSyncEncodeId("LIST"),
|
||||||
export const ListV2 = adbSyncEncodeId("LIS2");
|
ListV2: adbSyncEncodeId("LIS2"),
|
||||||
export const Send = adbSyncEncodeId("SEND");
|
Send: adbSyncEncodeId("SEND"),
|
||||||
export const SendV2 = adbSyncEncodeId("SND2");
|
SendV2: adbSyncEncodeId("SND2"),
|
||||||
export const Lstat = adbSyncEncodeId("STAT");
|
Lstat: adbSyncEncodeId("STAT"),
|
||||||
export const Stat = adbSyncEncodeId("STA2");
|
Stat: adbSyncEncodeId("STA2"),
|
||||||
export const LstatV2 = adbSyncEncodeId("LST2");
|
LstatV2: adbSyncEncodeId("LST2"),
|
||||||
export const Data = adbSyncEncodeId("DATA");
|
Data: adbSyncEncodeId("DATA"),
|
||||||
export const Done = adbSyncEncodeId("DONE");
|
Done: adbSyncEncodeId("DONE"),
|
||||||
export const Receive = adbSyncEncodeId("RECV");
|
Receive: adbSyncEncodeId("RECV"),
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
|
export const AdbSyncNumberRequest =
|
||||||
.uint32("id")
|
/* #__PURE__ */
|
||||||
.uint32("arg");
|
new Struct({ littleEndian: true }).uint32("id").uint32("arg");
|
||||||
|
|
||||||
export interface AdbSyncWritable {
|
export interface AdbSyncWritable {
|
||||||
write(buffer: Uint8Array): Promise<void>;
|
write(buffer: Uint8Array): Promise<void>;
|
||||||
|
|
|
@ -18,32 +18,36 @@ function encodeAsciiUnchecked(value: string): Uint8Array {
|
||||||
* Encode ID to numbers for faster comparison
|
* Encode ID to numbers for faster comparison
|
||||||
* @param value A 4-character string
|
* @param value A 4-character string
|
||||||
* @returns A 32-bit integer by encoding the string as little-endian
|
* @returns A 32-bit integer by encoding the string as little-endian
|
||||||
|
*
|
||||||
|
* #__NO_SIDE_EFFECTS__
|
||||||
*/
|
*/
|
||||||
export function adbSyncEncodeId(value: string): number {
|
export function adbSyncEncodeId(value: string): number {
|
||||||
const buffer = encodeAsciiUnchecked(value);
|
const buffer = encodeAsciiUnchecked(value);
|
||||||
return getUint32LittleEndian(buffer, 0);
|
return getUint32LittleEndian(buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace AdbSyncResponseId {
|
export const AdbSyncResponseId = {
|
||||||
export const Entry = adbSyncEncodeId("DENT");
|
Entry: adbSyncEncodeId("DENT"),
|
||||||
export const Entry2 = adbSyncEncodeId("DNT2");
|
Entry2: adbSyncEncodeId("DNT2"),
|
||||||
export const Lstat = adbSyncEncodeId("STAT");
|
Lstat: adbSyncEncodeId("STAT"),
|
||||||
export const Stat = adbSyncEncodeId("STA2");
|
Stat: adbSyncEncodeId("STA2"),
|
||||||
export const Lstat2 = adbSyncEncodeId("LST2");
|
Lstat2: adbSyncEncodeId("LST2"),
|
||||||
export const Done = adbSyncEncodeId("DONE");
|
Done: adbSyncEncodeId("DONE"),
|
||||||
export const Data = adbSyncEncodeId("DATA");
|
Data: adbSyncEncodeId("DATA"),
|
||||||
export const Ok = adbSyncEncodeId("OKAY");
|
Ok: adbSyncEncodeId("OKAY"),
|
||||||
export const Fail = adbSyncEncodeId("FAIL");
|
Fail: adbSyncEncodeId("FAIL"),
|
||||||
}
|
};
|
||||||
|
|
||||||
export class AdbSyncError extends Error {}
|
export class AdbSyncError extends Error {}
|
||||||
|
|
||||||
export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
export const AdbSyncFailResponse =
|
||||||
.uint32("messageLength")
|
/* #__PURE__ */
|
||||||
.string("message", { lengthField: "messageLength" })
|
new Struct({ littleEndian: true })
|
||||||
.postDeserialize((object) => {
|
.uint32("messageLength")
|
||||||
throw new AdbSyncError(object.message);
|
.string("message", { lengthField: "messageLength" })
|
||||||
});
|
.postDeserialize((object) => {
|
||||||
|
throw new AdbSyncError(object.message);
|
||||||
|
});
|
||||||
|
|
||||||
export async function adbSyncReadResponse<T>(
|
export async function adbSyncReadResponse<T>(
|
||||||
stream: AsyncExactReadable,
|
stream: AsyncExactReadable,
|
||||||
|
|
|
@ -5,11 +5,13 @@ import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
||||||
import type { AdbSyncSocket } from "./socket.js";
|
import type { AdbSyncSocket } from "./socket.js";
|
||||||
|
|
||||||
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
||||||
export enum LinuxFileType {
|
export const LinuxFileType = {
|
||||||
Directory = 0o04,
|
Directory: 0o04,
|
||||||
File = 0o10,
|
File: 0o10,
|
||||||
Link = 0o12,
|
Link: 0o12,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type LinuxFileType = (typeof LinuxFileType)[keyof typeof LinuxFileType];
|
||||||
|
|
||||||
export interface AdbSyncStat {
|
export interface AdbSyncStat {
|
||||||
mode: number;
|
mode: number;
|
||||||
|
@ -24,76 +26,92 @@ export interface AdbSyncStat {
|
||||||
ctime?: bigint;
|
ctime?: bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
|
export const AdbSyncLstatResponse =
|
||||||
.int32("mode")
|
/* #__PURE__ */
|
||||||
.int32("size")
|
new Struct({ littleEndian: true })
|
||||||
.int32("mtime")
|
.int32("mode")
|
||||||
.extra({
|
.int32("size")
|
||||||
get type() {
|
.int32("mtime")
|
||||||
return (this.mode >> 12) as LinuxFileType;
|
.extra({
|
||||||
},
|
get type() {
|
||||||
get permission() {
|
return (this.mode >> 12) as LinuxFileType;
|
||||||
return this.mode & 0b00001111_11111111;
|
},
|
||||||
},
|
get permission() {
|
||||||
})
|
return this.mode & 0b00001111_11111111;
|
||||||
.postDeserialize((object) => {
|
},
|
||||||
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
})
|
||||||
throw new Error("lstat error");
|
.postDeserialize((object) => {
|
||||||
}
|
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
||||||
});
|
throw new Error("lstat error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export type AdbSyncLstatResponse =
|
export type AdbSyncLstatResponse =
|
||||||
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
||||||
|
|
||||||
export enum AdbSyncStatErrorCode {
|
export const AdbSyncStatErrorCode = {
|
||||||
SUCCESS = 0,
|
SUCCESS: 0,
|
||||||
EACCES = 13,
|
EACCES: 13,
|
||||||
EEXIST = 17,
|
EEXIST: 17,
|
||||||
EFAULT = 14,
|
EFAULT: 14,
|
||||||
EFBIG = 27,
|
EFBIG: 27,
|
||||||
EINTR = 4,
|
EINTR: 4,
|
||||||
EINVAL = 22,
|
EINVAL: 22,
|
||||||
EIO = 5,
|
EIO: 5,
|
||||||
EISDIR = 21,
|
EISDIR: 21,
|
||||||
ELOOP = 40,
|
ELOOP: 40,
|
||||||
EMFILE = 24,
|
EMFILE: 24,
|
||||||
ENAMETOOLONG = 36,
|
ENAMETOOLONG: 36,
|
||||||
ENFILE = 23,
|
ENFILE: 23,
|
||||||
ENOENT = 2,
|
ENOENT: 2,
|
||||||
ENOMEM = 12,
|
ENOMEM: 12,
|
||||||
ENOSPC = 28,
|
ENOSPC: 28,
|
||||||
ENOTDIR = 20,
|
ENOTDIR: 20,
|
||||||
EOVERFLOW = 75,
|
EOVERFLOW: 75,
|
||||||
EPERM = 1,
|
EPERM: 1,
|
||||||
EROFS = 30,
|
EROFS: 30,
|
||||||
ETXTBSY = 26,
|
ETXTBSY: 26,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
export const AdbSyncStatResponse = new Struct({ littleEndian: true })
|
export type AdbSyncStatErrorCode =
|
||||||
.uint32("error", placeholder<AdbSyncStatErrorCode>())
|
(typeof AdbSyncStatErrorCode)[keyof typeof AdbSyncStatErrorCode];
|
||||||
.uint64("dev")
|
|
||||||
.uint64("ino")
|
const AdbSyncStatErrorName =
|
||||||
.uint32("mode")
|
/* #__PURE__ */
|
||||||
.uint32("nlink")
|
Object.fromEntries(
|
||||||
.uint32("uid")
|
Object.entries(AdbSyncStatErrorCode).map(([key, value]) => [
|
||||||
.uint32("gid")
|
value,
|
||||||
.uint64("size")
|
key,
|
||||||
.uint64("atime")
|
]),
|
||||||
.uint64("mtime")
|
);
|
||||||
.uint64("ctime")
|
|
||||||
.extra({
|
export const AdbSyncStatResponse =
|
||||||
get type() {
|
/* #__PURE__ */
|
||||||
return (this.mode >> 12) as LinuxFileType;
|
new Struct({ littleEndian: true })
|
||||||
},
|
.uint32("error", placeholder<AdbSyncStatErrorCode>())
|
||||||
get permission() {
|
.uint64("dev")
|
||||||
return this.mode & 0b00001111_11111111;
|
.uint64("ino")
|
||||||
},
|
.uint32("mode")
|
||||||
})
|
.uint32("nlink")
|
||||||
.postDeserialize((object) => {
|
.uint32("uid")
|
||||||
if (object.error) {
|
.uint32("gid")
|
||||||
throw new Error(AdbSyncStatErrorCode[object.error]);
|
.uint64("size")
|
||||||
}
|
.uint64("atime")
|
||||||
});
|
.uint64("mtime")
|
||||||
|
.uint64("ctime")
|
||||||
|
.extra({
|
||||||
|
get type() {
|
||||||
|
return (this.mode >> 12) as LinuxFileType;
|
||||||
|
},
|
||||||
|
get permission() {
|
||||||
|
return this.mode & 0b00001111_11111111;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.postDeserialize((object) => {
|
||||||
|
if (object.error) {
|
||||||
|
throw new Error(AdbSyncStatErrorName[object.error]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export type AdbSyncStatResponse =
|
export type AdbSyncStatResponse =
|
||||||
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
||||||
|
|
|
@ -1,30 +1,36 @@
|
||||||
import { Consumable, TransformStream } from "@yume-chan/stream-extra";
|
import { Consumable, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import Struct from "@yume-chan/struct";
|
import Struct from "@yume-chan/struct";
|
||||||
|
|
||||||
export enum AdbCommand {
|
export const AdbCommand = {
|
||||||
Auth = 0x48545541, // 'AUTH'
|
Auth: 0x48545541, // 'AUTH'
|
||||||
Close = 0x45534c43, // 'CLSE'
|
Close: 0x45534c43, // 'CLSE'
|
||||||
Connect = 0x4e584e43, // 'CNXN'
|
Connect: 0x4e584e43, // 'CNXN'
|
||||||
Okay = 0x59414b4f, // 'OKAY'
|
Okay: 0x59414b4f, // 'OKAY'
|
||||||
Open = 0x4e45504f, // 'OPEN'
|
Open: 0x4e45504f, // 'OPEN'
|
||||||
Write = 0x45545257, // 'WRTE'
|
Write: 0x45545257, // 'WRTE'
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
export const AdbPacketHeader = new Struct({ littleEndian: true })
|
export type AdbCommand = (typeof AdbCommand)[keyof typeof AdbCommand];
|
||||||
.uint32("command")
|
|
||||||
.uint32("arg0")
|
export const AdbPacketHeader =
|
||||||
.uint32("arg1")
|
/* #__PURE__ */
|
||||||
.uint32("payloadLength")
|
new Struct({ littleEndian: true })
|
||||||
.uint32("checksum")
|
.uint32("command")
|
||||||
.int32("magic");
|
.uint32("arg0")
|
||||||
|
.uint32("arg1")
|
||||||
|
.uint32("payloadLength")
|
||||||
|
.uint32("checksum")
|
||||||
|
.int32("magic");
|
||||||
|
|
||||||
export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
||||||
|
|
||||||
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
||||||
|
|
||||||
export const AdbPacket = new Struct({ littleEndian: true })
|
export const AdbPacket =
|
||||||
.concat(AdbPacketHeader)
|
/* #__PURE__ */
|
||||||
.uint8Array("payload", { lengthField: "payloadLength" });
|
new Struct({ littleEndian: true })
|
||||||
|
.concat(AdbPacketHeader)
|
||||||
|
.uint8Array("payload", { lengthField: "payloadLength" });
|
||||||
|
|
||||||
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
// The order follows
|
// The order follows
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/transport.cpp;l=77;drc=6d14d35d0241f6fee145f8e54ffd77252e8d29fd
|
// https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/transport.cpp;l=77;drc=6d14d35d0241f6fee145f8e54ffd77252e8d29fd
|
||||||
export enum AdbFeature {
|
export const AdbFeature = {
|
||||||
ShellV2 = "shell_v2",
|
ShellV2: "shell_v2",
|
||||||
Cmd = "cmd",
|
Cmd: "cmd",
|
||||||
StatV2 = "stat_v2",
|
StatV2: "stat_v2",
|
||||||
ListV2 = "ls_v2",
|
ListV2: "ls_v2",
|
||||||
FixedPushMkdir = "fixed_push_mkdir",
|
FixedPushMkdir: "fixed_push_mkdir",
|
||||||
Abb = "abb",
|
Abb: "abb",
|
||||||
AbbExec = "abb_exec",
|
AbbExec: "abb_exec",
|
||||||
SendReceiveV2 = "sendrecv_v2",
|
SendReceiveV2: "sendrecv_v2",
|
||||||
DelayedAck = "delayed_ack",
|
DelayedAck: "delayed_ack",
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AdbFeature = (typeof AdbFeature)[keyof typeof AdbFeature];
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
// Array is faster than object literal or `Map`
|
const [charToIndex, indexToChar, paddingChar] = /* #__PURE__ */ (() => {
|
||||||
const charToIndex: number[] = [];
|
// Array is faster than object literal or `Map`
|
||||||
const indexToChar: number[] = [];
|
const charToIndex: number[] = [];
|
||||||
const paddingChar = "=".charCodeAt(0);
|
const indexToChar: number[] = [];
|
||||||
|
const paddingChar = "=".charCodeAt(0);
|
||||||
|
|
||||||
function addRange(start: string, end: string) {
|
function addRange(start: string, end: string) {
|
||||||
const charCodeStart = start.charCodeAt(0);
|
const charCodeStart = start.charCodeAt(0);
|
||||||
const charCodeEnd = end.charCodeAt(0);
|
const charCodeEnd = end.charCodeAt(0);
|
||||||
|
|
||||||
for (let charCode = charCodeStart; charCode <= charCodeEnd; charCode += 1) {
|
for (
|
||||||
charToIndex[charCode] = indexToChar.length;
|
let charCode = charCodeStart;
|
||||||
indexToChar.push(charCode);
|
charCode <= charCodeEnd;
|
||||||
|
charCode += 1
|
||||||
|
) {
|
||||||
|
charToIndex[charCode] = indexToChar.length;
|
||||||
|
indexToChar.push(charCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
addRange("A", "Z");
|
addRange("A", "Z");
|
||||||
addRange("a", "z");
|
addRange("a", "z");
|
||||||
addRange("0", "9");
|
addRange("0", "9");
|
||||||
addRange("+", "+");
|
addRange("+", "+");
|
||||||
addRange("/", "/");
|
addRange("/", "/");
|
||||||
|
|
||||||
|
return [charToIndex, indexToChar, paddingChar];
|
||||||
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the required length of the output buffer for the given input length.
|
* Calculate the required length of the output buffer for the given input length.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
export const NOOP = () => {
|
export const NOOP = () => {
|
||||||
// no-op
|
// no-op
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,32 @@ const BatteryDumpFields: Record<
|
||||||
current: { type: "number", field: "current" },
|
current: { type: "number", field: "current" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Status = {
|
||||||
|
Unknown: 1,
|
||||||
|
Charging: 2,
|
||||||
|
Discharging: 3,
|
||||||
|
NotCharging: 4,
|
||||||
|
Full: 5,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const Health = {
|
||||||
|
Unknown: 1,
|
||||||
|
Good: 2,
|
||||||
|
Overheat: 3,
|
||||||
|
Dead: 4,
|
||||||
|
OverVoltage: 5,
|
||||||
|
UnspecifiedFailure: 6,
|
||||||
|
Cold: 7,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const Battery = {
|
||||||
|
Status,
|
||||||
|
Health,
|
||||||
|
};
|
||||||
|
|
||||||
export class DumpSys extends AdbCommandBase {
|
export class DumpSys extends AdbCommandBase {
|
||||||
|
static readonly Battery = Battery;
|
||||||
|
|
||||||
async diskStats() {
|
async diskStats() {
|
||||||
const output = await this.adb.subprocess.spawnAndWaitLegacy([
|
const output = await this.adb.subprocess.spawnAndWaitLegacy([
|
||||||
"dumpsys",
|
"dumpsys",
|
||||||
|
@ -113,6 +138,9 @@ export class DumpSys extends AdbCommandBase {
|
||||||
|
|
||||||
export namespace DumpSys {
|
export namespace DumpSys {
|
||||||
export namespace Battery {
|
export namespace Battery {
|
||||||
|
export type Status = (typeof Status)[keyof typeof Status];
|
||||||
|
export type Health = (typeof Health)[keyof typeof Health];
|
||||||
|
|
||||||
export interface Info {
|
export interface Info {
|
||||||
acPowered: boolean;
|
acPowered: boolean;
|
||||||
usbPowered: boolean;
|
usbPowered: boolean;
|
||||||
|
@ -131,23 +159,5 @@ export namespace DumpSys {
|
||||||
technology?: string;
|
technology?: string;
|
||||||
current?: number;
|
current?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Status {
|
|
||||||
Unknown = 1,
|
|
||||||
Charging,
|
|
||||||
Discharging,
|
|
||||||
NotCharging,
|
|
||||||
Full,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Health {
|
|
||||||
Unknown = 1,
|
|
||||||
Good,
|
|
||||||
Overheat,
|
|
||||||
Dead,
|
|
||||||
OverVoltage,
|
|
||||||
UnspecifiedFailure,
|
|
||||||
Cold,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,30 +17,39 @@ import Struct, { decodeUtf8 } from "@yume-chan/struct";
|
||||||
// so instead of adding to core library, it's implemented here
|
// so instead of adding to core library, it's implemented here
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=141;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=141;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||||
export enum LogId {
|
export const LogId = {
|
||||||
All = -1,
|
All: -1,
|
||||||
Main,
|
Main: 0,
|
||||||
Radio,
|
Radio: 1,
|
||||||
Events,
|
Events: 2,
|
||||||
System,
|
System: 3,
|
||||||
Crash,
|
Crash: 4,
|
||||||
Stats,
|
Stats: 5,
|
||||||
Security,
|
Security: 6,
|
||||||
Kernel,
|
Kernel: 7,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type LogId = (typeof LogId)[keyof typeof LogId];
|
||||||
|
|
||||||
|
const LogIdName =
|
||||||
|
/* #__PURE__ */
|
||||||
|
Object.fromEntries(Object.entries(LogId).map(([k, v]) => [v, k]));
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||||
export enum AndroidLogPriority {
|
export const AndroidLogPriority = {
|
||||||
Unknown,
|
Unknown: 0,
|
||||||
Default,
|
Default: 1,
|
||||||
Verbose,
|
Verbose: 2,
|
||||||
Debug,
|
Debug: 3,
|
||||||
Info,
|
Info: 4,
|
||||||
Warn,
|
Warn: 5,
|
||||||
Error,
|
Error: 6,
|
||||||
Fatal,
|
Fatal: 7,
|
||||||
Silent,
|
Silent: 8,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type AndroidLogPriority =
|
||||||
|
(typeof AndroidLogPriority)[keyof typeof AndroidLogPriority];
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=140;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=140;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
|
||||||
export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
|
export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
|
||||||
|
@ -56,16 +65,18 @@ export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
|
||||||
[AndroidLogPriority.Silent]: "S",
|
[AndroidLogPriority.Silent]: "S",
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum LogcatFormat {
|
export const LogcatFormat = {
|
||||||
Brief,
|
Brief: 0,
|
||||||
Process,
|
Process: 1,
|
||||||
Tag,
|
Tag: 2,
|
||||||
Thread,
|
Thread: 3,
|
||||||
Raw,
|
Raw: 4,
|
||||||
Time,
|
Time: 5,
|
||||||
ThreadTime,
|
ThreadTime: 6,
|
||||||
Long,
|
Long: 7,
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
|
export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat];
|
||||||
|
|
||||||
export interface LogcatFormatModifiers {
|
export interface LogcatFormatModifiers {
|
||||||
microseconds?: boolean;
|
microseconds?: boolean;
|
||||||
|
@ -88,23 +99,25 @@ export interface LogcatOptions {
|
||||||
const NANOSECONDS_PER_SECOND = BigInt(1e9);
|
const NANOSECONDS_PER_SECOND = BigInt(1e9);
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||||
export const LoggerEntry = new Struct({ littleEndian: true })
|
export const LoggerEntry =
|
||||||
.uint16("payloadSize")
|
/* #__PURE__ */
|
||||||
.uint16("headerSize")
|
new Struct({ littleEndian: true })
|
||||||
.int32("pid")
|
.uint16("payloadSize")
|
||||||
.uint32("tid")
|
.uint16("headerSize")
|
||||||
.uint32("seconds")
|
.int32("pid")
|
||||||
.uint32("nanoseconds")
|
.uint32("tid")
|
||||||
.uint32("logId")
|
.uint32("seconds")
|
||||||
.uint32("uid")
|
.uint32("nanoseconds")
|
||||||
.extra({
|
.uint32("logId")
|
||||||
get timestamp() {
|
.uint32("uid")
|
||||||
return (
|
.extra({
|
||||||
BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
|
get timestamp() {
|
||||||
BigInt(this.nanoseconds)
|
return (
|
||||||
);
|
BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
|
||||||
},
|
BigInt(this.nanoseconds)
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export type LoggerEntry = (typeof LoggerEntry)["TDeserializeResult"];
|
export type LoggerEntry = (typeof LoggerEntry)["TDeserializeResult"];
|
||||||
|
|
||||||
|
@ -385,7 +398,7 @@ export interface LogSize {
|
||||||
|
|
||||||
export class Logcat extends AdbCommandBase {
|
export class Logcat extends AdbCommandBase {
|
||||||
static logIdToName(id: LogId): string {
|
static logIdToName(id: LogId): string {
|
||||||
return LogId[id];
|
return LogIdName[id]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
static logNameToId(name: string): LogId {
|
static logNameToId(name: string): LogId {
|
||||||
|
|
|
@ -92,10 +92,9 @@ class VideoFrameCapturer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VideoFrameCapturerPool = /*@__PURE__*/ new Pool(
|
const VideoFrameCapturerPool =
|
||||||
() => new VideoFrameCapturer(),
|
/* #__PURE__ */
|
||||||
4,
|
new Pool(() => new VideoFrameCapturer(), 4);
|
||||||
);
|
|
||||||
|
|
||||||
export interface WebCodecsVideoDecoderInit {
|
export interface WebCodecsVideoDecoderInit {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import { Struct } from "@yume-chan/struct";
|
import { Struct } from "@yume-chan/struct";
|
||||||
|
|
||||||
export const EmptyControlMessage = new Struct().uint8("type");
|
export const EmptyControlMessage = /* #__PURE__ */ new Struct().uint8("type");
|
||||||
|
|
|
@ -205,12 +205,14 @@ export enum AndroidKeyCode {
|
||||||
AndroidPaste,
|
AndroidPaste,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyInjectKeyCodeControlMessage = new Struct()
|
export const ScrcpyInjectKeyCodeControlMessage =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint8("action", placeholder<AndroidKeyEventAction>())
|
new Struct()
|
||||||
.uint32("keyCode", placeholder<AndroidKeyCode>())
|
.uint8("type")
|
||||||
.uint32("repeat")
|
.uint8("action", placeholder<AndroidKeyEventAction>())
|
||||||
.uint32("metaState", placeholder<AndroidKeyEventMeta>());
|
.uint32("keyCode", placeholder<AndroidKeyCode>())
|
||||||
|
.uint32("repeat")
|
||||||
|
.uint32("metaState", placeholder<AndroidKeyEventMeta>());
|
||||||
|
|
||||||
export type ScrcpyInjectKeyCodeControlMessage =
|
export type ScrcpyInjectKeyCodeControlMessage =
|
||||||
(typeof ScrcpyInjectKeyCodeControlMessage)["TInit"];
|
(typeof ScrcpyInjectKeyCodeControlMessage)["TInit"];
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import Struct from "@yume-chan/struct";
|
import Struct from "@yume-chan/struct";
|
||||||
|
|
||||||
export const ScrcpyInjectTextControlMessage = new Struct()
|
export const ScrcpyInjectTextControlMessage =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint32("length")
|
new Struct()
|
||||||
.string("text", { lengthField: "length" });
|
.uint8("type")
|
||||||
|
.uint32("length")
|
||||||
|
.string("text", { lengthField: "length" });
|
||||||
|
|
||||||
export type ScrcpyInjectTextControlMessage =
|
export type ScrcpyInjectTextControlMessage =
|
||||||
(typeof ScrcpyInjectTextControlMessage)["TInit"];
|
(typeof ScrcpyInjectTextControlMessage)["TInit"];
|
||||||
|
|
|
@ -6,9 +6,11 @@ export enum AndroidScreenPowerMode {
|
||||||
Normal = 2,
|
Normal = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpySetScreenPowerModeControlMessage = new Struct()
|
export const ScrcpySetScreenPowerModeControlMessage =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint8("mode", placeholder<AndroidScreenPowerMode>());
|
new Struct()
|
||||||
|
.uint8("type")
|
||||||
|
.uint8("mode", placeholder<AndroidScreenPowerMode>());
|
||||||
|
|
||||||
export type ScrcpySetScreenPowerModeControlMessage =
|
export type ScrcpySetScreenPowerModeControlMessage =
|
||||||
(typeof ScrcpySetScreenPowerModeControlMessage)["TInit"];
|
(typeof ScrcpySetScreenPowerModeControlMessage)["TInit"];
|
||||||
|
|
|
@ -23,37 +23,43 @@ export const SCRCPY_CONTROL_MESSAGE_TYPES_1_16: readonly ScrcpyControlMessageTyp
|
||||||
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ScrcpyMediaStreamRawPacket = new Struct()
|
export const ScrcpyMediaStreamRawPacket =
|
||||||
.uint64("pts")
|
/* #__PURE__ */
|
||||||
.uint32("size")
|
new Struct()
|
||||||
.uint8Array("data", { lengthField: "size" });
|
.uint64("pts")
|
||||||
|
.uint32("size")
|
||||||
|
.uint8Array("data", { lengthField: "size" });
|
||||||
|
|
||||||
export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
|
export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
|
||||||
|
|
||||||
export const ScrcpyInjectTouchControlMessage1_16 = new Struct()
|
export const ScrcpyInjectTouchControlMessage1_16 =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
new Struct()
|
||||||
.uint64("pointerId")
|
.uint8("type")
|
||||||
.uint32("pointerX")
|
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||||
.uint32("pointerY")
|
.uint64("pointerId")
|
||||||
.uint16("screenWidth")
|
.uint32("pointerX")
|
||||||
.uint16("screenHeight")
|
.uint32("pointerY")
|
||||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
.uint16("screenWidth")
|
||||||
.uint32("buttons");
|
.uint16("screenHeight")
|
||||||
|
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||||
|
.uint32("buttons");
|
||||||
|
|
||||||
export type ScrcpyInjectTouchControlMessage1_16 =
|
export type ScrcpyInjectTouchControlMessage1_16 =
|
||||||
(typeof ScrcpyInjectTouchControlMessage1_16)["TInit"];
|
(typeof ScrcpyInjectTouchControlMessage1_16)["TInit"];
|
||||||
|
|
||||||
export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
|
export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
|
||||||
|
|
||||||
export const ScrcpySetClipboardControlMessage1_15 = new Struct()
|
export const ScrcpySetClipboardControlMessage1_15 =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint32("length")
|
new Struct()
|
||||||
.string("content", { lengthField: "length" });
|
.uint8("type")
|
||||||
|
.uint32("length")
|
||||||
|
.string("content", { lengthField: "length" });
|
||||||
|
|
||||||
export type ScrcpySetClipboardControlMessage1_15 =
|
export type ScrcpySetClipboardControlMessage1_15 =
|
||||||
(typeof ScrcpySetClipboardControlMessage1_15)["TInit"];
|
(typeof ScrcpySetClipboardControlMessage1_15)["TInit"];
|
||||||
|
|
||||||
export const ScrcpyClipboardDeviceMessage = new Struct()
|
export const ScrcpyClipboardDeviceMessage =
|
||||||
.uint32("length")
|
/* #__PURE__ */
|
||||||
.string("content", { lengthField: "length" });
|
new Struct().uint32("length").string("content", { lengthField: "length" });
|
||||||
|
|
|
@ -8,14 +8,16 @@ export interface ScrcpyScrollController {
|
||||||
): Uint8Array | undefined;
|
): Uint8Array | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
|
export const ScrcpyInjectScrollControlMessage1_16 =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint32("pointerX")
|
new Struct()
|
||||||
.uint32("pointerY")
|
.uint8("type")
|
||||||
.uint16("screenWidth")
|
.uint32("pointerX")
|
||||||
.uint16("screenHeight")
|
.uint32("pointerY")
|
||||||
.int32("scrollX")
|
.uint16("screenWidth")
|
||||||
.int32("scrollY");
|
.uint16("screenHeight")
|
||||||
|
.int32("scrollX")
|
||||||
|
.int32("scrollY");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Old version of Scrcpy server only supports integer values for scroll.
|
* Old version of Scrcpy server only supports integer values for scroll.
|
||||||
|
|
|
@ -42,9 +42,11 @@ export interface ScrcpyOptionsInit1_18
|
||||||
powerOffOnClose?: boolean;
|
powerOffOnClose?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyBackOrScreenOnControlMessage1_18 = new Struct()
|
export const ScrcpyBackOrScreenOnControlMessage1_18 =
|
||||||
.concat(ScrcpyBackOrScreenOnControlMessage1_16)
|
/* #__PURE__ */
|
||||||
.uint8("action", placeholder<AndroidKeyEventAction>());
|
new Struct()
|
||||||
|
.concat(ScrcpyBackOrScreenOnControlMessage1_16)
|
||||||
|
.uint8("action", placeholder<AndroidKeyEventAction>());
|
||||||
|
|
||||||
export type ScrcpyBackOrScreenOnControlMessage1_18 =
|
export type ScrcpyBackOrScreenOnControlMessage1_18 =
|
||||||
(typeof ScrcpyBackOrScreenOnControlMessage1_18)["TInit"];
|
(typeof ScrcpyBackOrScreenOnControlMessage1_18)["TInit"];
|
||||||
|
|
|
@ -10,7 +10,9 @@ import type { ScrcpyOptionsInit1_18 } from "./1_18.js";
|
||||||
import { ScrcpyOptions1_18 } from "./1_18.js";
|
import { ScrcpyOptions1_18 } from "./1_18.js";
|
||||||
import { ScrcpyOptions, toScrcpyOptionValue } from "./types.js";
|
import { ScrcpyOptions, toScrcpyOptionValue } from "./types.js";
|
||||||
|
|
||||||
export const ScrcpyAckClipboardDeviceMessage = new Struct().uint64("sequence");
|
export const ScrcpyAckClipboardDeviceMessage =
|
||||||
|
/* #__PURE__ */
|
||||||
|
new Struct().uint64("sequence");
|
||||||
|
|
||||||
export interface ScrcpyOptionsInit1_21 extends ScrcpyOptionsInit1_18 {
|
export interface ScrcpyOptionsInit1_21 extends ScrcpyOptionsInit1_18 {
|
||||||
clipboardAutosync?: boolean;
|
clipboardAutosync?: boolean;
|
||||||
|
@ -20,12 +22,14 @@ function toSnakeCase(input: string): string {
|
||||||
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpySetClipboardControlMessage1_21 = new Struct()
|
export const ScrcpySetClipboardControlMessage1_21 =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint64("sequence")
|
new Struct()
|
||||||
.int8("paste", placeholder<boolean>())
|
.uint8("type")
|
||||||
.uint32("length")
|
.uint64("sequence")
|
||||||
.string("content", { lengthField: "length" });
|
.int8("paste", placeholder<boolean>())
|
||||||
|
.uint32("length")
|
||||||
|
.string("content", { lengthField: "length" });
|
||||||
|
|
||||||
export type ScrcpySetClipboardControlMessage1_21 =
|
export type ScrcpySetClipboardControlMessage1_21 =
|
||||||
(typeof ScrcpySetClipboardControlMessage1_21)["TInit"];
|
(typeof ScrcpySetClipboardControlMessage1_21)["TInit"];
|
||||||
|
|
|
@ -5,9 +5,9 @@ import {
|
||||||
ScrcpyScrollController1_16,
|
ScrcpyScrollController1_16,
|
||||||
} from "../1_16/index.js";
|
} from "../1_16/index.js";
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_22 = new Struct()
|
export const ScrcpyInjectScrollControlMessage1_22 =
|
||||||
.concat(ScrcpyInjectScrollControlMessage1_16)
|
/* #__PURE__ */
|
||||||
.int32("buttons");
|
new Struct().concat(ScrcpyInjectScrollControlMessage1_16).int32("buttons");
|
||||||
|
|
||||||
export type ScrcpyInjectScrollControlMessage1_22 =
|
export type ScrcpyInjectScrollControlMessage1_22 =
|
||||||
(typeof ScrcpyInjectScrollControlMessage1_22)["TInit"];
|
(typeof ScrcpyInjectScrollControlMessage1_22)["TInit"];
|
||||||
|
|
|
@ -27,15 +27,17 @@ const ScrcpySignedFloatFieldDefinition = new NumberFieldDefinition(
|
||||||
ScrcpySignedFloatNumberVariant,
|
ScrcpySignedFloatNumberVariant,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_25 = new Struct()
|
export const ScrcpyInjectScrollControlMessage1_25 =
|
||||||
.uint8("type", ScrcpyControlMessageType.InjectScroll as const)
|
/* #__PURE__ */
|
||||||
.uint32("pointerX")
|
new Struct()
|
||||||
.uint32("pointerY")
|
.uint8("type", ScrcpyControlMessageType.InjectScroll as const)
|
||||||
.uint16("screenWidth")
|
.uint32("pointerX")
|
||||||
.uint16("screenHeight")
|
.uint32("pointerY")
|
||||||
.field("scrollX", ScrcpySignedFloatFieldDefinition)
|
.uint16("screenWidth")
|
||||||
.field("scrollY", ScrcpySignedFloatFieldDefinition)
|
.uint16("screenHeight")
|
||||||
.int32("buttons");
|
.field("scrollX", ScrcpySignedFloatFieldDefinition)
|
||||||
|
.field("scrollY", ScrcpySignedFloatFieldDefinition)
|
||||||
|
.int32("buttons");
|
||||||
|
|
||||||
export type ScrcpyInjectScrollControlMessage1_25 =
|
export type ScrcpyInjectScrollControlMessage1_25 =
|
||||||
(typeof ScrcpyInjectScrollControlMessage1_25)["TInit"];
|
(typeof ScrcpyInjectScrollControlMessage1_25)["TInit"];
|
||||||
|
|
|
@ -30,17 +30,19 @@ import type {
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import { ScrcpyOptions } from "./types.js";
|
import { ScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export const ScrcpyInjectTouchControlMessage2_0 = new Struct()
|
export const ScrcpyInjectTouchControlMessage2_0 =
|
||||||
.uint8("type")
|
/* #__PURE__ */
|
||||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
new Struct()
|
||||||
.uint64("pointerId")
|
.uint8("type")
|
||||||
.uint32("pointerX")
|
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||||
.uint32("pointerY")
|
.uint64("pointerId")
|
||||||
.uint16("screenWidth")
|
.uint32("pointerX")
|
||||||
.uint16("screenHeight")
|
.uint32("pointerY")
|
||||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
.uint16("screenWidth")
|
||||||
.uint32("actionButton")
|
.uint16("screenHeight")
|
||||||
.uint32("buttons");
|
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||||
|
.uint32("actionButton")
|
||||||
|
.uint32("buttons");
|
||||||
|
|
||||||
export type ScrcpyInjectTouchControlMessage2_0 =
|
export type ScrcpyInjectTouchControlMessage2_0 =
|
||||||
(typeof ScrcpyInjectTouchControlMessage2_0)["TInit"];
|
(typeof ScrcpyInjectTouchControlMessage2_0)["TInit"];
|
||||||
|
|
|
@ -17,6 +17,121 @@ function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Consumable<T> {
|
export class Consumable<T> {
|
||||||
|
static readonly WritableStream = class WritableStream<
|
||||||
|
in T,
|
||||||
|
> extends NativeWritableStream<Consumable<T>> {
|
||||||
|
static async write<T>(
|
||||||
|
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
||||||
|
value: T,
|
||||||
|
) {
|
||||||
|
const consumable = new Consumable(value);
|
||||||
|
await writer.write(consumable);
|
||||||
|
await consumable.consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
sink: Consumable.WritableStreamSink<T>,
|
||||||
|
strategy?: QueuingStrategy<T>,
|
||||||
|
) {
|
||||||
|
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||||
|
if (strategy) {
|
||||||
|
wrappedStrategy = {};
|
||||||
|
if ("highWaterMark" in strategy) {
|
||||||
|
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||||
|
}
|
||||||
|
if ("size" in strategy) {
|
||||||
|
wrappedStrategy.size = (chunk) => {
|
||||||
|
return strategy.size!(
|
||||||
|
chunk instanceof Consumable ? chunk.value : chunk,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super(
|
||||||
|
{
|
||||||
|
start(controller) {
|
||||||
|
return sink.start?.(controller);
|
||||||
|
},
|
||||||
|
async write(chunk, controller) {
|
||||||
|
await chunk.tryConsume((chunk) =>
|
||||||
|
sink.write?.(chunk, controller),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
abort(reason) {
|
||||||
|
return sink.abort?.(reason);
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
return sink.close?.();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wrappedStrategy,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static readonly ReadableStream = class ReadableStream<
|
||||||
|
T,
|
||||||
|
> extends NativeReadableStream<Consumable<T>> {
|
||||||
|
static async enqueue<T>(
|
||||||
|
controller: { enqueue: (chunk: Consumable<T>) => void },
|
||||||
|
chunk: T,
|
||||||
|
) {
|
||||||
|
const output = new Consumable(chunk);
|
||||||
|
controller.enqueue(output);
|
||||||
|
await output.consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
source: Consumable.ReadableStreamSource<T>,
|
||||||
|
strategy?: QueuingStrategy<T>,
|
||||||
|
) {
|
||||||
|
let wrappedController:
|
||||||
|
| Consumable.ReadableStreamController<T>
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||||
|
if (strategy) {
|
||||||
|
wrappedStrategy = {};
|
||||||
|
if ("highWaterMark" in strategy) {
|
||||||
|
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||||
|
}
|
||||||
|
if ("size" in strategy) {
|
||||||
|
wrappedStrategy.size = (chunk) => {
|
||||||
|
return strategy.size!(chunk.value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super(
|
||||||
|
{
|
||||||
|
async start(controller) {
|
||||||
|
wrappedController = {
|
||||||
|
async enqueue(chunk) {
|
||||||
|
await ReadableStream.enqueue(controller, chunk);
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
controller.close();
|
||||||
|
},
|
||||||
|
error(reason) {
|
||||||
|
controller.error(reason);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await source.start?.(wrappedController);
|
||||||
|
},
|
||||||
|
async pull() {
|
||||||
|
await source.pull?.(wrappedController!);
|
||||||
|
},
|
||||||
|
async cancel(reason) {
|
||||||
|
await source.cancel?.(reason);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wrappedStrategy,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
readonly #task: Task;
|
readonly #task: Task;
|
||||||
readonly #resolver: PromiseResolver<void>;
|
readonly #resolver: PromiseResolver<void>;
|
||||||
|
|
||||||
|
@ -76,58 +191,7 @@ export namespace Consumable {
|
||||||
close?(): void | PromiseLike<void>;
|
close?(): void | PromiseLike<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WritableStream<in T> extends NativeWritableStream<
|
export type WritableStream<in T> = typeof Consumable.WritableStream<T>;
|
||||||
Consumable<T>
|
|
||||||
> {
|
|
||||||
static async write<T>(
|
|
||||||
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
|
||||||
value: T,
|
|
||||||
) {
|
|
||||||
const consumable = new Consumable(value);
|
|
||||||
await writer.write(consumable);
|
|
||||||
await consumable.consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
sink: WritableStreamSink<T>,
|
|
||||||
strategy?: QueuingStrategy<T>,
|
|
||||||
) {
|
|
||||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
||||||
if (strategy) {
|
|
||||||
wrappedStrategy = {};
|
|
||||||
if ("highWaterMark" in strategy) {
|
|
||||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
||||||
}
|
|
||||||
if ("size" in strategy) {
|
|
||||||
wrappedStrategy.size = (chunk) => {
|
|
||||||
return strategy.size!(
|
|
||||||
chunk instanceof Consumable ? chunk.value : chunk,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super(
|
|
||||||
{
|
|
||||||
start(controller) {
|
|
||||||
return sink.start?.(controller);
|
|
||||||
},
|
|
||||||
async write(chunk, controller) {
|
|
||||||
await chunk.tryConsume((chunk) =>
|
|
||||||
sink.write?.(chunk, controller),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
abort(reason) {
|
|
||||||
return sink.abort?.(reason);
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
return sink.close?.();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wrappedStrategy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReadableStreamController<T> {
|
export interface ReadableStreamController<T> {
|
||||||
enqueue(chunk: T): Promise<void>;
|
enqueue(chunk: T): Promise<void>;
|
||||||
|
@ -145,61 +209,5 @@ export namespace Consumable {
|
||||||
cancel?(reason: unknown): void | PromiseLike<void>;
|
cancel?(reason: unknown): void | PromiseLike<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReadableStream<T> extends NativeReadableStream<Consumable<T>> {
|
export type ReadableStream<T> = typeof Consumable.ReadableStream<T>;
|
||||||
static async enqueue<T>(
|
|
||||||
controller: { enqueue: (chunk: Consumable<T>) => void },
|
|
||||||
chunk: T,
|
|
||||||
) {
|
|
||||||
const output = new Consumable(chunk);
|
|
||||||
controller.enqueue(output);
|
|
||||||
await output.consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
source: ReadableStreamSource<T>,
|
|
||||||
strategy?: QueuingStrategy<T>,
|
|
||||||
) {
|
|
||||||
let wrappedController: ReadableStreamController<T> | undefined;
|
|
||||||
|
|
||||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
||||||
if (strategy) {
|
|
||||||
wrappedStrategy = {};
|
|
||||||
if ("highWaterMark" in strategy) {
|
|
||||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
||||||
}
|
|
||||||
if ("size" in strategy) {
|
|
||||||
wrappedStrategy.size = (chunk) => {
|
|
||||||
return strategy.size!(chunk.value);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super(
|
|
||||||
{
|
|
||||||
async start(controller) {
|
|
||||||
wrappedController = {
|
|
||||||
async enqueue(chunk) {
|
|
||||||
await ReadableStream.enqueue(controller, chunk);
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
controller.close();
|
|
||||||
},
|
|
||||||
error(reason) {
|
|
||||||
controller.error(reason);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
await source.start?.(wrappedController);
|
|
||||||
},
|
|
||||||
async pull() {
|
|
||||||
await source.pull?.(wrappedController!);
|
|
||||||
},
|
|
||||||
async cancel(reason) {
|
|
||||||
await source.cancel?.(reason);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wrappedStrategy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
90
libraries/stream-extra/src/maybe-consumable-ns.ts
Normal file
90
libraries/stream-extra/src/maybe-consumable-ns.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import { Consumable } from "./consumable.js";
|
||||||
|
import type { MaybeConsumable } from "./maybe-consumable.js";
|
||||||
|
import type {
|
||||||
|
QueuingStrategy,
|
||||||
|
WritableStreamDefaultController,
|
||||||
|
} from "./stream.js";
|
||||||
|
import {
|
||||||
|
WritableStream as NativeWritableStream,
|
||||||
|
TransformStream,
|
||||||
|
} from "./stream.js";
|
||||||
|
|
||||||
|
export function getValue<T>(value: MaybeConsumable<T>): T {
|
||||||
|
return value instanceof Consumable ? value.value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tryConsume<T, R>(
|
||||||
|
value: T,
|
||||||
|
callback: (value: T extends Consumable<infer U> ? U : T) => R,
|
||||||
|
): R {
|
||||||
|
if (value instanceof Consumable) {
|
||||||
|
return value.tryConsume(callback);
|
||||||
|
} else {
|
||||||
|
return callback(value as never);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnwrapStream<T> extends TransformStream<MaybeConsumable<T>, T> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
transform(chunk, controller) {
|
||||||
|
tryConsume(chunk, (chunk) => {
|
||||||
|
controller.enqueue(chunk as T);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WritableStreamSink<in T> {
|
||||||
|
start?(
|
||||||
|
controller: WritableStreamDefaultController,
|
||||||
|
): void | PromiseLike<void>;
|
||||||
|
write?(
|
||||||
|
chunk: T,
|
||||||
|
controller: WritableStreamDefaultController,
|
||||||
|
): void | PromiseLike<void>;
|
||||||
|
abort?(reason: unknown): void | PromiseLike<void>;
|
||||||
|
close?(): void | PromiseLike<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WritableStream<in T> extends NativeWritableStream<
|
||||||
|
MaybeConsumable<T>
|
||||||
|
> {
|
||||||
|
constructor(sink: WritableStreamSink<T>, strategy?: QueuingStrategy<T>) {
|
||||||
|
let wrappedStrategy: QueuingStrategy<MaybeConsumable<T>> | undefined;
|
||||||
|
if (strategy) {
|
||||||
|
wrappedStrategy = {};
|
||||||
|
if ("highWaterMark" in strategy) {
|
||||||
|
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||||
|
}
|
||||||
|
if ("size" in strategy) {
|
||||||
|
wrappedStrategy.size = (chunk) => {
|
||||||
|
return strategy.size!(
|
||||||
|
chunk instanceof Consumable ? chunk.value : chunk,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super(
|
||||||
|
{
|
||||||
|
start(controller) {
|
||||||
|
return sink.start?.(controller);
|
||||||
|
},
|
||||||
|
async write(chunk, controller) {
|
||||||
|
await tryConsume(chunk, (chunk) =>
|
||||||
|
sink.write?.(chunk as T, controller),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
abort(reason) {
|
||||||
|
return sink.abort?.(reason);
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
return sink.close?.();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wrappedStrategy,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,101 +1,5 @@
|
||||||
import { Consumable } from "./consumable.js";
|
import type { Consumable } from "./consumable.js";
|
||||||
import type {
|
|
||||||
QueuingStrategy,
|
|
||||||
WritableStreamDefaultController,
|
|
||||||
} from "./stream.js";
|
|
||||||
import {
|
|
||||||
WritableStream as NativeWritableStream,
|
|
||||||
TransformStream,
|
|
||||||
} from "./stream.js";
|
|
||||||
|
|
||||||
export type MaybeConsumable<T> = T | Consumable<T>;
|
export type MaybeConsumable<T> = T | Consumable<T>;
|
||||||
|
|
||||||
export namespace MaybeConsumable {
|
export * as MaybeConsumable from "./maybe-consumable-ns.js";
|
||||||
export function getValue<T>(value: MaybeConsumable<T>): T {
|
|
||||||
return value instanceof Consumable ? value.value : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function tryConsume<T, R>(
|
|
||||||
value: T,
|
|
||||||
callback: (value: T extends Consumable<infer U> ? U : T) => R,
|
|
||||||
): R {
|
|
||||||
if (value instanceof Consumable) {
|
|
||||||
return value.tryConsume(callback);
|
|
||||||
} else {
|
|
||||||
return callback(value as never);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UnwrapStream<T> extends TransformStream<
|
|
||||||
MaybeConsumable<T>,
|
|
||||||
T
|
|
||||||
> {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
transform(chunk, controller) {
|
|
||||||
MaybeConsumable.tryConsume(chunk, (chunk) => {
|
|
||||||
controller.enqueue(chunk as T);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WritableStreamSink<in T> {
|
|
||||||
start?(
|
|
||||||
controller: WritableStreamDefaultController,
|
|
||||||
): void | PromiseLike<void>;
|
|
||||||
write?(
|
|
||||||
chunk: T,
|
|
||||||
controller: WritableStreamDefaultController,
|
|
||||||
): void | PromiseLike<void>;
|
|
||||||
abort?(reason: unknown): void | PromiseLike<void>;
|
|
||||||
close?(): void | PromiseLike<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WritableStream<in T> extends NativeWritableStream<
|
|
||||||
MaybeConsumable<T>
|
|
||||||
> {
|
|
||||||
constructor(
|
|
||||||
sink: WritableStreamSink<T>,
|
|
||||||
strategy?: QueuingStrategy<T>,
|
|
||||||
) {
|
|
||||||
let wrappedStrategy:
|
|
||||||
| QueuingStrategy<MaybeConsumable<T>>
|
|
||||||
| undefined;
|
|
||||||
if (strategy) {
|
|
||||||
wrappedStrategy = {};
|
|
||||||
if ("highWaterMark" in strategy) {
|
|
||||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
||||||
}
|
|
||||||
if ("size" in strategy) {
|
|
||||||
wrappedStrategy.size = (chunk) => {
|
|
||||||
return strategy.size!(
|
|
||||||
chunk instanceof Consumable ? chunk.value : chunk,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super(
|
|
||||||
{
|
|
||||||
start(controller) {
|
|
||||||
return sink.start?.(controller);
|
|
||||||
},
|
|
||||||
async write(chunk, controller) {
|
|
||||||
await MaybeConsumable.tryConsume(chunk, (chunk) =>
|
|
||||||
sink.write?.(chunk as T, controller),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
abort(reason) {
|
|
||||||
return sink.abort?.(reason);
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
return sink.close?.();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wrappedStrategy,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,15 +32,13 @@ interface GlobalExtension {
|
||||||
TransformStream: typeof TransformStreamType;
|
TransformStream: typeof TransformStreamType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Global = globalThis as unknown as GlobalExtension;
|
|
||||||
|
|
||||||
export const AbortController = Global.AbortController;
|
|
||||||
|
|
||||||
export type ReadableStream<out T> = ReadableStreamType<T>;
|
export type ReadableStream<out T> = ReadableStreamType<T>;
|
||||||
export const ReadableStream = Global.ReadableStream;
|
|
||||||
|
|
||||||
export type WritableStream<in T> = WritableStreamType<T>;
|
export type WritableStream<in T> = WritableStreamType<T>;
|
||||||
export const WritableStream = Global.WritableStream;
|
|
||||||
|
|
||||||
export type TransformStream<I, O> = TransformStreamType<I, O>;
|
export type TransformStream<I, O> = TransformStreamType<I, O>;
|
||||||
export const TransformStream = Global.TransformStream;
|
|
||||||
|
export const {
|
||||||
|
AbortController,
|
||||||
|
ReadableStream,
|
||||||
|
WritableStream,
|
||||||
|
TransformStream,
|
||||||
|
} = globalThis as unknown as GlobalExtension;
|
||||||
|
|
|
@ -33,7 +33,7 @@ class MockDeserializationStream implements ExactReadable {
|
||||||
describe("Struct", () => {
|
describe("Struct", () => {
|
||||||
describe(".constructor", () => {
|
describe(".constructor", () => {
|
||||||
it("should initialize fields", () => {
|
it("should initialize fields", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
assert.deepStrictEqual(struct.options, StructDefaultOptions);
|
assert.deepStrictEqual(struct.options, StructDefaultOptions);
|
||||||
assert.strictEqual(struct.size, 0);
|
assert.strictEqual(struct.size, 0);
|
||||||
});
|
});
|
||||||
|
@ -82,7 +82,7 @@ describe("Struct", () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
it("should push a field and update size", () => {
|
it("should push a field and update size", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
|
|
||||||
const field1 = "foo";
|
const field1 = "foo";
|
||||||
const fieldDefinition1 = new MockFieldDefinition(4);
|
const fieldDefinition1 = new MockFieldDefinition(4);
|
||||||
|
@ -104,7 +104,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw an error if field name already exists", () => {
|
it("should throw an error if field name already exists", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
const fieldName = "foo";
|
const fieldName = "foo";
|
||||||
struct.field(fieldName, new MockFieldDefinition(4));
|
struct.field(fieldName, new MockFieldDefinition(4));
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
|
@ -115,7 +115,7 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#number", () => {
|
describe("#number", () => {
|
||||||
it("`int8` should append an `int8` field", () => {
|
it("`int8` should append an `int8` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.int8("foo");
|
struct.int8("foo");
|
||||||
assert.strictEqual(struct.size, 1);
|
assert.strictEqual(struct.size, 1);
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`uint8` should append an `uint8` field", () => {
|
it("`uint8` should append an `uint8` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.uint8("foo");
|
struct.uint8("foo");
|
||||||
assert.strictEqual(struct.size, 1);
|
assert.strictEqual(struct.size, 1);
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`int16` should append an `int16` field", () => {
|
it("`int16` should append an `int16` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.int16("foo");
|
struct.int16("foo");
|
||||||
assert.strictEqual(struct.size, 2);
|
assert.strictEqual(struct.size, 2);
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`uint16` should append an `uint16` field", () => {
|
it("`uint16` should append an `uint16` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.uint16("foo");
|
struct.uint16("foo");
|
||||||
assert.strictEqual(struct.size, 2);
|
assert.strictEqual(struct.size, 2);
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`int32` should append an `int32` field", () => {
|
it("`int32` should append an `int32` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.int32("foo");
|
struct.int32("foo");
|
||||||
assert.strictEqual(struct.size, 4);
|
assert.strictEqual(struct.size, 4);
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`uint32` should append an `uint32` field", () => {
|
it("`uint32` should append an `uint32` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.uint32("foo");
|
struct.uint32("foo");
|
||||||
assert.strictEqual(struct.size, 4);
|
assert.strictEqual(struct.size, 4);
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`int64` should append an `int64` field", () => {
|
it("`int64` should append an `int64` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.int64("foo");
|
struct.int64("foo");
|
||||||
assert.strictEqual(struct.size, 8);
|
assert.strictEqual(struct.size, 8);
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`uint64` should append an `uint64` field", () => {
|
it("`uint64` should append an `uint64` field", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.uint64("foo");
|
struct.uint64("foo");
|
||||||
assert.strictEqual(struct.size, 8);
|
assert.strictEqual(struct.size, 8);
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ describe("Struct", () => {
|
||||||
describe("#uint8ArrayLike", () => {
|
describe("#uint8ArrayLike", () => {
|
||||||
describe("FixedLengthBufferLikeFieldDefinition", () => {
|
describe("FixedLengthBufferLikeFieldDefinition", () => {
|
||||||
it("`#uint8Array` with fixed length", () => {
|
it("`#uint8Array` with fixed length", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.uint8Array("foo", { length: 10 });
|
struct.uint8Array("foo", { length: 10 });
|
||||||
assert.strictEqual(struct.size, 10);
|
assert.strictEqual(struct.size, 10);
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`#string` with fixed length", () => {
|
it("`#string` with fixed length", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
struct.string("foo", { length: 10 });
|
struct.string("foo", { length: 10 });
|
||||||
assert.strictEqual(struct.size, 10);
|
assert.strictEqual(struct.size, 10);
|
||||||
|
|
||||||
|
@ -233,7 +233,9 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("VariableLengthBufferLikeFieldDefinition", () => {
|
describe("VariableLengthBufferLikeFieldDefinition", () => {
|
||||||
it("`#uint8Array` with variable length", () => {
|
it("`#uint8Array` with variable length", () => {
|
||||||
const struct = new Struct().int8("barLength");
|
const struct = /* #__PURE__ */ new Struct().int8(
|
||||||
|
"barLength",
|
||||||
|
);
|
||||||
assert.strictEqual(struct.size, 1);
|
assert.strictEqual(struct.size, 1);
|
||||||
|
|
||||||
struct.uint8Array("bar", { lengthField: "barLength" });
|
struct.uint8Array("bar", { lengthField: "barLength" });
|
||||||
|
@ -255,7 +257,9 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("`#string` with variable length", () => {
|
it("`#string` with variable length", () => {
|
||||||
const struct = new Struct().int8("barLength");
|
const struct = /* #__PURE__ */ new Struct().int8(
|
||||||
|
"barLength",
|
||||||
|
);
|
||||||
assert.strictEqual(struct.size, 1);
|
assert.strictEqual(struct.size, 1);
|
||||||
|
|
||||||
struct.string("bar", { lengthField: "barLength" });
|
struct.string("bar", { lengthField: "barLength" });
|
||||||
|
@ -280,9 +284,11 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#concat", () => {
|
describe("#concat", () => {
|
||||||
it("should append all fields from other struct", () => {
|
it("should append all fields from other struct", () => {
|
||||||
const sub = new Struct().int16("int16").int32("int32");
|
const sub = /* #__PURE__ */ new Struct()
|
||||||
|
.int16("int16")
|
||||||
|
.int32("int32");
|
||||||
|
|
||||||
const struct = new Struct()
|
const struct = /* #__PURE__ */ new Struct()
|
||||||
.int8("int8")
|
.int8("int8")
|
||||||
.concat(sub)
|
.concat(sub)
|
||||||
.int64("int64");
|
.int64("int64");
|
||||||
|
@ -312,7 +318,9 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#deserialize", () => {
|
describe("#deserialize", () => {
|
||||||
it("should deserialize without dynamic size fields", () => {
|
it("should deserialize without dynamic size fields", () => {
|
||||||
const struct = new Struct().int8("foo").int16("bar");
|
const struct = /* #__PURE__ */ new Struct()
|
||||||
|
.int8("foo")
|
||||||
|
.int16("bar");
|
||||||
|
|
||||||
const stream = new MockDeserializationStream();
|
const stream = new MockDeserializationStream();
|
||||||
stream.readExactly.mock.mockImplementationOnce(
|
stream.readExactly.mock.mockImplementationOnce(
|
||||||
|
@ -339,7 +347,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should deserialize with dynamic size fields", () => {
|
it("should deserialize with dynamic size fields", () => {
|
||||||
const struct = new Struct()
|
const struct = /* #__PURE__ */ new Struct()
|
||||||
.int8("fooLength")
|
.int8("fooLength")
|
||||||
.uint8Array("foo", { lengthField: "fooLength" });
|
.uint8Array("foo", { lengthField: "fooLength" });
|
||||||
|
|
||||||
|
@ -376,7 +384,10 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#extra", () => {
|
describe("#extra", () => {
|
||||||
it("should accept plain field", () => {
|
it("should accept plain field", () => {
|
||||||
const struct = new Struct().extra({ foo: 42, bar: true });
|
const struct = /* #__PURE__ */ new Struct().extra({
|
||||||
|
foo: 42,
|
||||||
|
bar: true,
|
||||||
|
});
|
||||||
|
|
||||||
const stream = new MockDeserializationStream();
|
const stream = new MockDeserializationStream();
|
||||||
const result = struct.deserialize(stream);
|
const result = struct.deserialize(stream);
|
||||||
|
@ -411,7 +422,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should accept accessors", () => {
|
it("should accept accessors", () => {
|
||||||
const struct = new Struct().extra({
|
const struct = /* #__PURE__ */ new Struct().extra({
|
||||||
get foo() {
|
get foo() {
|
||||||
return 42;
|
return 42;
|
||||||
},
|
},
|
||||||
|
@ -438,7 +449,7 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#postDeserialize", () => {
|
describe("#postDeserialize", () => {
|
||||||
it("can throw errors", () => {
|
it("can throw errors", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
const callback = mock.fn(() => {
|
const callback = mock.fn(() => {
|
||||||
throw new Error("mock");
|
throw new Error("mock");
|
||||||
});
|
});
|
||||||
|
@ -450,7 +461,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can replace return value", () => {
|
it("can replace return value", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
const callback = mock.fn(() => "mock");
|
const callback = mock.fn(() => "mock");
|
||||||
struct.postDeserialize(callback);
|
struct.postDeserialize(callback);
|
||||||
|
|
||||||
|
@ -461,7 +472,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can return nothing", () => {
|
it("can return nothing", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
const callback = mock.fn();
|
const callback = mock.fn();
|
||||||
struct.postDeserialize(callback);
|
struct.postDeserialize(callback);
|
||||||
|
|
||||||
|
@ -473,7 +484,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should overwrite callback", () => {
|
it("should overwrite callback", () => {
|
||||||
const struct = new Struct();
|
const struct = /* #__PURE__ */ new Struct();
|
||||||
|
|
||||||
const callback1 = mock.fn();
|
const callback1 = mock.fn();
|
||||||
struct.postDeserialize(callback1);
|
struct.postDeserialize(callback1);
|
||||||
|
@ -492,7 +503,9 @@ describe("Struct", () => {
|
||||||
|
|
||||||
describe("#serialize", () => {
|
describe("#serialize", () => {
|
||||||
it("should serialize without dynamic size fields", () => {
|
it("should serialize without dynamic size fields", () => {
|
||||||
const struct = new Struct().int8("foo").int16("bar");
|
const struct = /* #__PURE__ */ new Struct()
|
||||||
|
.int8("foo")
|
||||||
|
.int16("bar");
|
||||||
|
|
||||||
const result = new Uint8Array(
|
const result = new Uint8Array(
|
||||||
struct.serialize({ foo: 0x42, bar: 0x1024 }),
|
struct.serialize({ foo: 0x42, bar: 0x1024 }),
|
||||||
|
@ -505,7 +518,7 @@ describe("Struct", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should serialize with dynamic size fields", () => {
|
it("should serialize with dynamic size fields", () => {
|
||||||
const struct = new Struct()
|
const struct = /* #__PURE__ */ new Struct()
|
||||||
.int8("fooLength")
|
.int8("fooLength")
|
||||||
.uint8Array("foo", { lengthField: "fooLength" });
|
.uint8Array("foo", { lengthField: "fooLength" });
|
||||||
|
|
||||||
|
|
|
@ -82,9 +82,10 @@ interface GlobalExtension {
|
||||||
|
|
||||||
const { TextEncoder, TextDecoder } = globalThis as unknown as GlobalExtension;
|
const { TextEncoder, TextDecoder } = globalThis as unknown as GlobalExtension;
|
||||||
|
|
||||||
const SharedEncoder = new TextEncoder();
|
const SharedEncoder = /* #__PURE__ */ new TextEncoder();
|
||||||
const SharedDecoder = new TextDecoder();
|
const SharedDecoder = /* #__PURE__ */ new TextDecoder();
|
||||||
|
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
export function encodeUtf8(input: string): Uint8Array {
|
export function encodeUtf8(input: string): Uint8Array {
|
||||||
return SharedEncoder.encode(input);
|
return SharedEncoder.encode(input);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue