Cleanup: version 1.0.0, drop binaries, fix scan loop - #2
Conversation
Align package/Cargo/Tauri/UI versions, stop tracking installers and leftover assets, persist custom ports, prefer LAN IPs over VPN/WSL, and add CI. Co-authored-by: Krystian <haser88@gmail.com>
Keep selectedPort in a ref via an effect, and fold IP fetch into the scan timer so eslint no longer flags render-time ref writes or unused catch bindings. Co-authored-by: Krystian <haser88@gmail.com>
Keep hrefs on the published GitHub Release assets (filenames still EnvTunnel_0.1.0_*), show v1.0.0 names and real file sizes, and point Build from source at the README installation heading. Co-authored-by: Krystian <haser88@gmail.com>
There was a problem hiding this comment.
6 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src-tauri/src/lib.rs">
<violation number="1" location="src-tauri/src/lib.rs:82">
P2: When multiple adapters share the same priority (e.g. Ethernet and Wi-Fi both on 192.168.x.x), the `_ => {}` arm keeps whichever the OS enumerated first, and `list_afinet_netifas()` order is not guaranteed stable. The chosen IP can therefore change between launches without any network change, producing an inconsistent QR/localhost IP. Break ties deterministically rather than relying on enumeration order.</violation>
<violation number="2" location="src-tauri/src/lib.rs:88">
P1: When no eligible RFC1918 interface exists, this new filtered path falls back to `local_ip()` and can return the VPN, Tailscale, or CGNAT address that the code claims to skip. Keep the fallback subject to the same interface/address filtering, or return an error when no reachable LAN address is available.</violation>
</file>
<file name="src/App.tsx">
<violation number="1" location="src/App.tsx:144">
P2: When `customPorts` changes during an in-flight scan, the effect starts a replacement scan but the old `scanPorts` still applies its result after cleanup. A stale result can overwrite the current ports and selection; guard result application with a generation token or serialize scans.</violation>
<violation number="2" location="src/App.tsx:161">
P2: On mount the loop scans twice: the effect's first run fetches the IP, begins an immediate in-flight scan, then setIp re-runs the effect (ip is a dependency) which starts a second immediate scan before the first finishes. Both concurrent scanPorts calls read the still-empty prevPortsRef, so every running dev server emits duplicate "PORT X ACTIVE" toasts and is probed back-to-back at launch. The old code scanned once on init and the interval effect returned early on a null ip, so this is a regression. Drop `ip` from the dependency array (only fetchIp mutates ip, and it is already awaited inside start) so the loop runs once and still re-scans when customPorts changes.</violation>
</file>
<file name=".github/workflows/ci.yml">
<violation number="1" location=".github/workflows/ci.yml:21">
P2: The `rust` job runs `cargo check`/`cargo test` on `ubuntu-latest`, but EnvTunnel is a Windows-only Tauri app (README lists Windows + Visual Studio Build Tools as the only supported build environment and documents a known Windows link failure). Running on Linux never produces or validates the actual shipping artifact and cannot catch Windows-specific breakages such as the documented `LNK1181: legacy_stdio_definitions.lib` failure, so the CI gives false confidence that the app builds. Consider running this job on `windows-latest` (with the LIB workaround for the known issue) and/or adding a `tauri build` step so the release binary is actually compiled in CI.</violation>
<violation number="2" location=".github/workflows/ci.yml:40">
P1: The `rust` job runs `cargo check` / `cargo test` on a fresh runner without a frontend build, so `dist/` never exists. `tauri::generate_context!()` (lib.rs:337) and tauri-build require `frontendDist` (`../dist`) to exist and panic with "frontendDist configuration is set to '../dist' but this path doesn't exist", so both rust steps fail on a clean checkout. The `frontend` job builds `dist/` but on a separate runner with no shared filesystem. Add `actions/setup-node@v4`, `npm ci` and `npm run build` (before `cargo check`) to the rust job, or at minimum create the empty `dist/` directory, so the tauri context macro has assets to load.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| _ => {} | ||
| } | ||
| } | ||
| if let Some((_, ip)) = best { |
There was a problem hiding this comment.
P1: When no eligible RFC1918 interface exists, this new filtered path falls back to local_ip() and can return the VPN, Tailscale, or CGNAT address that the code claims to skip. Keep the fallback subject to the same interface/address filtering, or return an error when no reachable LAN address is available.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src-tauri/src/lib.rs, line 88:
<comment>When no eligible RFC1918 interface exists, this new filtered path falls back to `local_ip()` and can return the VPN, Tailscale, or CGNAT address that the code claims to skip. Keep the fallback subject to the same interface/address filtering, or return an error when no reachable LAN address is available.</comment>
<file context>
@@ -13,14 +13,117 @@ pub struct PortStatus {
+ _ => {}
+ }
+ }
+ if let Some((_, ip)) = best {
+ return Ok(ip);
+ }
</file context>
| librsvg2-dev \ | ||
| patchelf \ | ||
| libssl-dev | ||
| - run: cargo check --locked |
There was a problem hiding this comment.
P1: The rust job runs cargo check / cargo test on a fresh runner without a frontend build, so dist/ never exists. tauri::generate_context!() (lib.rs:337) and tauri-build require frontendDist (../dist) to exist and panic with "frontendDist configuration is set to '../dist' but this path doesn't exist", so both rust steps fail on a clean checkout. The frontend job builds dist/ but on a separate runner with no shared filesystem. Add actions/setup-node@v4, npm ci and npm run build (before cargo check) to the rust job, or at minimum create the empty dist/ directory, so the tauri context macro has assets to load.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 40:
<comment>The `rust` job runs `cargo check` / `cargo test` on a fresh runner without a frontend build, so `dist/` never exists. `tauri::generate_context!()` (lib.rs:337) and tauri-build require `frontendDist` (`../dist`) to exist and panic with "frontendDist configuration is set to '../dist' but this path doesn't exist", so both rust steps fail on a clean checkout. The `frontend` job builds `dist/` but on a separate runner with no shared filesystem. Add `actions/setup-node@v4`, `npm ci` and `npm run build` (before `cargo check`) to the rust job, or at minimum create the empty `dist/` directory, so the tauri context macro has assets to load.</comment>
<file context>
@@ -0,0 +1,41 @@
+ librsvg2-dev \
+ patchelf \
+ libssl-dev
+ - run: cargo check --locked
+ - run: cargo test --locked --lib
</file context>
| let timeoutId: number | ||
|
|
||
| const tick = async (targetIp: string) => { | ||
| await scanPorts(targetIp) |
There was a problem hiding this comment.
P2: When customPorts changes during an in-flight scan, the effect starts a replacement scan but the old scanPorts still applies its result after cleanup. A stale result can overwrite the current ports and selection; guard result application with a generation token or serialize scans.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/App.tsx, line 144:
<comment>When `customPorts` changes during an in-flight scan, the effect starts a replacement scan but the old `scanPorts` still applies its result after cleanup. A stale result can overwrite the current ports and selection; guard result application with a generation token or serialize scans.</comment>
<file context>
@@ -102,28 +134,47 @@ function App() {
+ let timeoutId: number
+
+ const tick = async (targetIp: string) => {
+ await scanPorts(targetIp)
+ if (!cancelled) {
+ timeoutId = window.setTimeout(() => tick(targetIp), 3000)
</file context>
| - run: npm run lint | ||
| - run: npm run build | ||
|
|
||
| rust: |
There was a problem hiding this comment.
P2: The rust job runs cargo check/cargo test on ubuntu-latest, but EnvTunnel is a Windows-only Tauri app (README lists Windows + Visual Studio Build Tools as the only supported build environment and documents a known Windows link failure). Running on Linux never produces or validates the actual shipping artifact and cannot catch Windows-specific breakages such as the documented LNK1181: legacy_stdio_definitions.lib failure, so the CI gives false confidence that the app builds. Consider running this job on windows-latest (with the LIB workaround for the known issue) and/or adding a tauri build step so the release binary is actually compiled in CI.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 21:
<comment>The `rust` job runs `cargo check`/`cargo test` on `ubuntu-latest`, but EnvTunnel is a Windows-only Tauri app (README lists Windows + Visual Studio Build Tools as the only supported build environment and documents a known Windows link failure). Running on Linux never produces or validates the actual shipping artifact and cannot catch Windows-specific breakages such as the documented `LNK1181: legacy_stdio_definitions.lib` failure, so the CI gives false confidence that the app builds. Consider running this job on `windows-latest` (with the LIB workaround for the known issue) and/or adding a `tauri build` step so the release binary is actually compiled in CI.</comment>
<file context>
@@ -0,0 +1,41 @@
+ - run: npm run lint
+ - run: npm run build
+
+ rust:
+ runs-on: ubuntu-latest
+ defaults:
</file context>
| init() | ||
| return () => { isMounted = false } | ||
| }, [fetchIp, scanPorts]) | ||
| }, [ip, scanPorts, fetchIp]) |
There was a problem hiding this comment.
P2: On mount the loop scans twice: the effect's first run fetches the IP, begins an immediate in-flight scan, then setIp re-runs the effect (ip is a dependency) which starts a second immediate scan before the first finishes. Both concurrent scanPorts calls read the still-empty prevPortsRef, so every running dev server emits duplicate "PORT X ACTIVE" toasts and is probed back-to-back at launch. The old code scanned once on init and the interval effect returned early on a null ip, so this is a regression. Drop ip from the dependency array (only fetchIp mutates ip, and it is already awaited inside start) so the loop runs once and still re-scans when customPorts changes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/App.tsx, line 161:
<comment>On mount the loop scans twice: the effect's first run fetches the IP, begins an immediate in-flight scan, then setIp re-runs the effect (ip is a dependency) which starts a second immediate scan before the first finishes. Both concurrent scanPorts calls read the still-empty prevPortsRef, so every running dev server emits duplicate "PORT X ACTIVE" toasts and is probed back-to-back at launch. The old code scanned once on init and the interval effect returned early on a null ip, so this is a regression. Drop `ip` from the dependency array (only fetchIp mutates ip, and it is already awaited inside start) so the loop runs once and still re-scans when customPorts changes.</comment>
<file context>
@@ -102,28 +134,47 @@ function App() {
- init()
- return () => { isMounted = false }
- }, [fetchIp, scanPorts])
+ }, [ip, scanPorts, fetchIp])
useEffect(() => {
</file context>
| }, [ip, scanPorts, fetchIp]) | |
| }, [scanPorts, fetchIp]) |
| }; | ||
| match &best { | ||
| None => best = Some((prio, v4.to_string())), | ||
| Some((best_prio, _)) if prio < *best_prio => { |
There was a problem hiding this comment.
P2: When multiple adapters share the same priority (e.g. Ethernet and Wi-Fi both on 192.168.x.x), the _ => {} arm keeps whichever the OS enumerated first, and list_afinet_netifas() order is not guaranteed stable. The chosen IP can therefore change between launches without any network change, producing an inconsistent QR/localhost IP. Break ties deterministically rather than relying on enumeration order.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src-tauri/src/lib.rs, line 82:
<comment>When multiple adapters share the same priority (e.g. Ethernet and Wi-Fi both on 192.168.x.x), the `_ => {}` arm keeps whichever the OS enumerated first, and `list_afinet_netifas()` order is not guaranteed stable. The chosen IP can therefore change between launches without any network change, producing an inconsistent QR/localhost IP. Break ties deterministically rather than relying on enumeration order.</comment>
<file context>
@@ -13,14 +13,117 @@ pub struct PortStatus {
+ };
+ match &best {
+ None => best = Some((prio, v4.to_string())),
+ Some((best_prio, _)) if prio < *best_prio => {
+ best = Some((prio, v4.to_string()));
+ }
</file context>
Short housekeeping from the repo review.
Changes
package.json, Cargo, Tauri, UI badge, and README (clone URL +envtunnel.exepath).release/) and leftover screenshots/Vite assets. Favicon/public/icon.pngshrunk from 1024×1024 (~1.5 MB) to 128×128.selectedPortis kept in a ref so clicking a port no longer resets the 3s timer. Custom ports and path persist inlocalStorage.192.168→10.x→172.16-31.npm run lint+npm run build,cargo check+cargo test --lib.hrefs still target the published GitHub Release assets (EnvTunnel_0.1.0_*— those are the actual filenames; renaming the URL to1.0.0would 404 until a new release is published). “Build from source” now points at the README installation heading instead of a broken#-installationfragment.Checks
npm run lint— passnpm run build— passcargo test --libcould not run in this environment (Rust 1.83 vs a lockfile crate that needs edition 2024). GitHub Actions uses current stable.Not in this PR: macOS/Linux builds, HTTPS QR codes, full settings UI.
Summary by cubic
Releases v1.0.0, removes committed installers, and fixes the scan loop so selecting a port no longer resets the 3s timer or retriggers IP lookups; QR codes now prefer reachable LAN IPs.
package.json,Cargo.toml,tauri.conf.json, UI badge, and README (repo URL andenvtunnel.exepath). Landing download cards show v1.0.0 names and sizes; “Build from source” links to the README installation heading.release/to.gitignore; shrink icons.npm run lint,npm run build,cargo check --locked, andcargo test --locked --libwith Tauri dependencies.Rollout
EnvTunnel_0.1.0_*).Written for commit 6a5862f. Summary will update on new commits.