Track devices
The first feature of the project is to track the list of devices connected to the server, then sync the device list with the clients.
Server
When a client connects to /devices
endpoint, the server immediately sends the current device list to the client.
It also saves the client, so when the device list changes, the client can be notified.
- JavaScript
- TypeScript
const clients = new Set();
function sendDeviceList(client, devices) {
client.send(
JSON.stringify(
devices.map((device) => ({
serial: device.serial,
name: device.name,
vendorId: device.raw.vendorId,
productId: device.raw.productId,
})),
),
);
}
wsServer.addListener("connection", async (client, request) => {
const url = new URL(request.url, "http://localhost");
const segments = url.pathname.substring(1).split("/");
switch (segments[0]) {
case "devices":
sendDeviceList(client, await Manager.getDevices());
clients.add(client);
client.addListener("close", () => {
clients.delete(client);
});
break;
// ...
}
});
const observer = Manager.trackDevices();
observer.onListChange((devices) => {
for (const client of clients) {
sendDeviceList(client, devices);
}
});
export {};
import type { AdbDaemonWebUsbDeviceManager, AdbDaemonWebUsbDevice } from "@yume-chan/adb";
import type { WebSocket } from "ws";
declare const Manager: AdbDaemonWebUsbDeviceManager;
const clients = new Set<WebSocket>();
function sendDeviceList(client: WebSocket, devices: AdbDaemonWebUsbDevice[]) {
client.send(
JSON.stringify(
devices.map((device) => ({
serial: device.serial,
name: device.name,
vendorId: device.raw.vendorId,
productId: device.raw.productId,
})),
),
);
}
wsServer.addListener("connection", async (client, request) => {
const url = new URL(request.url!, "http://localhost");
const segments = url.pathname.substring(1).split("/");
switch (segments[0]) {
case "devices":
sendDeviceList(client, await Manager.getDevices());
clients.add(client);
client.addListener("close", () => {
clients.delete(client);
});
break;
// ...
}
});
const observer = Manager.trackDevices();
observer.onListChange((devices) => {
for (const client of clients) {
sendDeviceList(client, devices);
}
});
The sendDeviceList
method can be modified to include more information as needed.
Client
index.html
page contains a simple table template to display the device list.
index.html
<table>
<thead>
<tr>
<th>Serial</th>
<th>Name</th>
<th>Vendor ID</th>
<th>Product ID</th>
<th>Open</th>
</tr>
</thead>
<tbody id="devices"></tbody>
</table>
When page loads, a WebSocket connection to the server is created. When the server sends the device list, the client updates the table.
- JavaScript
- TypeScript
const container = document.getElementById("devices");
const socket = new WebSocket("http://localhost:8080/devices");
socket.addEventListener("message", ({ data }) => {
const devices = JSON.parse(data);
// Clear table
container.replaceChildren();
for (const device of devices) {
const row = container.insertRow();
row.insertCell().textContent = device.serial;
row.insertCell().textContent = device.name;
row.insertCell().textContent = device.vendorId.toString(16);
row.insertCell().textContent = device.productId.toString(16);
const anchor = document.createElement("a");
anchor.href = `/device/?serial=${device.serial}`;
anchor.textContent = "Open";
row.insertCell().appendChild(anchor);
}
});
const container = document.getElementById("devices") as HTMLTableSectionElement;
const socket = new WebSocket("http://localhost:8080/devices");
socket.addEventListener("message", ({ data }) => {
const devices = JSON.parse(data);
// Clear table
container.replaceChildren();
for (const device of devices) {
const row = container.insertRow();
row.insertCell().textContent = device.serial;
row.insertCell().textContent = device.name;
row.insertCell().textContent = device.vendorId.toString(16);
row.insertCell().textContent = device.productId.toString(16);
const anchor = document.createElement("a");
anchor.href = `/device/?serial=${device.serial}`;
anchor.textContent = "Open";
row.insertCell().appendChild(anchor);
}
});