Skip to content

Commit 0914db0

Browse files
NathanWalkerclaude
andcommitted
fix(windows): keep the service port private and make the CLI recover from stale services
Running `simdeck` on Windows could sit silent for three minutes and then come up on a different port. Four Windows-specific gaps combined to cause it: - Tokio creates Windows sockets with `socket()`, so the HTTP listener handle was inheritable and every adb server or emulator the service spawned kept the port open after the service exited. The listener now clears its inherit flag right after binding. - The CLI probed an existing service's `/api/health` with the 180 second HTTP client read timeout, so an orphaned port that accepts but never answers stalled every command. The probe now uses a 5 second bounded connect/read timeout. - Process control shelled out to `kill` and `ps`, which do not exist on Windows, so `service stop` and `simdeck kill` reported success without ending anything and stale services accumulated. Windows now checks processes through OpenProcess/GetExitCodeProcess and terminates the service tree with `taskkill /T`. - The state directory came from `HOME`, which PowerShell and cmd do not set, so each shell used a different service.json. Home resolution is now shared in `platform::user_home_dir` and honours USERPROFILE. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R5M5zpn6gaZYNyjANLwfoP
1 parent c5ecb2c commit 0914db0

7 files changed

Lines changed: 276 additions & 30 deletions

File tree

‎docs/guide/troubleshooting.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ If it is an old service:
4444
simdeck service stop
4545
```
4646

47+
### `simdeck` prints nothing for minutes on Windows
48+
49+
Earlier Windows builds let child processes inherit the service's listening
50+
socket. If the service exited while the adb server or an emulator it
51+
started was still running, port 4310 stayed open with nothing answering, and
52+
the next `simdeck` run waited on it before starting a fresh service on another
53+
port. Stop the orphaned holder and run `simdeck` again:
54+
55+
```powershell
56+
adb kill-server
57+
```
58+
59+
Newer builds keep the listener private to the service and give up on a silent
60+
port after a few seconds.
61+
62+
### Windows reports a missing `libstdc++-6.dll`
63+
64+
The Windows binary is built with the MinGW toolchain and must not depend on its
65+
runtime DLLs. A build that does starts only inside Git Bash and fails from
66+
PowerShell or cmd with exit code `0xC0000135`. Released builds link the runtime
67+
statically; a source build needs `SIMDECK_BUILD_TARGET=x86_64-pc-windows-gnu`,
68+
which `npm run build:cli` handles by adding `+crt-static` and refusing to
69+
package a binary that still imports those DLLs.
70+
4771
### Native binary is missing
4872

4973
Reinstall from npm:

‎packages/server/src/android.rs‎

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,20 +1981,7 @@ fn java_home() -> Option<OsString> {
19811981
}
19821982

19831983
fn home_dir() -> PathBuf {
1984-
env::var_os("HOME")
1985-
.or_else(|| env::var_os("USERPROFILE"))
1986-
.or_else(
1987-
|| match (env::var_os("HOMEDRIVE"), env::var_os("HOMEPATH")) {
1988-
(Some(drive), Some(path)) => {
1989-
let mut combined = PathBuf::from(drive);
1990-
combined.push(path);
1991-
Some(combined.into_os_string())
1992-
}
1993-
_ => None,
1994-
},
1995-
)
1996-
.map(PathBuf::from)
1997-
.unwrap_or_else(|| Path::new("/").to_path_buf())
1984+
crate::platform::user_home_dir().unwrap_or_else(|| Path::new("/").to_path_buf())
19981985
}
19991986

20001987
fn extract_xml(output: &str) -> &str {

‎packages/server/src/config.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ pub fn user_config_path() -> PathBuf {
8383
}
8484

8585
pub fn simdeck_user_state_dir() -> PathBuf {
86-
std::env::var_os("HOME")
87-
.filter(|value| !value.is_empty())
88-
.map(PathBuf::from)
86+
crate::platform::user_home_dir()
8987
.map(|home| home.join(".simdeck"))
9088
.unwrap_or_else(|| std::env::temp_dir().join("simdeck"))
9189
}

‎packages/server/src/inspector.rs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,7 @@ impl Drop for RegistryFileLock {
540540
fn inspector_registry_path() -> PathBuf {
541541
env::var_os("SIMDECK_INSPECTOR_REGISTRY_PATH")
542542
.map(PathBuf::from)
543-
.or_else(|| env::var_os("HOME").map(|home| PathBuf::from(home).join(".simdeck")))
544-
.unwrap_or_else(|| env::temp_dir().join("simdeck"))
543+
.unwrap_or_else(crate::config::simdeck_user_state_dir)
545544
.join("inspectors.json")
546545
}
547546

0 commit comments

Comments
 (0)