mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 09:49:24 +02:00
feat(adb): add pair device and connect device commands to server client mode
This commit is contained in:
parent
f5e1a2b701
commit
a6e3f0e5d1
2 changed files with 75 additions and 11 deletions
|
@ -176,7 +176,7 @@ export class AdbServerClient {
|
||||||
throw new Error(`Unexpected response: ${decodeUtf8(response)}`);
|
throw new Error(`Unexpected response: ${decodeUtf8(response)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(
|
async createConnection(
|
||||||
request: string,
|
request: string,
|
||||||
options?: AdbServerConnectionOptions,
|
options?: AdbServerConnectionOptions,
|
||||||
): Promise<AdbServerConnection> {
|
): Promise<AdbServerConnection> {
|
||||||
|
@ -219,7 +219,7 @@ export class AdbServerClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVersion(): Promise<number> {
|
async getVersion(): Promise<number> {
|
||||||
const connection = await this.connect("host:version");
|
const connection = await this.createConnection("host:version");
|
||||||
const readable = new BufferedReadableStream(connection.readable);
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
try {
|
try {
|
||||||
const length = hexToNumber(await readable.readExactly(4));
|
const length = hexToNumber(await readable.readExactly(4));
|
||||||
|
@ -241,13 +241,13 @@ export class AdbServerClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
async killServer(): Promise<void> {
|
async killServer(): Promise<void> {
|
||||||
const connection = await this.connect("host:kill");
|
const connection = await this.createConnection("host:kill");
|
||||||
connection.writable.close().catch(NOOP);
|
connection.writable.close().catch(NOOP);
|
||||||
connection.readable.cancel().catch(NOOP);
|
connection.readable.cancel().catch(NOOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getServerFeatures(): Promise<AdbFeature[]> {
|
async getServerFeatures(): Promise<AdbFeature[]> {
|
||||||
const connection = await this.connect("host:host-features");
|
const connection = await this.createConnection("host:host-features");
|
||||||
const readable = new BufferedReadableStream(connection.readable);
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
try {
|
try {
|
||||||
const response = await AdbServerClient.readString(readable);
|
const response = await AdbServerClient.readString(readable);
|
||||||
|
@ -258,6 +258,44 @@ export class AdbServerClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async pairDevice(address: string, code: string): Promise<void> {
|
||||||
|
const connection = await this.createConnection(
|
||||||
|
`host:pair:${code}:${address}`,
|
||||||
|
);
|
||||||
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
|
try {
|
||||||
|
const response = await AdbServerClient.readString(readable);
|
||||||
|
if (!response.startsWith("Successfully paired to")) {
|
||||||
|
throw new AdbServerClient.UnauthorizedError(response);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
connection.writable.close().catch(NOOP);
|
||||||
|
readable.cancel().catch(NOOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectDevice(address: string): Promise<void> {
|
||||||
|
const connection = await this.createConnection(
|
||||||
|
`host:connect:${address}`,
|
||||||
|
);
|
||||||
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
|
try {
|
||||||
|
const response = await AdbServerClient.readString(readable);
|
||||||
|
if (response === `already connected to ${address}`) {
|
||||||
|
throw new AdbServerClient.AlreadyConnectedError(response);
|
||||||
|
}
|
||||||
|
if (response === `failed to connect to ${address}`) {
|
||||||
|
throw new AdbServerClient.UnauthorizedError(response);
|
||||||
|
}
|
||||||
|
if (response !== `connected to ${address}`) {
|
||||||
|
throw new AdbServerClient.NetworkError(response);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
connection.writable.close().catch(NOOP);
|
||||||
|
readable.cancel().catch(NOOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parseDeviceList(value: string): AdbServerDevice[] {
|
parseDeviceList(value: string): AdbServerDevice[] {
|
||||||
const devices: AdbServerDevice[] = [];
|
const devices: AdbServerDevice[] = [];
|
||||||
for (const line of value.split("\n")) {
|
for (const line of value.split("\n")) {
|
||||||
|
@ -309,7 +347,7 @@ export class AdbServerClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDevices(): Promise<AdbServerDevice[]> {
|
async getDevices(): Promise<AdbServerDevice[]> {
|
||||||
const connection = await this.connect("host:devices-l");
|
const connection = await this.createConnection("host:devices-l");
|
||||||
const readable = new BufferedReadableStream(connection.readable);
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
try {
|
try {
|
||||||
const response = await AdbServerClient.readString(readable);
|
const response = await AdbServerClient.readString(readable);
|
||||||
|
@ -323,7 +361,7 @@ export class AdbServerClient {
|
||||||
async trackDevices(
|
async trackDevices(
|
||||||
callback: (devices: AdbServerDevice[]) => void,
|
callback: (devices: AdbServerDevice[]) => void,
|
||||||
): Promise<() => void> {
|
): Promise<() => void> {
|
||||||
const connection = await this.connect("host:track-devices-l");
|
const connection = await this.createConnection("host:track-devices-l");
|
||||||
const readable = new BufferedReadableStream(connection.readable);
|
const readable = new BufferedReadableStream(connection.readable);
|
||||||
let running = true;
|
let running = true;
|
||||||
(async () => {
|
(async () => {
|
||||||
|
@ -380,7 +418,10 @@ export class AdbServerClient {
|
||||||
// Also, if the command is about a device, but didn't specify a selector,
|
// Also, if the command is about a device, but didn't specify a selector,
|
||||||
// it will be executed against the device selected previously by `connectDevice`.
|
// it will be executed against the device selected previously by `connectDevice`.
|
||||||
// Using this method, we can get the transport ID and device features in one connection.
|
// Using this method, we can get the transport ID and device features in one connection.
|
||||||
const socket = await this.connectDevice(device, "host:features");
|
const socket = await this.createDeviceConnection(
|
||||||
|
device,
|
||||||
|
"host:features",
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
const readable = new BufferedReadableStream(socket.readable);
|
const readable = new BufferedReadableStream(socket.readable);
|
||||||
const featuresString = await AdbServerClient.readString(readable);
|
const featuresString = await AdbServerClient.readString(readable);
|
||||||
|
@ -397,7 +438,7 @@ export class AdbServerClient {
|
||||||
* @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 `AdbServerSocket` that can be used to communicate with the service
|
||||||
*/
|
*/
|
||||||
async connectDevice(
|
async createDeviceConnection(
|
||||||
device: AdbServerDeviceSelector,
|
device: AdbServerDeviceSelector,
|
||||||
service: string,
|
service: string,
|
||||||
): Promise<AdbServerSocket> {
|
): Promise<AdbServerSocket> {
|
||||||
|
@ -420,7 +461,7 @@ export class AdbServerClient {
|
||||||
throw new Error("Invalid device selector");
|
throw new Error("Invalid device selector");
|
||||||
}
|
}
|
||||||
|
|
||||||
const connection = await this.connect(switchService);
|
const connection = await this.createConnection(switchService);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const writer = connection.writable.getWriter();
|
const writer = connection.writable.getWriter();
|
||||||
|
@ -496,7 +537,7 @@ export class AdbServerClient {
|
||||||
`wait-for-${type}-${state}`,
|
`wait-for-${type}-${state}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const socket = await this.connect(service, options);
|
const socket = await this.createConnection(service, options);
|
||||||
const readable = new BufferedReadableStream(socket.readable);
|
const readable = new BufferedReadableStream(socket.readable);
|
||||||
await AdbServerClient.readOkay(readable);
|
await AdbServerClient.readOkay(readable);
|
||||||
|
|
||||||
|
@ -560,3 +601,26 @@ export async function raceSignal<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace AdbServerClient {
|
||||||
|
export class NetworkError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = "ConnectionFailedError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnauthorizedError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = "UnauthorizedError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AlreadyConnectedError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = "AlreadyConnectedError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ export class AdbServerTransport implements AdbTransport {
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(service: string): Promise<AdbSocket> {
|
async connect(service: string): Promise<AdbSocket> {
|
||||||
return await this.#client.connectDevice(
|
return await this.#client.createDeviceConnection(
|
||||||
{
|
{
|
||||||
transportId: this.transportId,
|
transportId: this.transportId,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue