Loading libraries/adb/src/adb.ts +1 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ export class Adb implements Closeable { // Initially, set to highest-supported version and payload size. let version = 0x01000001; // Android 4: 4K, Android 7: 256K, Android 9: 1M let maxPayloadSize = 0x100000; let maxPayloadSize = 1024 * 1024; const resolver = new PromiseResolver<string>(); const authProcessor = new AdbAuthenticationProcessor( Loading libraries/adb/src/commands/sync/list.ts +1 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ export async function* adbSyncOpenDirV2( ): AsyncGenerator<AdbSyncEntry2Response, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List2, path); await adbSyncWriteRequest(locked, AdbSyncRequestId.ListV2, path); for await (const item of adbSyncReadResponses( locked, AdbSyncResponseId.Entry2, Loading libraries/adb/src/commands/sync/push.ts +84 −3 Original line number Diff line number Diff line import type { ReadableStream } from "@yume-chan/stream-extra"; import { ChunkStream, WritableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import Struct, { placeholder } from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js"; Loading @@ -13,7 +13,7 @@ export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024; export async function adbSyncPush( export async function adbSyncPushV1( socket: AdbSyncSocket, filename: string, file: ReadableStream<Uint8Array>, Loading @@ -26,7 +26,7 @@ export async function adbSyncPush( const pathAndMode = `${filename},${mode.toString()}`; await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode); await file.pipeThrough(new ChunkStream(packetSize)).pipeTo( await file.pipeThrough(new ChunkStream(packetSize, true)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest( Loading @@ -48,3 +48,84 @@ export async function adbSyncPush( locked.release(); } } export enum AdbSyncSendV2Flags { None = 0, Brotli = 1, /** * 2 */ Lz4 = 1 << 1, /** * 4 */ Zstd = 1 << 2, /** * 0x80000000 */ DryRun = (1 << 31) >>> 0, } export const AdbSyncSendV2Request = new Struct({ littleEndian: true }) .uint32("id", placeholder<AdbSyncRequestId>()) .uint32("mode") .uint32("flags", placeholder<AdbSyncSendV2Flags>()); export async function adbSyncPushV2( 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 { await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename); await locked.write( AdbSyncSendV2Request.serialize({ id: AdbSyncRequestId.SendV2, mode, flags: 0, }) ); await file.pipeThrough(new ChunkStream(packetSize, true)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest( locked, AdbSyncRequestId.Data, chunk ); }, }) ); await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse( locked, AdbSyncResponseId.Ok, AdbSyncOkResponse ); } finally { locked.release(); } } export function adbSyncPush( v2: boolean, 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 ) { if (v2) { return adbSyncPushV2(socket, filename, file, mode, mtime, packetSize); } else { return adbSyncPushV1(socket, filename, file, mode, mtime, packetSize); } } libraries/adb/src/commands/sync/request.ts +3 −2 Original line number Diff line number Diff line Loading @@ -4,11 +4,12 @@ import { encodeUtf8 } from "../../utils/index.js"; export enum AdbSyncRequestId { List = "LIST", List2 = "LIS2", ListV2 = "LIS2", Send = "SEND", SendV2 = "SND2", Lstat = "STAT", Stat = "STA2", Lstat2 = "LST2", LstatV2 = "LST2", Data = "DATA", Done = "DONE", Receive = "RECV", Loading libraries/adb/src/commands/sync/socket.ts +40 −14 Original line number Diff line number Diff line Loading @@ -25,11 +25,15 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { this._lock = lock; } public async flush() { public async flush(hard: boolean) { if (this._bufferedLength === 0) { return; } if (!hard && this._bufferedLength < this._bufferSize) { return; } if (this._buffered.length === 1) { await this._writer.write(this._buffered[0]!); this._buffered.length = 0; Loading @@ -37,6 +41,7 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { return; } if (hard) { const data = new Uint8Array(this._bufferedLength); let offset = 0; for (const chunk of this._buffered) { Loading @@ -47,18 +52,39 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { this._bufferedLength = 0; // Let AdbSocket chunk the data for us await this._writer.write(data); } else { while (this._bufferedLength >= this._bufferSize) { const data = new Uint8Array(this._bufferSize); let offset = 0; let available = this._bufferSize; while (offset < this._bufferSize) { const chunk = this._buffered[0]!; if (chunk.byteLength <= available) { data.set(chunk, offset); offset += chunk.byteLength; available -= chunk.byteLength; this._buffered.shift(); this._bufferedLength -= chunk.byteLength; } else { data.set(chunk.subarray(0, available), offset); this._buffered[0] = chunk.subarray(available); this._bufferedLength -= available; break; } } await this._writer.write(data); } } } public async write(data: Uint8Array) { this._buffered.push(data); this._bufferedLength += data.byteLength; if (this._bufferedLength >= this._bufferSize) { await this.flush(); } await this.flush(false); } public async read(length: number) { await this.flush(); await this.flush(true); return await this._readable.read(length); } Loading Loading
libraries/adb/src/adb.ts +1 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ export class Adb implements Closeable { // Initially, set to highest-supported version and payload size. let version = 0x01000001; // Android 4: 4K, Android 7: 256K, Android 9: 1M let maxPayloadSize = 0x100000; let maxPayloadSize = 1024 * 1024; const resolver = new PromiseResolver<string>(); const authProcessor = new AdbAuthenticationProcessor( Loading
libraries/adb/src/commands/sync/list.ts +1 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ export async function* adbSyncOpenDirV2( ): AsyncGenerator<AdbSyncEntry2Response, void, void> { const locked = await socket.lock(); try { await adbSyncWriteRequest(locked, AdbSyncRequestId.List2, path); await adbSyncWriteRequest(locked, AdbSyncRequestId.ListV2, path); for await (const item of adbSyncReadResponses( locked, AdbSyncResponseId.Entry2, Loading
libraries/adb/src/commands/sync/push.ts +84 −3 Original line number Diff line number Diff line import type { ReadableStream } from "@yume-chan/stream-extra"; import { ChunkStream, WritableStream } from "@yume-chan/stream-extra"; import Struct from "@yume-chan/struct"; import Struct, { placeholder } from "@yume-chan/struct"; import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js"; import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js"; Loading @@ -13,7 +13,7 @@ export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32( export const ADB_SYNC_MAX_PACKET_SIZE = 64 * 1024; export async function adbSyncPush( export async function adbSyncPushV1( socket: AdbSyncSocket, filename: string, file: ReadableStream<Uint8Array>, Loading @@ -26,7 +26,7 @@ export async function adbSyncPush( const pathAndMode = `${filename},${mode.toString()}`; await adbSyncWriteRequest(locked, AdbSyncRequestId.Send, pathAndMode); await file.pipeThrough(new ChunkStream(packetSize)).pipeTo( await file.pipeThrough(new ChunkStream(packetSize, true)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest( Loading @@ -48,3 +48,84 @@ export async function adbSyncPush( locked.release(); } } export enum AdbSyncSendV2Flags { None = 0, Brotli = 1, /** * 2 */ Lz4 = 1 << 1, /** * 4 */ Zstd = 1 << 2, /** * 0x80000000 */ DryRun = (1 << 31) >>> 0, } export const AdbSyncSendV2Request = new Struct({ littleEndian: true }) .uint32("id", placeholder<AdbSyncRequestId>()) .uint32("mode") .uint32("flags", placeholder<AdbSyncSendV2Flags>()); export async function adbSyncPushV2( 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 { await adbSyncWriteRequest(locked, AdbSyncRequestId.SendV2, filename); await locked.write( AdbSyncSendV2Request.serialize({ id: AdbSyncRequestId.SendV2, mode, flags: 0, }) ); await file.pipeThrough(new ChunkStream(packetSize, true)).pipeTo( new WritableStream({ write: async (chunk) => { await adbSyncWriteRequest( locked, AdbSyncRequestId.Data, chunk ); }, }) ); await adbSyncWriteRequest(locked, AdbSyncRequestId.Done, mtime); await adbSyncReadResponse( locked, AdbSyncResponseId.Ok, AdbSyncOkResponse ); } finally { locked.release(); } } export function adbSyncPush( v2: boolean, 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 ) { if (v2) { return adbSyncPushV2(socket, filename, file, mode, mtime, packetSize); } else { return adbSyncPushV1(socket, filename, file, mode, mtime, packetSize); } }
libraries/adb/src/commands/sync/request.ts +3 −2 Original line number Diff line number Diff line Loading @@ -4,11 +4,12 @@ import { encodeUtf8 } from "../../utils/index.js"; export enum AdbSyncRequestId { List = "LIST", List2 = "LIS2", ListV2 = "LIS2", Send = "SEND", SendV2 = "SND2", Lstat = "STAT", Stat = "STA2", Lstat2 = "LST2", LstatV2 = "LST2", Data = "DATA", Done = "DONE", Receive = "RECV", Loading
libraries/adb/src/commands/sync/socket.ts +40 −14 Original line number Diff line number Diff line Loading @@ -25,11 +25,15 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { this._lock = lock; } public async flush() { public async flush(hard: boolean) { if (this._bufferedLength === 0) { return; } if (!hard && this._bufferedLength < this._bufferSize) { return; } if (this._buffered.length === 1) { await this._writer.write(this._buffered[0]!); this._buffered.length = 0; Loading @@ -37,6 +41,7 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { return; } if (hard) { const data = new Uint8Array(this._bufferedLength); let offset = 0; for (const chunk of this._buffered) { Loading @@ -47,18 +52,39 @@ export class AdbSyncSocketLocked implements StructAsyncDeserializeStream { this._bufferedLength = 0; // Let AdbSocket chunk the data for us await this._writer.write(data); } else { while (this._bufferedLength >= this._bufferSize) { const data = new Uint8Array(this._bufferSize); let offset = 0; let available = this._bufferSize; while (offset < this._bufferSize) { const chunk = this._buffered[0]!; if (chunk.byteLength <= available) { data.set(chunk, offset); offset += chunk.byteLength; available -= chunk.byteLength; this._buffered.shift(); this._bufferedLength -= chunk.byteLength; } else { data.set(chunk.subarray(0, available), offset); this._buffered[0] = chunk.subarray(available); this._bufferedLength -= available; break; } } await this._writer.write(data); } } } public async write(data: Uint8Array) { this._buffered.push(data); this._bufferedLength += data.byteLength; if (this._bufferedLength >= this._bufferSize) { await this.flush(); } await this.flush(false); } public async read(length: number) { await this.flush(); await this.flush(true); return await this._readable.read(length); } Loading