mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 13:00:33 +02:00
Devices: fixes from review round 8
- A batch of dropped files stays with the headset it was dropped on, and stops if the app switches. - Removing or moving the address in use reroutes at once; a headset with no addresses reaches nothing rather than whatever ~/.ssh/config says. - A late answer to an older device-list request is ignored. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
51ef5d8283
commit
175c39a2b0
3 files changed
+37
-8
No files matched your search
+12
-4
@@ -338,8 +338,10 @@ class Link:
|
||||
"""What every ssh command adds to reach DEVICE at HOST."""
|
||||
if device.get("none"):
|
||||
return ["-o", "HostName=no-headset.invalid"] # fails at once, with ssh's own "can't resolve"
|
||||
if device.get("transient") or not host:
|
||||
if device.get("transient"):
|
||||
return []
|
||||
if not host: # a headset with no addresses: reach nothing, not whatever ~/.ssh/config says
|
||||
return ["-o", "HostName=no-address.invalid"]
|
||||
return ["-o", f"HostName={frame_devices.ssh_host(host)}",
|
||||
"-o", f"HostKeyAlias={frame_devices.host_key_alias(device['id'])}",
|
||||
"-o", f"UserKnownHostsFile={frame_devices.known_hosts_opt(device['id'])}", "-o", "HashKnownHosts=no",
|
||||
@@ -454,7 +456,7 @@ class Link:
|
||||
self.state.update(phase="connected", retry_at=None, error=None)
|
||||
else:
|
||||
self.fails += 1
|
||||
self.state.update(phase="failed", retry_at=None if device.get("none") else
|
||||
self.state.update(phase="failed", retry_at=None if device.get("none") or not (device.get("transient") or device["addresses"]) else
|
||||
now() + RETRY[min(self.fails, len(RETRY)) - 1])
|
||||
if not self.state["error"]:
|
||||
self.state["error"] = {"stage": "find", "message": "Couldn't connect", "raw": ""}
|
||||
@@ -485,6 +487,9 @@ class Link:
|
||||
if device.get("none"):
|
||||
self.fail("find", "No headset is set up. Add one on the Devices tab.")
|
||||
return False
|
||||
if not device.get("transient") and not device["addresses"]:
|
||||
self.fail("find", f"{device['name']} has no addresses. Add one on the Devices tab.")
|
||||
return False
|
||||
# 1. this computer's network
|
||||
self.stage("network", "active")
|
||||
net = frame_network.current_network(self.last_fp)
|
||||
@@ -506,8 +511,7 @@ class Link:
|
||||
# 2. find the headset
|
||||
self.stage("find", "active")
|
||||
port = device.get("port") or 22
|
||||
bare = device.get("transient") or not device["addresses"]
|
||||
if bare:
|
||||
if device.get("transient"):
|
||||
host, port, user, proxied = ssh_g(device["alias"])
|
||||
if user and not device.get("user"):
|
||||
device["user"] = user
|
||||
@@ -951,9 +955,13 @@ def devices_action(link, body, open_setup, busy=lambda: 0):
|
||||
elif action == "address-update":
|
||||
a = reg.update_address(did, body.get("host"), new_host=body.get("newHost"), kind=body.get("kind"),
|
||||
label=body.get("label"))
|
||||
if is_active and a["host"] != body.get("host"):
|
||||
link.invalidate() # the address in use may have moved
|
||||
msg = f"Saved {a['host']}"
|
||||
elif action == "address-remove":
|
||||
reg.remove_address(did, body.get("host"))
|
||||
if is_active:
|
||||
link.invalidate() # it may be the address in use: stop using it now
|
||||
msg = f"Removed {body.get('host')}"
|
||||
elif action == "address-move":
|
||||
delta = body.get("delta")
|
||||
|
||||
+14
-4
@@ -1537,12 +1537,12 @@ window.addEventListener("drop", e => {
|
||||
const dirs = new Set(items.map((it, i) => it.webkitGetAsEntry && it.webkitGetAsEntry()?.isDirectory ? i : -1).filter(i => i >= 0));
|
||||
sendFiles([...e.dataTransfer.files], dirs);
|
||||
});
|
||||
function upload(file, mode) {
|
||||
function upload(file, mode, dev = window.connDevice) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/api/upload");
|
||||
xhr.setRequestHeader("X-Frame-UI", UI_KEY);
|
||||
if (window.connDevice) xhr.setRequestHeader("X-Frame-Device", window.connDevice);
|
||||
if (dev) xhr.setRequestHeader("X-Frame-Device", dev);
|
||||
xhr.setRequestHeader("X-Filename", encodeURIComponent(file.name));
|
||||
xhr.setRequestHeader("X-Mode", mode);
|
||||
const bar = $("prog").firstElementChild;
|
||||
@@ -1603,7 +1603,12 @@ $("apkAltClose").onclick = () => $("apkAltDlg").close();
|
||||
|
||||
const TITLE_EXT = /\.(zip|exe)$/i;
|
||||
async function sendFiles(files, dirs = new Set()) {
|
||||
const dev = window.connDevice; // the whole batch is for the headset it was dropped on
|
||||
for (const [i, f] of files.entries()) {
|
||||
if (window.connDevice !== dev) {
|
||||
toast(`Switched headsets: didn't send ${files.length - i} remaining file${files.length - i === 1 ? "" : "s"}`, true);
|
||||
break;
|
||||
}
|
||||
const path = window.frameApp?.pathForFile ? window.frameApp.pathForFile(f) : "";
|
||||
if (dirs.has(i)) {
|
||||
if (path) await sideload(f, path, true);
|
||||
@@ -1613,7 +1618,7 @@ async function sendFiles(files, dirs = new Set()) {
|
||||
if (!f.size) { toast(`${f.name}: empty files aren't supported`, true); continue; }
|
||||
if (TITLE_EXT.test(f.name)) { await sideload(f, path); continue; }
|
||||
const apk = f.name.toLowerCase().endsWith(".apk");
|
||||
await act(apk ? `Install ${f.name}` : `Copy ${f.name} to ~/Downloads`, () => upload(f, apk ? "apk" : "push"));
|
||||
await act(apk ? `Install ${f.name}` : `Copy ${f.name} to ~/Downloads`, () => upload(f, apk ? "apk" : "push", dev));
|
||||
}
|
||||
$("fileInput").value = "";
|
||||
refresh();
|
||||
@@ -2639,9 +2644,14 @@ $("connSetup").onclick = setUpActive;
|
||||
|
||||
// ---- Devices tab ----
|
||||
PAGES.push("devices");
|
||||
let devicesSeq = 0; // an older answer arriving late mustn't bring back the old selection
|
||||
async function loadDevices() {
|
||||
if (!link.live) return;
|
||||
try { dv.data = await api("/api/devices"); } catch (e) { return failed($("devList"), e); }
|
||||
const seq = ++devicesSeq;
|
||||
let data;
|
||||
try { data = await api("/api/devices"); } catch (e) { if (seq === devicesSeq) failed($("devList"), e); return; }
|
||||
if (seq !== devicesSeq) return;
|
||||
dv.data = data;
|
||||
dv.list = dv.data.devices;
|
||||
if (!dv.list.some(d => d.id === dv.sel)) dv.sel = dv.data.active;
|
||||
const sel = $("devSel");
|
||||
|
||||
Reference in new issue
Block a user