mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-06 03:50:18 +02:00
chore: format code
This commit is contained in:
parent
0046c76ee1
commit
19ee58ce29
12 changed files with 122 additions and 51 deletions
|
@ -1,5 +1,3 @@
|
||||||
// cspell: ignore libusb
|
|
||||||
|
|
||||||
import { PromiseResolver } from "@yume-chan/async";
|
import { PromiseResolver } from "@yume-chan/async";
|
||||||
import {
|
import {
|
||||||
AbortController,
|
AbortController,
|
||||||
|
@ -269,6 +267,10 @@ export class Adb implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public supportsFeature(feature: AdbFeatures): boolean {
|
||||||
|
return this._features.includes(feature);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a handler for incoming socket.
|
* Add a handler for incoming socket.
|
||||||
* @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
|
* @param handler A function to call with new incoming sockets. It must return `true` if it accepts the socket.
|
||||||
|
|
|
@ -97,9 +97,9 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
||||||
const [publicKeyBase64Length] =
|
const [publicKeyBase64Length] =
|
||||||
calculateBase64EncodedLength(publicKeyLength);
|
calculateBase64EncodedLength(publicKeyLength);
|
||||||
|
|
||||||
// The public key is null terminated,
|
const publicKeyBuffer = new Uint8Array(
|
||||||
// So we allocate the buffer with one extra byte.
|
publicKeyBase64Length + 1 // Null character
|
||||||
const publicKeyBuffer = new Uint8Array(publicKeyBase64Length + 1);
|
);
|
||||||
|
|
||||||
calculatePublicKey(privateKey, publicKeyBuffer);
|
calculatePublicKey(privateKey, publicKeyBuffer);
|
||||||
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
||||||
|
|
|
@ -69,6 +69,6 @@ export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
||||||
case 2:
|
case 2:
|
||||||
return AdbFrameBufferV2.deserialize(stream);
|
return AdbFrameBufferV2.deserialize(stream);
|
||||||
default:
|
default:
|
||||||
throw new Error("Unknown FrameBuffer version");
|
throw new Error("Unsupported FrameBuffer version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,16 +14,22 @@ import { type AdbSubprocessProtocol } from "./types.js";
|
||||||
* * `resize`: No
|
* * `resize`: No
|
||||||
*/
|
*/
|
||||||
export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
||||||
public static isSupported() { return true; }
|
public static isSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static async pty(adb: Adb, command: string) {
|
public static async pty(adb: Adb, command: string) {
|
||||||
return new AdbSubprocessNoneProtocol(await adb.createSocket(`shell:${command}`));
|
return new AdbSubprocessNoneProtocol(
|
||||||
|
await adb.createSocket(`shell:${command}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async raw(adb: Adb, command: string) {
|
public static async raw(adb: Adb, command: string) {
|
||||||
// `shell,raw:${command}` also triggers raw mode,
|
// `shell,raw:${command}` also triggers raw mode,
|
||||||
// But is not supported on Android version <7.
|
// But is not supported on Android version <7.
|
||||||
return new AdbSubprocessNoneProtocol(await adb.createSocket(`exec:${command}`));
|
return new AdbSubprocessNoneProtocol(
|
||||||
|
await adb.createSocket(`exec:${command}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly socket: AdbSocket;
|
private readonly socket: AdbSocket;
|
||||||
|
@ -31,22 +37,30 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
||||||
private readonly duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
|
private readonly duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
|
||||||
|
|
||||||
// Legacy shell forwards all data to stdin.
|
// Legacy shell forwards all data to stdin.
|
||||||
public get stdin() { return this.socket.writable; }
|
public get stdin() {
|
||||||
|
return this.socket.writable;
|
||||||
|
}
|
||||||
|
|
||||||
private _stdout: ReadableStream<Uint8Array>;
|
private _stdout: ReadableStream<Uint8Array>;
|
||||||
/**
|
/**
|
||||||
* Legacy shell mixes stdout and stderr.
|
* Legacy shell mixes stdout and stderr.
|
||||||
*/
|
*/
|
||||||
public get stdout() { return this._stdout; }
|
public get stdout() {
|
||||||
|
return this._stdout;
|
||||||
|
}
|
||||||
|
|
||||||
private _stderr: ReadableStream<Uint8Array>;
|
private _stderr: ReadableStream<Uint8Array>;
|
||||||
/**
|
/**
|
||||||
* `stderr` will always be empty.
|
* `stderr` will always be empty.
|
||||||
*/
|
*/
|
||||||
public get stderr() { return this._stderr; }
|
public get stderr() {
|
||||||
|
return this._stderr;
|
||||||
|
}
|
||||||
|
|
||||||
private _exit: Promise<number>;
|
private _exit: Promise<number>;
|
||||||
public get exit() { return this._exit; }
|
public get exit() {
|
||||||
|
return this._exit;
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(socket: AdbSocket) {
|
public constructor(socket: AdbSocket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
|
|
@ -13,9 +13,9 @@ import {
|
||||||
import Struct, { placeholder, type StructValueType } from '@yume-chan/struct';
|
import Struct, { placeholder, type StructValueType } from '@yume-chan/struct';
|
||||||
|
|
||||||
import { type Adb } from "../../../adb.js";
|
import { type Adb } from "../../../adb.js";
|
||||||
import { AdbFeatures } from '../../../features.js';
|
import { AdbFeatures } from "../../../features.js";
|
||||||
import { type AdbSocket } from "../../../socket/index.js";
|
import { type AdbSocket } from "../../../socket/index.js";
|
||||||
import { encodeUtf8 } from '../../../utils/index.js';
|
import { encodeUtf8 } from "../../../utils/index.js";
|
||||||
|
|
||||||
import { type AdbSubprocessProtocol } from "./types.js";
|
import { type AdbSubprocessProtocol } from "./types.js";
|
||||||
|
|
||||||
|
@ -29,17 +29,19 @@ export enum AdbShellProtocolId {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This packet format is used in both direction.
|
// This packet format is used in both direction.
|
||||||
const AdbShellProtocolPacket =
|
const AdbShellProtocolPacket = new Struct({ littleEndian: true })
|
||||||
new Struct({ littleEndian: true })
|
.uint8("id", placeholder<AdbShellProtocolId>())
|
||||||
.uint8('id', placeholder<AdbShellProtocolId>())
|
.uint32("length")
|
||||||
.uint32('length')
|
.uint8Array("data", { lengthField: "length" });
|
||||||
.uint8Array('data', { lengthField: 'length' });
|
|
||||||
|
|
||||||
type AdbShellProtocolPacketInit = typeof AdbShellProtocolPacket['TInit'];
|
type AdbShellProtocolPacketInit = typeof AdbShellProtocolPacket["TInit"];
|
||||||
|
|
||||||
type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
|
type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
|
||||||
|
|
||||||
class StdinSerializeStream extends TransformStream<Uint8Array, AdbShellProtocolPacketInit>{
|
class StdinSerializeStream extends TransformStream<
|
||||||
|
Uint8Array,
|
||||||
|
AdbShellProtocolPacketInit
|
||||||
|
> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
transform(chunk, controller) {
|
transform(chunk, controller) {
|
||||||
|
@ -50,12 +52,15 @@ class StdinSerializeStream extends TransformStream<Uint8Array, AdbShellProtocolP
|
||||||
},
|
},
|
||||||
flush() {
|
flush() {
|
||||||
// TODO: AdbShellSubprocessProtocol: support closing stdin
|
// TODO: AdbShellSubprocessProtocol: support closing stdin
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StdoutDeserializeStream extends TransformStream<AdbShellProtocolPacket, Uint8Array>{
|
class StdoutDeserializeStream extends TransformStream<
|
||||||
|
AdbShellProtocolPacket,
|
||||||
|
Uint8Array
|
||||||
|
> {
|
||||||
constructor(type: AdbShellProtocolId.Stdout | AdbShellProtocolId.Stderr) {
|
constructor(type: AdbShellProtocolId.Stdout | AdbShellProtocolId.Stderr) {
|
||||||
super({
|
super({
|
||||||
transform(chunk, controller) {
|
transform(chunk, controller) {
|
||||||
|
@ -116,7 +121,7 @@ class MultiplexStream<T> {
|
||||||
*/
|
*/
|
||||||
export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
||||||
public static isSupported(adb: Adb) {
|
public static isSupported(adb: Adb) {
|
||||||
return adb.features.includes(AdbFeatures.ShellV2);
|
return adb.supportsFeature(AdbFeatures.ShellV2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async pty(adb: Adb, command: string) {
|
public static async pty(adb: Adb, command: string) {
|
||||||
|
|
|
@ -46,21 +46,21 @@ export class AdbSync extends AutoDisposable {
|
||||||
protected sendLock = this.addDisposable(new AutoResetEvent());
|
protected sendLock = this.addDisposable(new AutoResetEvent());
|
||||||
|
|
||||||
public get supportsStat(): boolean {
|
public get supportsStat(): boolean {
|
||||||
return this.adb.features.includes(AdbFeatures.StatV2);
|
return this.adb.supportsFeature(AdbFeatures.StatV2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get supportsList2(): boolean {
|
public get supportsList2(): boolean {
|
||||||
return this.adb.features.includes(AdbFeatures.ListV2);
|
return this.adb.supportsFeature(AdbFeatures.ListV2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get fixedPushMkdir(): boolean {
|
public get fixedPushMkdir(): boolean {
|
||||||
return this.adb.features.includes(AdbFeatures.FixedPushMkdir);
|
return this.adb.supportsFeature(AdbFeatures.FixedPushMkdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get needPushMkdirWorkaround(): boolean {
|
public get needPushMkdirWorkaround(): boolean {
|
||||||
// https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
|
// https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
|
||||||
return (
|
return (
|
||||||
this.adb.features.includes(AdbFeatures.ShellV2) &&
|
this.adb.supportsFeature(AdbFeatures.ShellV2) &&
|
||||||
!this.fixedPushMkdir
|
!this.fixedPushMkdir
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export class AdbSync extends AutoDisposable {
|
||||||
this.supportsStat
|
this.supportsStat
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
this.sendLock.notify();
|
this.sendLock.notifyOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ export class AdbSync extends AutoDisposable {
|
||||||
try {
|
try {
|
||||||
return adbSyncStat(this.stream, this.writer, path);
|
return adbSyncStat(this.stream, this.writer, path);
|
||||||
} finally {
|
} finally {
|
||||||
this.sendLock.notify();
|
this.sendLock.notifyOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ export class AdbSync extends AutoDisposable {
|
||||||
this.supportsList2
|
this.supportsList2
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
this.sendLock.notify();
|
this.sendLock.notifyOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ export class AdbSync extends AutoDisposable {
|
||||||
return adbSyncPull(this.stream, this.writer, filename);
|
return adbSyncPull(this.stream, this.writer, filename);
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
this.sendLock.notify();
|
this.sendLock.notifyOne();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ export class AdbSync extends AutoDisposable {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
this.sendLock.notify();
|
this.sendLock.notifyOne();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,40 +2,39 @@ import { PromiseResolver } from "@yume-chan/async";
|
||||||
import { type Disposable } from "@yume-chan/event";
|
import { type Disposable } from "@yume-chan/event";
|
||||||
|
|
||||||
export class AutoResetEvent implements Disposable {
|
export class AutoResetEvent implements Disposable {
|
||||||
private readonly list: PromiseResolver<void>[] = [];
|
private _set: boolean;
|
||||||
|
private readonly _queue: PromiseResolver<void>[] = [];
|
||||||
private blocking: boolean;
|
|
||||||
|
|
||||||
public constructor(initialSet = false) {
|
public constructor(initialSet = false) {
|
||||||
this.blocking = initialSet;
|
this._set = initialSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public wait(): Promise<void> {
|
public wait(): Promise<void> {
|
||||||
if (!this.blocking) {
|
if (!this._set) {
|
||||||
this.blocking = true;
|
this._set = true;
|
||||||
|
|
||||||
if (this.list.length === 0) {
|
if (this._queue.length === 0) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = new PromiseResolver<void>();
|
const resolver = new PromiseResolver<void>();
|
||||||
this.list.push(resolver);
|
this._queue.push(resolver);
|
||||||
return resolver.promise;
|
return resolver.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public notify() {
|
public notifyOne() {
|
||||||
if (this.list.length !== 0) {
|
if (this._queue.length !== 0) {
|
||||||
this.list.pop()!.resolve();
|
this._queue.pop()!.resolve();
|
||||||
} else {
|
} else {
|
||||||
this.blocking = false;
|
this._set = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose() {
|
public dispose() {
|
||||||
for (const item of this.list) {
|
for (const item of this._queue) {
|
||||||
item.reject(new Error("The AutoResetEvent has been disposed"));
|
item.reject(new Error("The AutoResetEvent has been disposed"));
|
||||||
}
|
}
|
||||||
this.list.length = 0;
|
this._queue.length = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
libraries/adb/src/utils/conditional-variable.ts
Normal file
45
libraries/adb/src/utils/conditional-variable.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { PromiseResolver } from "@yume-chan/async";
|
||||||
|
import { type Disposable } from "@yume-chan/event";
|
||||||
|
|
||||||
|
interface WaitEntry {
|
||||||
|
condition: () => boolean;
|
||||||
|
resolver: PromiseResolver<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConditionalVariable implements Disposable {
|
||||||
|
private _locked = false;
|
||||||
|
private readonly _queue: WaitEntry[] = [];
|
||||||
|
|
||||||
|
public wait(condition: () => boolean): Promise<void> {
|
||||||
|
if (!this._locked) {
|
||||||
|
this._locked = true;
|
||||||
|
if (this._queue.length === 0 && condition()) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolver = new PromiseResolver<void>();
|
||||||
|
this._queue.push({ condition, resolver });
|
||||||
|
return resolver.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public notifyOne() {
|
||||||
|
const entry = this._queue.shift();
|
||||||
|
if (entry) {
|
||||||
|
if (entry.condition()) {
|
||||||
|
entry.resolver.resolve();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
for (const item of this._queue) {
|
||||||
|
item.resolver.reject(
|
||||||
|
new Error("The ConditionalVariable has been disposed")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this._queue.length = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
export { decodeUtf8, encodeUtf8 } from '@yume-chan/struct';
|
export { decodeUtf8, encodeUtf8 } from '@yume-chan/struct';
|
||||||
export * from './auto-reset-event.js';
|
export * from './auto-reset-event.js';
|
||||||
export * from './base64.js';
|
export * from './base64.js';
|
||||||
|
export * from "./conditional-variable.js";
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// cspell: ignore systemui
|
// cspell: ignore systemui
|
||||||
// cspell: ignore sysui
|
// cspell: ignore sysui
|
||||||
|
|
||||||
import { type Adb, AdbCommandBase } from "@yume-chan/adb";
|
import { AdbCommandBase, type Adb } from "@yume-chan/adb";
|
||||||
|
|
||||||
import { Settings } from "./settings.js";
|
import { Settings } from "./settings.js";
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { type Adb } from "@yume-chan/adb";
|
||||||
|
|
||||||
import { type ScrcpyOptionsInit1_22 } from "../../options/index.js";
|
import { type ScrcpyOptionsInit1_22 } from "../../options/index.js";
|
||||||
import {
|
import {
|
||||||
type AdbScrcpyConnection,
|
|
||||||
AdbScrcpyForwardConnection,
|
AdbScrcpyForwardConnection,
|
||||||
AdbScrcpyReverseConnection,
|
AdbScrcpyReverseConnection,
|
||||||
|
type AdbScrcpyConnection,
|
||||||
} from "../connection.js";
|
} from "../connection.js";
|
||||||
|
|
||||||
import { AdbScrcpyOptions1_16 } from "./1_16.js";
|
import { AdbScrcpyOptions1_16 } from "./1_16.js";
|
||||||
|
|
|
@ -18,8 +18,12 @@ export class BufferedReadableStream {
|
||||||
private bufferedOffset = 0;
|
private bufferedOffset = 0;
|
||||||
private bufferedLength = 0;
|
private bufferedLength = 0;
|
||||||
|
|
||||||
protected readonly stream: ReadableStream<Uint8Array>;
|
private _position = 0;
|
||||||
|
public get position() {
|
||||||
|
return this._position;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly stream: ReadableStream<Uint8Array>;
|
||||||
protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
|
protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
|
||||||
|
|
||||||
public constructor(stream: ReadableStream<Uint8Array>) {
|
public constructor(stream: ReadableStream<Uint8Array>) {
|
||||||
|
@ -32,6 +36,7 @@ export class BufferedReadableStream {
|
||||||
if (done) {
|
if (done) {
|
||||||
throw new BufferedReadableStreamEndedError();
|
throw new BufferedReadableStreamEndedError();
|
||||||
}
|
}
|
||||||
|
this._position += value.byteLength;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue