Loading libraries/adb/src/adb.ts +8 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ export class Adb implements Closeable { ): Promise<Adb> { // Initially, set to highest-supported version and payload size. let version = 0x01000001; // Android 4: 4K, Android 7: 256K, Android 9: 1M let maxPayloadSize = 0x100000; const resolver = new PromiseResolver<string>(); Loading Loading @@ -167,11 +168,16 @@ export class Adb implements Closeable { return this.dispatcher.disconnected; } private _protocolVersion: number | undefined; private _protocolVersion: number; public get protocolVersion() { return this._protocolVersion; } private _maxPayloadSize: number; public get maxPayloadSize() { return this._maxPayloadSize; } private _product: string | undefined; public get product() { return this._product; Loading Loading @@ -222,6 +228,7 @@ export class Adb implements Closeable { }); this._protocolVersion = version; this._maxPayloadSize = maxPayloadSize; this.subprocess = new AdbSubprocess(this); this.power = new AdbPower(this); Loading libraries/adb/src/commands/sync/index.ts +1 −0 Original line number Diff line number Diff line Loading @@ -3,5 +3,6 @@ export * from "./pull.js"; export * from "./push.js"; export * from "./request.js"; export * from "./response.js"; export * from "./socket.js"; export * from "./stat.js"; export * from "./sync.js"; libraries/adb/src/commands/sync/list.ts +38 −16 Original line number Diff line number Diff line import type { BufferedReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; import type { AdbSyncStat } from "./stat.js"; import { AdbSyncLstatResponse, AdbSyncStatResponse } from "./stat.js"; Loading @@ -31,16 +28,15 @@ export const AdbSyncEntry2Response = new Struct({ littleEndian: true }) export type AdbSyncEntry2Response = (typeof AdbSyncEntry2Response)["TDeserializeResult"]; export async function* adbSyncOpenDir( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, path: string, v2: boolean ): AsyncGenerator<AdbSyncEntry, void, void> { if (v2) { await adbSyncWriteRequest(writer, AdbSyncRequestId.List2, path); export async function* adbSyncOpenDirV2( socket: AdbSyncSocket, path: string ): AsyncGenerator<AdbSyncEntry2Response, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List2, path); for await (const item of adbSyncReadResponses( stream, locked, AdbSyncResponseId.Entry2, AdbSyncEntry2Response )) { Loading @@ -52,13 +48,39 @@ export async function* adbSyncOpenDir( } yield item; } } else { await adbSyncWriteRequest(writer, AdbSyncRequestId.List, path); } finally { locked.release(); } } export async function* adbSyncOpenDirV1( socket: AdbSyncSocket, path: string ): AsyncGenerator<AdbSyncEntryResponse, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List, path); for await (const item of adbSyncReadResponses( stream, locked, AdbSyncResponseId.Entry, AdbSyncEntryResponse )) { yield item; } } finally { locked.release(); } } export async function* adbSyncOpenDir( socket: AdbSyncSocket, path: string, v2: boolean ): AsyncGenerator<AdbSyncEntry, void, void> { if (v2) { yield* adbSyncOpenDirV2(socket, path); } else { for await (const item of adbSyncOpenDirV1(socket, path)) { // Convert to same format as `AdbSyncEntry2Response` for easier consumption. // However it will add some overhead. yield { Loading libraries/adb/src/commands/sync/pull.ts +39 −44 Original line number Diff line number Diff line import type { BufferedReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import { ReadableStream } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra"; import { PushReadableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; export const AdbSyncDataResponse = new Struct({ littleEndian: true }) .uint32("dataLength") Loading @@ -16,47 +14,44 @@ export const AdbSyncDataResponse = new Struct({ littleEndian: true }) export type AdbSyncDataResponse = (typeof AdbSyncDataResponse)["TDeserializeResult"]; export function adbSyncPull( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, export async function* adbSyncPullGenerator( socket: AdbSyncSocket, path: string ): ReadableStream<Uint8Array> { let generator!: AsyncGenerator<AdbSyncDataResponse, void, void>; return new ReadableStream<Uint8Array>( { async start() { // TODO: If `ReadableStream.from(AsyncGenerator)` is added to spec, use it instead. await adbSyncWriteRequest( writer, AdbSyncRequestId.Receive, path ); generator = adbSyncReadResponses( stream, ): AsyncGenerator<Uint8Array, void, void> { const locked = await socket.lock(); let done = false; try { await adbSyncWriteRequest(locked, AdbSyncRequestId.Receive, path); for await (const packet of adbSyncReadResponses( locked, AdbSyncResponseId.Data, AdbSyncDataResponse ); }, async pull(controller) { const { done, value } = await generator.next(); if (done) { controller.close(); return; )) { yield packet.data; } controller.enqueue(value.data); }, cancel() { generator.return().catch((e) => { void e; }); throw new Error(`Sync commands can't be canceled.`); }, }, { highWaterMark: 16 * 1024, size(chunk) { return chunk.byteLength; }, done = true; } finally { if (!done) { // sync pull can't be cancelled, so we have to read all data for await (const packet of adbSyncReadResponses( locked, AdbSyncResponseId.Data, AdbSyncDataResponse )) { void packet; } } locked.release(); } ); } export function adbSyncPull( socket: AdbSyncSocket, path: string ): ReadableStream<Uint8Array> { return new PushReadableStream(async (controller) => { for await (const data of adbSyncPullGenerator(socket, path)) { await controller.enqueue(data); } }); } libraries/adb/src/commands/sync/push.ts +27 −18 Original line number Diff line number Diff line import type { BufferedReadableStream, ReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra"; import { ChunkStream, WritableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; import { LinuxFileType } from "./stat.js"; export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( Loading @@ -17,25 +14,37 @@ export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024; export async function adbSyncPush( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, socket: AdbSyncSocket, filename: string, file: ReadableStream<Uint8Array>, mode: number = (LinuxFileType.File << 12) | 0o666, mtime: number = (Date.now() / 1000) | 0, packetSize: number = ADB_SYNC_MAX_PACKET_SIZE ) { const locked = await socket.lock(); try { const pathAndMode = `${filename},${mode.toString()}`; await adbSyncWriteRequest(writer, AdbSyncRequestId.Send, pathAndMode); await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode); await file.pipeThrough(new ChunkStream(packetSize)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk); await adbSyncWriteRequest( locked, AdbSyncRequestId.Data, chunk ); }, }) ); await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse(stream, AdbSyncResponseId.Ok, AdbSyncOkResponse); await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse( locked, AdbSyncResponseId.Ok, AdbSyncOkResponse ); } finally { locked.release(); } } Loading
libraries/adb/src/adb.ts +8 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ export class Adb implements Closeable { ): Promise<Adb> { // Initially, set to highest-supported version and payload size. let version = 0x01000001; // Android 4: 4K, Android 7: 256K, Android 9: 1M let maxPayloadSize = 0x100000; const resolver = new PromiseResolver<string>(); Loading Loading @@ -167,11 +168,16 @@ export class Adb implements Closeable { return this.dispatcher.disconnected; } private _protocolVersion: number | undefined; private _protocolVersion: number; public get protocolVersion() { return this._protocolVersion; } private _maxPayloadSize: number; public get maxPayloadSize() { return this._maxPayloadSize; } private _product: string | undefined; public get product() { return this._product; Loading Loading @@ -222,6 +228,7 @@ export class Adb implements Closeable { }); this._protocolVersion = version; this._maxPayloadSize = maxPayloadSize; this.subprocess = new AdbSubprocess(this); this.power = new AdbPower(this); Loading
libraries/adb/src/commands/sync/index.ts +1 −0 Original line number Diff line number Diff line Loading @@ -3,5 +3,6 @@ export * from "./pull.js"; export * from "./push.js"; export * from "./request.js"; export * from "./response.js"; export * from "./socket.js"; export * from "./stat.js"; export * from "./sync.js";
libraries/adb/src/commands/sync/list.ts +38 −16 Original line number Diff line number Diff line import type { BufferedReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; import type { AdbSyncStat } from "./stat.js"; import { AdbSyncLstatResponse, AdbSyncStatResponse } from "./stat.js"; Loading @@ -31,16 +28,15 @@ export const AdbSyncEntry2Response = new Struct({ littleEndian: true }) export type AdbSyncEntry2Response = (typeof AdbSyncEntry2Response)["TDeserializeResult"]; export async function* adbSyncOpenDir( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, path: string, v2: boolean ): AsyncGenerator<AdbSyncEntry, void, void> { if (v2) { await adbSyncWriteRequest(writer, AdbSyncRequestId.List2, path); export async function* adbSyncOpenDirV2( socket: AdbSyncSocket, path: string ): AsyncGenerator<AdbSyncEntry2Response, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List2, path); for await (const item of adbSyncReadResponses( stream, locked, AdbSyncResponseId.Entry2, AdbSyncEntry2Response )) { Loading @@ -52,13 +48,39 @@ export async function* adbSyncOpenDir( } yield item; } } else { await adbSyncWriteRequest(writer, AdbSyncRequestId.List, path); } finally { locked.release(); } } export async function* adbSyncOpenDirV1( socket: AdbSyncSocket, path: string ): AsyncGenerator<AdbSyncEntryResponse, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List, path); for await (const item of adbSyncReadResponses( stream, locked, AdbSyncResponseId.Entry, AdbSyncEntryResponse )) { yield item; } } finally { locked.release(); } } export async function* adbSyncOpenDir( socket: AdbSyncSocket, path: string, v2: boolean ): AsyncGenerator<AdbSyncEntry, void, void> { if (v2) { yield* adbSyncOpenDirV2(socket, path); } else { for await (const item of adbSyncOpenDirV1(socket, path)) { // Convert to same format as `AdbSyncEntry2Response` for easier consumption. // However it will add some overhead. yield { Loading
libraries/adb/src/commands/sync/pull.ts +39 −44 Original line number Diff line number Diff line import type { BufferedReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import { ReadableStream } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra"; import { PushReadableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; export const AdbSyncDataResponse = new Struct({ littleEndian: true }) .uint32("dataLength") Loading @@ -16,47 +14,44 @@ export const AdbSyncDataResponse = new Struct({ littleEndian: true }) export type AdbSyncDataResponse = (typeof AdbSyncDataResponse)["TDeserializeResult"]; export function adbSyncPull( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, export async function* adbSyncPullGenerator( socket: AdbSyncSocket, path: string ): ReadableStream<Uint8Array> { let generator!: AsyncGenerator<AdbSyncDataResponse, void, void>; return new ReadableStream<Uint8Array>( { async start() { // TODO: If `ReadableStream.from(AsyncGenerator)` is added to spec, use it instead. await adbSyncWriteRequest( writer, AdbSyncRequestId.Receive, path ); generator = adbSyncReadResponses( stream, ): AsyncGenerator<Uint8Array, void, void> { const locked = await socket.lock(); let done = false; try { await adbSyncWriteRequest(locked, AdbSyncRequestId.Receive, path); for await (const packet of adbSyncReadResponses( locked, AdbSyncResponseId.Data, AdbSyncDataResponse ); }, async pull(controller) { const { done, value } = await generator.next(); if (done) { controller.close(); return; )) { yield packet.data; } controller.enqueue(value.data); }, cancel() { generator.return().catch((e) => { void e; }); throw new Error(`Sync commands can't be canceled.`); }, }, { highWaterMark: 16 * 1024, size(chunk) { return chunk.byteLength; }, done = true; } finally { if (!done) { // sync pull can't be cancelled, so we have to read all data for await (const packet of adbSyncReadResponses( locked, AdbSyncResponseId.Data, AdbSyncDataResponse )) { void packet; } } locked.release(); } ); } export function adbSyncPull( socket: AdbSyncSocket, path: string ): ReadableStream<Uint8Array> { return new PushReadableStream(async (controller) => { for await (const data of adbSyncPullGenerator(socket, path)) { await controller.enqueue(data); } }); }
libraries/adb/src/commands/sync/push.ts +27 −18 Original line number Diff line number Diff line import type { BufferedReadableStream, ReadableStream, WritableStreamDefaultWriter, } from "@yume-chan/stream-extra"; import type { ReadableStream } from "@yume-chan/stream-extra"; import { ChunkStream, WritableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js"; import type { AdbSyncSocket } from "./socket.js"; import { LinuxFileType } from "./stat.js"; export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( Loading @@ -17,25 +14,37 @@ export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024; export async function adbSyncPush( stream: BufferedReadableStream, writer: WritableStreamDefaultWriter<Uint8Array>, socket: AdbSyncSocket, filename: string, file: ReadableStream<Uint8Array>, mode: number = (LinuxFileType.File << 12) | 0o666, mtime: number = (Date.now() / 1000) | 0, packetSize: number = ADB_SYNC_MAX_PACKET_SIZE ) { const locked = await socket.lock(); try { const pathAndMode = `${filename},${mode.toString()}`; await adbSyncWriteRequest(writer, AdbSyncRequestId.Send, pathAndMode); await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode); await file.pipeThrough(new ChunkStream(packetSize)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest(writer, AdbSyncRequestId.Data, chunk); await adbSyncWriteRequest( locked, AdbSyncRequestId.Data, chunk ); }, }) ); await adbSyncWriteRequest(writer, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse(stream, AdbSyncResponseId.Ok, AdbSyncOkResponse); await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse( locked, AdbSyncResponseId.Ok, AdbSyncOkResponse ); } finally { locked.release(); } }