Loading libraries/adb-server-node-tcp/src/index.ts +9 −10 Original line number Original line Diff line number Diff line import type { AddressInfo, SocketConnectOpts } from "net"; import type { AddressInfo, SocketConnectOpts } from "net"; import { Server, Socket } from "net"; import { Server, Socket } from "net"; import type { import type { AdbIncomingSocketHandler, AdbServerClient } from "@yume-chan/adb"; AdbIncomingSocketHandler, AdbServerConnection, AdbServerConnectionOptions, AdbServerConnector, } from "@yume-chan/adb"; import { import { MaybeConsumable, MaybeConsumable, PushReadableStream, PushReadableStream, Loading @@ -15,7 +10,9 @@ import { } from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra"; import type { ValueOrPromise } from "@yume-chan/struct"; import type { ValueOrPromise } from "@yume-chan/struct"; function nodeSocketToConnection(socket: Socket): AdbServerConnection { function nodeSocketToConnection( socket: Socket, ): AdbServerClient.ServerConnection { socket.setNoDelay(true); socket.setNoDelay(true); const closed = new Promise<void>((resolve) => { const closed = new Promise<void>((resolve) => { Loading Loading @@ -64,7 +61,9 @@ function nodeSocketToConnection(socket: Socket): AdbServerConnection { }; }; } } export class AdbServerNodeTcpConnector implements AdbServerConnector { export class AdbServerNodeTcpConnector implements AdbServerClient.ServerConnector { readonly spec: SocketConnectOpts; readonly spec: SocketConnectOpts; readonly #listeners = new Map<string, Server>(); readonly #listeners = new Map<string, Server>(); Loading @@ -74,8 +73,8 @@ export class AdbServerNodeTcpConnector implements AdbServerConnector { } } async connect( async connect( { unref }: AdbServerConnectionOptions = { unref: false }, { unref }: AdbServerClient.ServerConnectionOptions = { unref: false }, ): Promise<AdbServerConnection> { ): Promise<AdbServerClient.ServerConnection> { const socket = new Socket(); const socket = new Socket(); if (unref) { if (unref) { socket.unref(); socket.unref(); Loading libraries/adb/src/server/client.ts +98 −65 Original line number Original line Diff line number Diff line Loading @@ -27,52 +27,6 @@ import { NOOP, hexToNumber, write4HexDigits } from "../utils/index.js"; import { AdbServerTransport } from "./transport.js"; import { AdbServerTransport } from "./transport.js"; export interface AdbServerConnectionOptions { unref?: boolean | undefined; signal?: AbortSignal | undefined; } export interface AdbServerConnection extends ReadableWritablePair<Uint8Array, Uint8Array>, Closeable { get closed(): Promise<void>; } export interface AdbServerConnector { connect( options?: AdbServerConnectionOptions, ): ValueOrPromise<AdbServerConnection>; addReverseTunnel( handler: AdbIncomingSocketHandler, address?: string, ): ValueOrPromise<string>; removeReverseTunnel(address: string): ValueOrPromise<void>; clearReverseTunnels(): ValueOrPromise<void>; } export interface AdbServerSocket extends AdbSocket { transportId: bigint; } export type AdbServerDeviceSelector = | { transportId: bigint } | { serial: string } | { usb: true } | { tcp: true } | undefined; export interface AdbServerDevice { serial: string; authenticating: boolean; product?: string | undefined; model?: string | undefined; device?: string | undefined; transportId: bigint; } function sequenceEqual(a: Uint8Array, b: Uint8Array): boolean { function sequenceEqual(a: Uint8Array, b: Uint8Array): boolean { if (a.length !== b.length) { if (a.length !== b.length) { return false; return false; Loading @@ -91,11 +45,11 @@ const OKAY = encodeUtf8("OKAY"); const FAIL = encodeUtf8("FAIL"); const FAIL = encodeUtf8("FAIL"); class AdbServerStream { class AdbServerStream { #connection: AdbServerConnection; #connection: AdbServerClient.ServerConnection; #buffered: BufferedReadableStream; #buffered: BufferedReadableStream; #writer: WritableStreamDefaultWriter<Uint8Array>; #writer: WritableStreamDefaultWriter<Uint8Array>; constructor(connection: AdbServerConnection) { constructor(connection: AdbServerClient.ServerConnection) { this.#connection = connection; this.#connection = connection; this.#buffered = new BufferedReadableStream(connection.readable); this.#buffered = new BufferedReadableStream(connection.readable); this.#writer = connection.writable.getWriter(); this.#writer = connection.writable.getWriter(); Loading Loading @@ -191,15 +145,15 @@ class AdbServerStream { export class AdbServerClient { export class AdbServerClient { static readonly VERSION = 41; static readonly VERSION = 41; readonly connection: AdbServerConnector; readonly connection: AdbServerClient.ServerConnector; constructor(connection: AdbServerConnector) { constructor(connection: AdbServerClient.ServerConnector) { this.connection = connection; this.connection = connection; } } async createConnection( async createConnection( request: string, request: string, options?: AdbServerConnectionOptions, options?: AdbServerClient.ServerConnectionOptions, ): Promise<AdbServerStream> { ): Promise<AdbServerStream> { const connection = await this.connection.connect(options); const connection = await this.connection.connect(options); const stream = new AdbServerStream(connection); const stream = new AdbServerStream(connection); Loading Loading @@ -326,8 +280,8 @@ export class AdbServerClient { } } } } parseDeviceList(value: string): AdbServerDevice[] { parseDeviceList(value: string): AdbServerClient.Device[] { const devices: AdbServerDevice[] = []; const devices: AdbServerClient.Device[] = []; for (const line of value.split("\n")) { for (const line of value.split("\n")) { if (!line) { if (!line) { continue; continue; Loading Loading @@ -379,7 +333,7 @@ export class AdbServerClient { /** /** * `adb devices -l` * `adb devices -l` */ */ async getDevices(): Promise<AdbServerDevice[]> { async getDevices(): Promise<AdbServerClient.Device[]> { const connection = await this.createConnection("host:devices-l"); const connection = await this.createConnection("host:devices-l"); try { try { const response = await connection.readString(); const response = await connection.readString(); Loading @@ -398,7 +352,7 @@ export class AdbServerClient { */ */ async *trackDevices( async *trackDevices( signal?: AbortSignal, signal?: AbortSignal, ): AsyncGenerator<AdbServerDevice[], void, void> { ): AsyncGenerator<AdbServerClient.Device[], void, void> { const connection = await this.createConnection("host:track-devices-l"); const connection = await this.createConnection("host:track-devices-l"); try { try { while (true) { while (true) { Loading @@ -418,7 +372,40 @@ export class AdbServerClient { } } } } formatDeviceService(device: AdbServerDeviceSelector, command: string) { async mDnsCheck() { const connection = await this.createConnection("host:mdns:check"); try { const response = await connection.readString(); return !response.startsWith("ERROR:"); } finally { await connection.dispose(); } } async mDnsGetServices() { const connection = await this.createConnection("host:mdns:services"); try { const response = await connection.readString(); return response .split("\n") .filter(Boolean) .map((line) => { const parts = line.split("\t"); return { name: parts[0]!, service: parts[1]!, address: parts[2]!, }; }); } finally { await connection.dispose(); } } formatDeviceService( device: AdbServerClient.DeviceSelector, command: string, ) { if (!device) { if (!device) { return `host:${command}`; return `host:${command}`; } } Loading @@ -440,7 +427,7 @@ export class AdbServerClient { /** /** * `adb -s <device> reconnect` or `adb reconnect offline` * `adb -s <device> reconnect` or `adb reconnect offline` */ */ async reconnectDevice(device: AdbServerDeviceSelector | "offline") { async reconnectDevice(device: AdbServerClient.DeviceSelector | "offline") { const connection = await this.createConnection( const connection = await this.createConnection( device === "offline" device === "offline" ? "host:reconnect-offline" ? "host:reconnect-offline" Loading @@ -461,7 +448,7 @@ export class AdbServerClient { * @returns The transport ID of the selected device, and the features supported by the device. * @returns The transport ID of the selected device, and the features supported by the device. */ */ async getDeviceFeatures( async getDeviceFeatures( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, ): Promise<{ transportId: bigint; features: AdbFeature[] }> { ): Promise<{ transportId: bigint; features: AdbFeature[] }> { // On paper, `host:features` is a host service (device features are cached in host), // On paper, `host:features` is a host service (device features are cached in host), // so it shouldn't use `createDeviceConnection`, // so it shouldn't use `createDeviceConnection`, Loading @@ -483,7 +470,7 @@ export class AdbServerClient { device, device, "host:features", "host:features", ); ); // Luckily `AdbServerSocket` is compatible with `AdbServerConnection` // Luckily `AdbServerClient.Socket` is compatible with `AdbServerClient.ServerConnection` const stream = new AdbServerStream(connection); const stream = new AdbServerStream(connection); try { try { const featuresString = await stream.readString(); const featuresString = await stream.readString(); Loading @@ -498,12 +485,12 @@ export class AdbServerClient { * Creates a connection that will forward the service to device. * Creates a connection that will forward the service to device. * @param device The device selector * @param device The device selector * @param service The service to forward * @param service The service to forward * @returns An `AdbServerSocket` that can be used to communicate with the service * @returns An `AdbServerClient.Socket` that can be used to communicate with the service */ */ async createDeviceConnection( async createDeviceConnection( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, service: string, service: string, ): Promise<AdbServerSocket> { ): Promise<AdbServerClient.Socket> { await this.validateVersion(); await this.validateVersion(); let switchService: string; let switchService: string; Loading Loading @@ -573,9 +560,9 @@ export class AdbServerClient { * @returns A promise that resolves when the condition is met. * @returns A promise that resolves when the condition is met. */ */ async waitFor( async waitFor( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, state: "device" | "disconnect", state: "device" | "disconnect", options?: AdbServerConnectionOptions, options?: AdbServerClient.ServerConnectionOptions, ): Promise<void> { ): Promise<void> { let type: string; let type: string; if (!device) { if (!device) { Loading Loading @@ -608,7 +595,7 @@ export class AdbServerClient { } } async createTransport( async createTransport( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, ): Promise<AdbServerTransport> { ): Promise<AdbServerTransport> { const { transportId, features } = await this.getDeviceFeatures(device); const { transportId, features } = await this.getDeviceFeatures(device); Loading Loading @@ -665,6 +652,52 @@ export async function raceSignal<T>( } } export namespace AdbServerClient { export namespace AdbServerClient { export interface ServerConnectionOptions { unref?: boolean | undefined; signal?: AbortSignal | undefined; } export interface ServerConnection extends ReadableWritablePair<Uint8Array, Uint8Array>, Closeable { get closed(): Promise<void>; } export interface ServerConnector { connect( options?: ServerConnectionOptions, ): ValueOrPromise<ServerConnection>; addReverseTunnel( handler: AdbIncomingSocketHandler, address?: string, ): ValueOrPromise<string>; removeReverseTunnel(address: string): ValueOrPromise<void>; clearReverseTunnels(): ValueOrPromise<void>; } export interface Socket extends AdbSocket { transportId: bigint; } export type DeviceSelector = | { transportId: bigint } | { serial: string } | { usb: true } | { tcp: true } | undefined; export interface Device { serial: string; authenticating: boolean; product?: string | undefined; model?: string | undefined; device?: string | undefined; transportId: bigint; } export class NetworkError extends Error { export class NetworkError extends Error { constructor(message: string) { constructor(message: string) { super(message); super(message); Loading Loading
libraries/adb-server-node-tcp/src/index.ts +9 −10 Original line number Original line Diff line number Diff line import type { AddressInfo, SocketConnectOpts } from "net"; import type { AddressInfo, SocketConnectOpts } from "net"; import { Server, Socket } from "net"; import { Server, Socket } from "net"; import type { import type { AdbIncomingSocketHandler, AdbServerClient } from "@yume-chan/adb"; AdbIncomingSocketHandler, AdbServerConnection, AdbServerConnectionOptions, AdbServerConnector, } from "@yume-chan/adb"; import { import { MaybeConsumable, MaybeConsumable, PushReadableStream, PushReadableStream, Loading @@ -15,7 +10,9 @@ import { } from "@yume-chan/stream-extra"; } from "@yume-chan/stream-extra"; import type { ValueOrPromise } from "@yume-chan/struct"; import type { ValueOrPromise } from "@yume-chan/struct"; function nodeSocketToConnection(socket: Socket): AdbServerConnection { function nodeSocketToConnection( socket: Socket, ): AdbServerClient.ServerConnection { socket.setNoDelay(true); socket.setNoDelay(true); const closed = new Promise<void>((resolve) => { const closed = new Promise<void>((resolve) => { Loading Loading @@ -64,7 +61,9 @@ function nodeSocketToConnection(socket: Socket): AdbServerConnection { }; }; } } export class AdbServerNodeTcpConnector implements AdbServerConnector { export class AdbServerNodeTcpConnector implements AdbServerClient.ServerConnector { readonly spec: SocketConnectOpts; readonly spec: SocketConnectOpts; readonly #listeners = new Map<string, Server>(); readonly #listeners = new Map<string, Server>(); Loading @@ -74,8 +73,8 @@ export class AdbServerNodeTcpConnector implements AdbServerConnector { } } async connect( async connect( { unref }: AdbServerConnectionOptions = { unref: false }, { unref }: AdbServerClient.ServerConnectionOptions = { unref: false }, ): Promise<AdbServerConnection> { ): Promise<AdbServerClient.ServerConnection> { const socket = new Socket(); const socket = new Socket(); if (unref) { if (unref) { socket.unref(); socket.unref(); Loading
libraries/adb/src/server/client.ts +98 −65 Original line number Original line Diff line number Diff line Loading @@ -27,52 +27,6 @@ import { NOOP, hexToNumber, write4HexDigits } from "../utils/index.js"; import { AdbServerTransport } from "./transport.js"; import { AdbServerTransport } from "./transport.js"; export interface AdbServerConnectionOptions { unref?: boolean | undefined; signal?: AbortSignal | undefined; } export interface AdbServerConnection extends ReadableWritablePair<Uint8Array, Uint8Array>, Closeable { get closed(): Promise<void>; } export interface AdbServerConnector { connect( options?: AdbServerConnectionOptions, ): ValueOrPromise<AdbServerConnection>; addReverseTunnel( handler: AdbIncomingSocketHandler, address?: string, ): ValueOrPromise<string>; removeReverseTunnel(address: string): ValueOrPromise<void>; clearReverseTunnels(): ValueOrPromise<void>; } export interface AdbServerSocket extends AdbSocket { transportId: bigint; } export type AdbServerDeviceSelector = | { transportId: bigint } | { serial: string } | { usb: true } | { tcp: true } | undefined; export interface AdbServerDevice { serial: string; authenticating: boolean; product?: string | undefined; model?: string | undefined; device?: string | undefined; transportId: bigint; } function sequenceEqual(a: Uint8Array, b: Uint8Array): boolean { function sequenceEqual(a: Uint8Array, b: Uint8Array): boolean { if (a.length !== b.length) { if (a.length !== b.length) { return false; return false; Loading @@ -91,11 +45,11 @@ const OKAY = encodeUtf8("OKAY"); const FAIL = encodeUtf8("FAIL"); const FAIL = encodeUtf8("FAIL"); class AdbServerStream { class AdbServerStream { #connection: AdbServerConnection; #connection: AdbServerClient.ServerConnection; #buffered: BufferedReadableStream; #buffered: BufferedReadableStream; #writer: WritableStreamDefaultWriter<Uint8Array>; #writer: WritableStreamDefaultWriter<Uint8Array>; constructor(connection: AdbServerConnection) { constructor(connection: AdbServerClient.ServerConnection) { this.#connection = connection; this.#connection = connection; this.#buffered = new BufferedReadableStream(connection.readable); this.#buffered = new BufferedReadableStream(connection.readable); this.#writer = connection.writable.getWriter(); this.#writer = connection.writable.getWriter(); Loading Loading @@ -191,15 +145,15 @@ class AdbServerStream { export class AdbServerClient { export class AdbServerClient { static readonly VERSION = 41; static readonly VERSION = 41; readonly connection: AdbServerConnector; readonly connection: AdbServerClient.ServerConnector; constructor(connection: AdbServerConnector) { constructor(connection: AdbServerClient.ServerConnector) { this.connection = connection; this.connection = connection; } } async createConnection( async createConnection( request: string, request: string, options?: AdbServerConnectionOptions, options?: AdbServerClient.ServerConnectionOptions, ): Promise<AdbServerStream> { ): Promise<AdbServerStream> { const connection = await this.connection.connect(options); const connection = await this.connection.connect(options); const stream = new AdbServerStream(connection); const stream = new AdbServerStream(connection); Loading Loading @@ -326,8 +280,8 @@ export class AdbServerClient { } } } } parseDeviceList(value: string): AdbServerDevice[] { parseDeviceList(value: string): AdbServerClient.Device[] { const devices: AdbServerDevice[] = []; const devices: AdbServerClient.Device[] = []; for (const line of value.split("\n")) { for (const line of value.split("\n")) { if (!line) { if (!line) { continue; continue; Loading Loading @@ -379,7 +333,7 @@ export class AdbServerClient { /** /** * `adb devices -l` * `adb devices -l` */ */ async getDevices(): Promise<AdbServerDevice[]> { async getDevices(): Promise<AdbServerClient.Device[]> { const connection = await this.createConnection("host:devices-l"); const connection = await this.createConnection("host:devices-l"); try { try { const response = await connection.readString(); const response = await connection.readString(); Loading @@ -398,7 +352,7 @@ export class AdbServerClient { */ */ async *trackDevices( async *trackDevices( signal?: AbortSignal, signal?: AbortSignal, ): AsyncGenerator<AdbServerDevice[], void, void> { ): AsyncGenerator<AdbServerClient.Device[], void, void> { const connection = await this.createConnection("host:track-devices-l"); const connection = await this.createConnection("host:track-devices-l"); try { try { while (true) { while (true) { Loading @@ -418,7 +372,40 @@ export class AdbServerClient { } } } } formatDeviceService(device: AdbServerDeviceSelector, command: string) { async mDnsCheck() { const connection = await this.createConnection("host:mdns:check"); try { const response = await connection.readString(); return !response.startsWith("ERROR:"); } finally { await connection.dispose(); } } async mDnsGetServices() { const connection = await this.createConnection("host:mdns:services"); try { const response = await connection.readString(); return response .split("\n") .filter(Boolean) .map((line) => { const parts = line.split("\t"); return { name: parts[0]!, service: parts[1]!, address: parts[2]!, }; }); } finally { await connection.dispose(); } } formatDeviceService( device: AdbServerClient.DeviceSelector, command: string, ) { if (!device) { if (!device) { return `host:${command}`; return `host:${command}`; } } Loading @@ -440,7 +427,7 @@ export class AdbServerClient { /** /** * `adb -s <device> reconnect` or `adb reconnect offline` * `adb -s <device> reconnect` or `adb reconnect offline` */ */ async reconnectDevice(device: AdbServerDeviceSelector | "offline") { async reconnectDevice(device: AdbServerClient.DeviceSelector | "offline") { const connection = await this.createConnection( const connection = await this.createConnection( device === "offline" device === "offline" ? "host:reconnect-offline" ? "host:reconnect-offline" Loading @@ -461,7 +448,7 @@ export class AdbServerClient { * @returns The transport ID of the selected device, and the features supported by the device. * @returns The transport ID of the selected device, and the features supported by the device. */ */ async getDeviceFeatures( async getDeviceFeatures( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, ): Promise<{ transportId: bigint; features: AdbFeature[] }> { ): Promise<{ transportId: bigint; features: AdbFeature[] }> { // On paper, `host:features` is a host service (device features are cached in host), // On paper, `host:features` is a host service (device features are cached in host), // so it shouldn't use `createDeviceConnection`, // so it shouldn't use `createDeviceConnection`, Loading @@ -483,7 +470,7 @@ export class AdbServerClient { device, device, "host:features", "host:features", ); ); // Luckily `AdbServerSocket` is compatible with `AdbServerConnection` // Luckily `AdbServerClient.Socket` is compatible with `AdbServerClient.ServerConnection` const stream = new AdbServerStream(connection); const stream = new AdbServerStream(connection); try { try { const featuresString = await stream.readString(); const featuresString = await stream.readString(); Loading @@ -498,12 +485,12 @@ export class AdbServerClient { * Creates a connection that will forward the service to device. * Creates a connection that will forward the service to device. * @param device The device selector * @param device The device selector * @param service The service to forward * @param service The service to forward * @returns An `AdbServerSocket` that can be used to communicate with the service * @returns An `AdbServerClient.Socket` that can be used to communicate with the service */ */ async createDeviceConnection( async createDeviceConnection( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, service: string, service: string, ): Promise<AdbServerSocket> { ): Promise<AdbServerClient.Socket> { await this.validateVersion(); await this.validateVersion(); let switchService: string; let switchService: string; Loading Loading @@ -573,9 +560,9 @@ export class AdbServerClient { * @returns A promise that resolves when the condition is met. * @returns A promise that resolves when the condition is met. */ */ async waitFor( async waitFor( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, state: "device" | "disconnect", state: "device" | "disconnect", options?: AdbServerConnectionOptions, options?: AdbServerClient.ServerConnectionOptions, ): Promise<void> { ): Promise<void> { let type: string; let type: string; if (!device) { if (!device) { Loading Loading @@ -608,7 +595,7 @@ export class AdbServerClient { } } async createTransport( async createTransport( device: AdbServerDeviceSelector, device: AdbServerClient.DeviceSelector, ): Promise<AdbServerTransport> { ): Promise<AdbServerTransport> { const { transportId, features } = await this.getDeviceFeatures(device); const { transportId, features } = await this.getDeviceFeatures(device); Loading Loading @@ -665,6 +652,52 @@ export async function raceSignal<T>( } } export namespace AdbServerClient { export namespace AdbServerClient { export interface ServerConnectionOptions { unref?: boolean | undefined; signal?: AbortSignal | undefined; } export interface ServerConnection extends ReadableWritablePair<Uint8Array, Uint8Array>, Closeable { get closed(): Promise<void>; } export interface ServerConnector { connect( options?: ServerConnectionOptions, ): ValueOrPromise<ServerConnection>; addReverseTunnel( handler: AdbIncomingSocketHandler, address?: string, ): ValueOrPromise<string>; removeReverseTunnel(address: string): ValueOrPromise<void>; clearReverseTunnels(): ValueOrPromise<void>; } export interface Socket extends AdbSocket { transportId: bigint; } export type DeviceSelector = | { transportId: bigint } | { serial: string } | { usb: true } | { tcp: true } | undefined; export interface Device { serial: string; authenticating: boolean; product?: string | undefined; model?: string | undefined; device?: string | undefined; transportId: bigint; } export class NetworkError extends Error { export class NetworkError extends Error { constructor(message: string) { constructor(message: string) { super(message); super(message); Loading