Create transport
The second step is to create a custom AdbTransport
instance.
Creating the AdbTransport
instance requires maxPayloadSize
and banner
information from the device. The server retrieves this information from the device, and sends it back to the client.
Server
The client can request the maxPayloadSize
and banner
information by sending a HTTP request to the server.
The server creates an AdbTransport
to the device using one of the supported transports, then sends the maxPayloadSize
and banner
information back to the client.
It also caches the created AdbTransport
instances, because the information won't change for the same device.
- JavaScript
- TypeScript
const devices = new Map();
const httpServer = createServer(async (request, response) => {
const url = new URL(request.url, "http://localhost");
const segments = url.pathname.substring(1).split("/");
if (segments[0] !== "device") {
// Route not found
response.writeHead(404, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
const [, serial] = segments;
if (!serial) {
// Invalid request
response.writeHead(400, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
if (!devices.has(serial)) {
const [device] = await Manager.getDevices({
filters: [{ serialNumber: serial }],
});
if (!device) {
// Requested device not found
response.writeHead(401, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
const connection = await device.connect();
const transport = await AdbDaemonTransport.authenticate({
serial,
connection,
credentialStore: CredentialStore,
});
devices.set(serial, transport);
}
const transport = devices.get(serial);
response
.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
})
.end(
JSON.stringify({
maxPayloadSize: transport.maxPayloadSize,
product: transport.banner.product,
model: transport.banner.model,
device: transport.banner.device,
features: transport.banner.features,
}),
);
});
import type { AdbTransport, AdbDaemonWebUsbDeviceManager } from "@yume-chan/adb";
declare const Manager: AdbDaemonWebUsbDeviceManager;
const devices = new Map<string, AdbTransport>();
const httpServer = createServer(async (request, response) => {
const url = new URL(request.url!, "http://localhost");
const segments = url.pathname.substring(1).split("/");
if (segments[0] !== "device") {
// Route not found
response.writeHead(404, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
const [, serial] = segments;
if (!serial) {
// Invalid request
response.writeHead(400, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
if (!devices.has(serial)) {
const [device] = await Manager.getDevices({
filters: [{ serialNumber: serial }],
});
if (!device) {
// Requested device not found
response.writeHead(401, { "Access-Control-Allow-Origin": "*" }).end();
return;
}
const connection = await device.connect();
const transport = await AdbDaemonTransport.authenticate({
serial,
connection,
credentialStore: CredentialStore,
});
devices.set(serial, transport);
}
const transport = devices.get(serial)!;
response
.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
})
.end(
JSON.stringify({
maxPayloadSize: transport.maxPayloadSize,
product: transport.banner.product,
model: transport.banner.model,
device: transport.banner.device,
features: transport.banner.features,
}),
);
});
Client
The client has a custom AdbTransport
implementation, that uses the maxPayloadSize
and banner
information to initialize:
- JavaScript
- TypeScript
import { ADB_DAEMON_DEFAULT_FEATURES } from "@yume-chan/adb";
class WebSocketTransport {
serial;
maxPayloadSize;
banner;
#disconnected = Promise.withResolvers();
get disconnected() {
return this.#disconnected.promise;
}
clientFeatures = ADB_DAEMON_DEFAULT_FEATURES;
constructor(serial, maxPayloadSize, banner) {
this.serial = serial;
this.maxPayloadSize = maxPayloadSize;
this.banner = banner;
}
addReverseTunnel() {
// TODO
}
removeReverseTunnel() {
// TODO
}
clearReverseTunnels() {
// TODO
}
async connect(service) {
// TODO
}
close() {
// TODO
this.#disconnected.resolve();
}
}
import {
ADB_DAEMON_DEFAULT_FEATURES,
AdbBanner,
AdbReverseNotSupportedError,
type AdbSocket,
type AdbTransport,
} from "@yume-chan/adb";
class WebSocketTransport implements AdbTransport {
serial: string;
maxPayloadSize: number;
banner: AdbBanner;
#disconnected = Promise.withResolvers<void>();
get disconnected() {
return this.#disconnected.promise;
}
clientFeatures = ADB_DAEMON_DEFAULT_FEATURES;
constructor(serial: string, maxPayloadSize: number, banner: AdbBanner) {
this.serial = serial;
this.maxPayloadSize = maxPayloadSize;
this.banner = banner;
}
addReverseTunnel() {
// TODO
}
removeReverseTunnel() {
// TODO
}
clearReverseTunnels() {
// TODO
}
async connect(service: string): Promise<AdbSocket> {
// TODO
}
close() {
// TODO
this.#disconnected.resolve();
}
}
It sends an HTTP request to the server to get the maxPayloadSize
and banner
information.
- JavaScript
- TypeScript
import { AdbBanner } from "@yume-chan/adb";
const container = document.getElementById("app");
const params = new URLSearchParams(location.search);
const serial = params.get("serial");
if (!serial) {
container.textContent = "Missing `serial` parameter";
return;
}
const response = await fetch(`http://localhost:8080/device/${serial}`);
if (!response.ok) {
container.textContent = "Connect error: " + response.status;
return;
}
const data = await response.json();
const transport = new WebSocketTransport(
serial,
data.maxPayloadSize,
new AdbBanner(data.product, data.model, data.device, data.features),
);
import { AdbBanner } from "@yume-chan/adb";
const container = document.getElementById("app")!;
const params = new URLSearchParams(location.search);
const serial = params.get("serial");
if (!serial) {
container.textContent = "Missing `serial` parameter";
return;
}
const response = await fetch(`http://localhost:8080/device/${serial}`);
if (!response.ok) {
container.textContent = "Connect error: " + response.status;
return;
}
const data = await response.json();
const transport = new WebSocketTransport(
serial,
data.maxPayloadSize,
new AdbBanner(data.product, data.model, data.device, data.features),
);