Skip to content

feat: share an album beyond the local network - #1478

Merged
rohan-pandeyy merged 26 commits into
AOSSIE-Org:mainfrom
rohan-pandeyy:feat/share-internet-mode
Aug 9, 2026
Merged

rohan-pandeyy merged 26 commits into
AOSSIE-Org:mainfrom
rohan-pandeyy:feat/share-internet-mode

Conversation

@rohan-pandeyy

@rohan-pandeyy rohan-pandeyy commented Aug 8, 2026

Copy link
Copy Markdown
Member

Closes #1477

Adds a second mode to the share dialog, chosen while creating a share, that makes an album reachable from outside the local network. Local sharing only works when both people are on the same Wi-Fi, and it fails outright on networks that block their own devices from reaching each other, which is most guest Wi-Fi and some home routers.

Approach

The route is an SSH reverse tunnel opened with the system ssh client, which every desktop platform already ships. Nothing is bundled and nothing is downloaded, so the installer does not grow and there is no third-party binary to pin. The tunnel forwards the share port, and since the share server already binds to all interfaces and serves /s/{token}, the backend needs no changes at all; tokens, passwords and expiry behave identically in both modes.

The child process is owned by the Tauri side and closed from the window handler, the tray quit item, and when the share is stopped. An orphaned tunnel would leave an album reachable from the internet, which is worse than the orphaned local listener the backend already guards against. It is killed through its handle rather than by matching process names, because matching on ssh would take down the user's own unrelated sessions.

The assigned URL is read from the provider's output by host suffix rather than by the wording around it, because the banner it prints first contains several unrelated links. Output keeps being drained afterwards, since the provider also emits a QR code and a full pipe would stall ssh.

What it costs, and how that is handled

The relay terminates TLS, so it handles photos in readable form as they pass. Internet mode is therefore opt-in per share and never the default, the dialog states the trade-off rather than implying the link is private, and an information button links to the documentation.

Password protection is switched on by default in this mode. It stays removable, but chat applications fetch links to build previews without anyone opening them, and the unlock page is what stops those previews seeing the album. A failed connection undoes the share rather than leaving one the user did not ask for.

Not included

Reaching a share through router port forwarding is deliberately out of scope. The host cannot confirm that a port is reachable without something outside trying it, so any such indicator would be a guess.

Testing

Eleven new tests: four in Rust covering the URL parsing against real captured provider output, and seven in the dialog covering the mode toggle, the tunnel lifecycle, the rollback on failure and the documentation link. Full suites at 368 frontend tests and 4 Rust tests passing.

The tunnel transport itself was verified by hand on a network where local sharing provably fails, returning 200 through the public URL with the request arriving locally. The dialog flow has been exercised in the running application only as far as the documentation link; creating an internet share from the app and opening it from outside the network still wants a manual pass before merge.

Summary by CodeRabbit

  • New Features

    • Added Internet sharing for albums alongside local-network sharing.
    • Displays public sharing links, connection progress, and tunnel status.
    • Automatically cleans up sharing when tunnel setup fails or sharing stops.
    • Added helpful links and troubleshooting guidance.
  • Documentation

    • Added user and developer documentation covering album sharing, privacy, connectivity, passwords, and troubleshooting.
    • Updated documentation navigation.
  • Bug Fixes

    • Improved handling of tunnel failures, application shutdown, and help-link fallback behavior.

The tunnel spawn needs a timeout; without one a provider that connects but
never answers would hang the caller indefinitely.
Uses the system ssh client rather than a bundled tunnel binary: every desktop
platform ships one, which avoids ~40MB in the installer and the problem of
pinning a binary published from unversioned URLs.

The URL is matched by host suffix rather than by the wording around it, because
both providers print a banner containing several unrelated links first. Output
keeps being drained after the URL is found, so the ANSI QR code they emit
cannot fill the pipe and stall ssh.
Closed from both the window handler and the tray quit item. An orphaned tunnel
leaves an album reachable from the internet, which is worse than the orphaned
LAN listener the backend already guards against.

The child is killed through its handle rather than by matching process names,
as kill_process_tree does: an ssh name match would take down the user's own
unrelated sessions.
The status command kept handing out a URL after ssh exited, so the dialog
would show a dead link as live. Cleared when the event stream ends, and only
when the tunnel is still the current one, so a newer tunnel is not cleared by
an older one's exit.
A full-width toggle picks where the share is reachable from, and only appears
while creating one: switching afterwards would be a different operation.

Internet mode starts with the password on. It stays removable, but chat apps
fetch links to build previews, and the unlock page is what stops those previews
seeing the album. A failed connection undoes the share rather than leaving the
user with one they did not ask for.
A user-facing page under Overview, with mermaid diagrams of both paths, since
internet mode routes photos through a relay that can read them and that is not
something to leave people to discover. The existing backend page stays
developer-facing and now points at it.
An info button in both steps, deep-linking to the section for whichever mode
is selected. Opening a URL needed a capability the app did not have.
The click swallowed every error, so a missing capability looked like a dead
button. The address is now handed over instead, which stays useful whatever
stopped the browser from launching.
The opener plugin scopes open_url by URL as well as gating the command, so the
bare permission allowed nothing and every call was denied. Scoped to the
documentation site rather than all of https, so the app can only ever launch a
browser at our own pages.
Reads as part of the heading rather than a stray control at the far edge. The
title truncates so a long album name cannot push it out of view.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR adds Internet album sharing through an SSH reverse tunnel. It integrates tunnel lifecycle commands with Tauri and the share dialog, adds lifecycle tests, and documents LAN and Internet sharing.

Changes

Internet album sharing

Layer / File(s) Summary
Reverse tunnel service
frontend/src-tauri/Cargo.toml, frontend/src-tauri/src/services/...
The Tauri backend starts, reuses, monitors, and stops localhost.run SSH tunnels. It extracts HTTPS URLs and cleans up child processes.
Tauri lifecycle and command wiring
frontend/src-tauri/src/main.rs, frontend/src-tauri/capabilities/migrated.json, frontend/src/utils/tunnel.ts
Tauri registers tunnel commands, owns TunnelState, permits documentation URLs, and shuts down tunnels on exit.
Share mode and tunnel UI
frontend/src/types/Share.ts, frontend/src/hooks/useShareTunnel.ts, frontend/src/components/Albums/ShareAlbumDialog.tsx
The dialog adds LAN and Internet modes, tunnel progress, public URLs, Internet warnings, password defaults, cleanup, and documentation links.
Share mode validation
frontend/src/components/Albums/__tests__/ShareAlbumDialog.test.tsx, frontend/src/hooks/__tests__/useShareTunnel.test.ts, frontend/src/pages/__tests__/Album.test.tsx
Tests cover tunnel creation, URL display, race handling, failure cleanup, help links, stale status results, tunnel shutdown, and delayed mutation errors.
Sharing documentation
docs/overview/sharing-albums.md, docs/backend/backend_python/album-sharing.md, mkdocs.yml
The documentation explains sharing modes, privacy, lifecycle, troubleshooting, backend behavior, tests, and navigation entries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ShareAlbumDialog
  participant Tauri
  participant TunnelService
  participant localhost_run as localhost.run
  User->>ShareAlbumDialog: Select Internet sharing
  ShareAlbumDialog->>Tauri: Create local share
  ShareAlbumDialog->>Tauri: Start tunnel for share port
  Tauri->>TunnelService: tunnel_start(port)
  TunnelService->>localhost_run: Open SSH reverse tunnel
  localhost_run-->>TunnelService: Return HTTPS URL
  TunnelService-->>ShareAlbumDialog: Return public URL
  ShareAlbumDialog-->>User: Display Internet share URL
Loading

Possibly related PRs

Suggested labels: Python, TypeScript/JavaScript, Rust, Documentation

Poem

A rabbit opens a tunnel wide,
An album hops to the outside.
LAN links stay within the den,
Passwords guard the public span.
When sharing ends, the tunnel sleeps.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The Album.test.tsx retry-wait adjustment is unrelated to the Internet sharing objectives in [#1477]. Move the unrelated Album.test.tsx timing adjustment to a separate pull request or provide explicit scope justification.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: sharing albums beyond the local network.
Linked Issues check ✅ Passed The changes implement Internet sharing, SSH tunnel lifecycle management, opt-in privacy messaging, rollback handling, tests, and documentation required by issue [#1477].
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (2)
frontend/src/types/Share.ts (1)

23-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use this shared ShareMode type in the share dialog.

frontend/src/components/Albums/ShareAlbumDialog.tsx:27 also declares ShareMode. Remove that local declaration and import this type. Duplicate unions can diverge when a new mode is added.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/types/Share.ts` around lines 23 - 27, Update ShareAlbumDialog to
remove its local ShareMode declaration and import the shared ShareMode type from
Share.ts, using that imported type wherever the dialog references share modes.

Source: Coding guidelines

frontend/src/utils/tunnel.ts (1)

12-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add explicit return types to exported IPC wrappers.

The frontend rules require every export and API boundary to be typed. Add return annotations to startTunnel, stopTunnel, and tunnelStatus.

Proposed fix
-export const startTunnel = (port: number): Promise<string> =>
+export const startTunnel = (port: number): Promise<string> =>
   invoke<string>('tunnel_start', { port });

-export const stopTunnel = (): Promise<void> => invoke<void>('tunnel_stop');
+export const stopTunnel = (): Promise<void> => invoke<void>('tunnel_stop');

-export const tunnelStatus = (): Promise<string | null> =>
+export const tunnelStatus = (): Promise<string | null> =>
   invoke<string | null>('tunnel_status');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/utils/tunnel.ts` around lines 12 - 19, Add explicit Promise
return-type annotations to the exported IPC wrapper functions startTunnel,
stopTunnel, and tunnelStatus, preserving their existing generic result types and
behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/backend/backend_python/album-sharing.md`:
- Around line 84-89: Replace the complete token in the example response and its
repeated URL prefix with the literal placeholder <share_token>; if the exposed
value is real, revoke it as well.

In `@docs/overview/sharing-albums.md`:
- Around line 18-19: Update the LAN entries in the sharing overview table and
the confidentiality statements in the LAN-mode section to state that access is
available to any client able to reach the machine and possessing the link,
rather than only Wi-Fi users. Clarify that LAN mode avoids a third-party relay
but is not end-to-end encrypted, while preserving the existing relay-mode
descriptions.
- Around line 3-5: Update the opening summary of the album-sharing documentation
to separate storage from network transit: clarify that photos are not stored or
uploaded by PictoPy while explicitly stating that Internet-mode sharing sends
image data through the relay, which can read it. Keep the local disk source and
share-duration behavior accurate, and align the later storage and relay
descriptions with this distinction.

In `@frontend/src-tauri/Cargo.toml`:
- Line 24: Update the Tokio dependency feature list in Cargo.toml to include the
sync feature alongside macros and time, so tunnel.rs can use
tokio::sync::mpsc::Receiver.

In `@frontend/src-tauri/src/main.rs`:
- Around line 78-80: Add application-level tunnel cleanup at the exit boundary
in main, ensuring services::tunnel::shutdown runs before app.exit for every
normal exit path. Update the existing cleanup calls at
frontend/src-tauri/src/main.rs lines 78-80 and 328-330 as needed so close and
tray-quit handlers remain harmless local no-ops while the centralized exit
cleanup handles termination.

In `@frontend/src-tauri/src/services/tunnel.rs`:
- Around line 253-293: Add controlled-process lifecycle tests alongside the
existing find_url tests, covering child cleanup, state removal after child exit,
startup rollback when launch fails, and stop failure handling. Exercise the
relevant tunnel lifecycle functions with deterministic mock or helper processes,
and assert each path leaves the expected state and propagates failures
correctly.
- Around line 98-110: The read_url function currently parses each command output
chunk independently, so URLs split across events are missed. Maintain a bounded
buffer across Stdout and Stderr events, append each decoded chunk before calling
find_url, and trim older content to enforce the bound; add a test covering a URL
split across multiple events while preserving termination and timeout behavior.
- Around line 180-196: Serialize the complete tunnel lifecycle around the start
flow containing the initial active-state check and `open(&app, provider,
port).await`, using one shared lifecycle state also acquired by `tunnel_stop`
and `shutdown`. Keep the lock/state held or otherwise marked through the full
open-to-install transition so concurrent starts cannot spawn competing children
and stop cannot return before the new `ActiveTunnel` is installed; add coverage
for concurrent starts and stop during startup.
- Around line 211-217: Update tunnel_stop so the active tunnel’s CommandChild
remains stored until child.kill() succeeds, allowing a retry if termination
fails. Avoid consuming or clearing the active entry before the kill operation;
only remove it after successful termination while preserving the existing error
reporting.

In `@frontend/src/components/Albums/ShareAlbumDialog.tsx`:
- Around line 75-105: Split ShareAlbumDialog into focused modules: extract
tunnel state and lifecycle logic into a dedicated hook, and move the creation
form and active-share display into separate components. Update ShareAlbumDialog
to compose these pieces while retaining existing share mutations, documentation
behavior, and UI state transitions.
- Around line 161-166: Update the share-stop flow around tunnelStatus() and
stopTunnel() so cleanup is based on managed tunnel state rather than transient
tunnelUrl availability, including when status lookup is pending or rejects. Do
not swallow stopTunnel failures; propagate the rejection so the dialog does not
report success and the user can retry. Add regression coverage for
unresolved/failed status lookup and failed tunnel shutdown.
- Around line 198-214: Update the ShareAlbumDialog reopening initialization
around tunnelStatus() so a returned tunnel URL sets mode to internet, while an
absent URL preserves LAN mode; ensure the active-share description and help link
use this restored mode. Add a reopening test that confirms an active tunnel
opens the Internet documentation URL.
- Around line 140-146: Update the catch path in ShareAlbumDialog.tsx
(frontend/src/components/Albums/ShareAlbumDialog.tsx#L140-L146) to handle
revokeShare rejection separately, preserving cleanup state and reporting that
revocation remains incomplete instead of claiming the album was not shared;
provide a retry path. Add coverage in ShareAlbumDialog.test.tsx
(frontend/src/components/Albums/__tests__/ShareAlbumDialog.test.tsx#L138-L157)
by mocking revokeShare failure and verifying the incomplete-cleanup message and
retry behavior.

---

Nitpick comments:
In `@frontend/src/types/Share.ts`:
- Around line 23-27: Update ShareAlbumDialog to remove its local ShareMode
declaration and import the shared ShareMode type from Share.ts, using that
imported type wherever the dialog references share modes.

In `@frontend/src/utils/tunnel.ts`:
- Around line 12-19: Add explicit Promise return-type annotations to the
exported IPC wrapper functions startTunnel, stopTunnel, and tunnelStatus,
preserving their existing generic result types and behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e0564dec-877d-4ebd-964e-564de69ff138

📥 Commits

Reviewing files that changed from the base of the PR and between 7fb0e8f and 5d305c8.

📒 Files selected for processing (12)
  • docs/backend/backend_python/album-sharing.md
  • docs/overview/sharing-albums.md
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/capabilities/migrated.json
  • frontend/src-tauri/src/main.rs
  • frontend/src-tauri/src/services/mod.rs
  • frontend/src-tauri/src/services/tunnel.rs
  • frontend/src/components/Albums/ShareAlbumDialog.tsx
  • frontend/src/components/Albums/__tests__/ShareAlbumDialog.test.tsx
  • frontend/src/types/Share.ts
  • frontend/src/utils/tunnel.ts
  • mkdocs.yml

Comment thread docs/backend/backend_python/album-sharing.md Outdated
Comment thread docs/overview/sharing-albums.md Outdated
Comment thread docs/overview/sharing-albums.md Outdated
Comment thread frontend/src-tauri/Cargo.toml Outdated
Comment thread frontend/src-tauri/src/main.rs
Comment thread frontend/src-tauri/src/services/tunnel.rs
Comment thread frontend/src/components/Albums/ShareAlbumDialog.tsx
Comment thread frontend/src/components/Albums/ShareAlbumDialog.tsx Outdated
Comment thread frontend/src/components/Albums/ShareAlbumDialog.tsx Outdated
Comment thread frontend/src/components/Albums/ShareAlbumDialog.tsx Outdated
Two concurrent starts could both find no tunnel, both spawn ssh, and leave the
first child running with nothing holding its handle. Start and stop now run
under one lock that covers the whole open-and-install transition.

Stopping captures the pid before killing, because CommandChild::kill consumes
the handle and cannot hand it back for a retry; a failure now names the process
still running rather than reporting nothing actionable.

tokio::sync was reaching us only through Tauri's own feature selection.
The close handler and the tray item did not cover every way the app can end.
RunEvent::Exit is the one path they all pass through, and an ssh child
outliving PictoPy leaves an album reachable from the internet.
Stopping a share checked a value the dialog might not have received yet, so a
share stopped before the status lookup resolved left the tunnel running, and a
failed stop reported success. The lifecycle moves into a hook that asks the
owner and lets failures reach the user.

Undoing a share whose tunnel could not be opened no longer claims the album was
withdrawn when the revoke itself failed, and reopening restores internet mode so
the help link and description match the link on screen.
The opening conflated storage with transit, which hid the relay from anyone who
stopped reading early. Local sharing was described as fully private when it is
plain HTTP and openable by anyone on the network holding the link.

The example response also carried a real-looking share token, which is the
credential that authorises access to an album.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src-tauri/src/services/tunnel.rs`:
- Around line 268-270: The shutdown path around TunnelState::shutdown must
handle a tunnel still starting, not only the child in active: ensure the SSH
child is tracked before URL discovery or coordinate cancellation and waiting
with lifecycle so shutdown cannot complete while startup owns a child. Add an
interleaving test covering shutdown during open/startup, then run cargo fmt and
cargo test from frontend/src-tauri.

In `@frontend/src/hooks/useShareTunnel.ts`:
- Around line 12-52: Add a shared ShareTunnel type in Share.ts describing the
url, isConnecting, refresh, open, and close members returned by useShareTunnel.
Import that type into useShareTunnel and explicitly declare useShareTunnel as
returning ShareTunnel, preserving the existing callback behavior and inferred
member signatures.
- Around line 17-20: Update useShareTunnel’s refresh and tunnel lifecycle
handling to track a revision in a ref, and only apply refresh results while no
later open or stopTunnel cycle has completed. Prevent a delayed null
tunnelStatus response from overwriting the URL set by a successful
open/startTunnel flow, and add a race test covering delayed tunnelStatus with
successful startTunnel.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 174e8707-b956-4b6e-9023-565ccb517488

📥 Commits

Reviewing files that changed from the base of the PR and between 5d305c8 and e2f7576.

📒 Files selected for processing (8)
  • docs/backend/backend_python/album-sharing.md
  • docs/overview/sharing-albums.md
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/src/main.rs
  • frontend/src-tauri/src/services/tunnel.rs
  • frontend/src/components/Albums/ShareAlbumDialog.tsx
  • frontend/src/components/Albums/__tests__/ShareAlbumDialog.test.tsx
  • frontend/src/hooks/useShareTunnel.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • frontend/src-tauri/Cargo.toml
  • frontend/src/components/Albums/tests/ShareAlbumDialog.test.tsx
  • docs/backend/backend_python/album-sharing.md
  • frontend/src/components/Albums/ShareAlbumDialog.tsx
  • docs/overview/sharing-albums.md

Comment thread frontend/src-tauri/src/services/tunnel.rs Outdated
Comment thread frontend/src/hooks/useShareTunnel.ts Outdated
Comment thread frontend/src/hooks/useShareTunnel.ts
Exiting while a tunnel was still starting left the child untracked, so nothing
could kill it and an album stayed reachable from the internet after PictoPy had
gone. The child is now tracked the moment it spawns, with the URL filled in
afterwards.

The lifecycle moves behind a small trait so it can be exercised without
spawning ssh: six tests now cover stopping, a refused kill, forgetting only the
current tunnel, and killing a child that never announced anything.
The status query fired when the dialog opens can resolve after a tunnel has
been opened, and its stale answer would drop the address just obtained. Results
are applied only while no newer open or close has completed.

The hook's shape is now declared as ShareTunnel alongside the other share types
rather than left to inference.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src-tauri/src/services/tunnel.rs`:
- Around line 259-262: Update the tunnel lifecycle coordination around
tunnel_start, state.track, and shutdown/state.stop so a shutdown request is
recorded before shutdown returns, and tunnel_start immediately stops any child
obtained after that request instead of announcing it. Preserve normal startup
behavior, and add an interleaving test covering shutdown during spawn_ssh().

In `@frontend/src/hooks/useShareTunnel.ts`:
- Around line 39-66: Serialize the lifecycle operations in useShareTunnel around
open and close so a close request cannot observe a pending start as absent or
allow its late result to be applied. Ensure close ultimately stops any tunnel
started by open and prevents stale state from being published, then add coverage
for close invoked while startTunnel is pending.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bb8423df-c597-438d-b6ec-841cbce17216

📥 Commits

Reviewing files that changed from the base of the PR and between e2f7576 and 701eb91.

📒 Files selected for processing (5)
  • frontend/src-tauri/src/services/tunnel.rs
  • frontend/src/components/Albums/ShareAlbumDialog.tsx
  • frontend/src/components/Albums/__tests__/ShareAlbumDialog.test.tsx
  • frontend/src/hooks/useShareTunnel.ts
  • frontend/src/types/Share.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/components/Albums/tests/ShareAlbumDialog.test.tsx
  • frontend/src/components/Albums/ShareAlbumDialog.tsx

Comment thread frontend/src-tauri/src/services/tunnel.rs
Comment thread frontend/src/hooks/useShareTunnel.ts
Exit could land between ssh being spawned and its handle being tracked: the
shutdown found nothing to kill, and the start then installed a child that
outlived the application. The refusal is recorded under the same lock the start
uses to track, so whichever arrives second kills the process.
Closing while a start was in flight read a status of null, skipped the stop
entirely, and then applied a live public address once the slow start answered.
The stop is now unconditional, since the owner already holds the child and
stopping nothing is a no-op, and a start that finishes after a close shuts its
own tunnel down rather than handing it back.
findBy waits one second by default, but the delete mutation retries twice with
a 500ms backoff before it reports failure, so the assertion raced the retry
schedule and failed under load.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/hooks/__tests__/useShareTunnel.test.ts`:
- Around line 1-3: Rename the useShareTunnel test file from the .test.ts
extension to .test.tsx, preserving its existing contents and location under the
__tests__ directory.
- Around line 11-13: Replace the `jest.Mock` casts for `mockStartTunnel`,
`mockStopTunnel`, and `mockTunnelStatus` with `jest.mocked()` wrappers so each
mocked tunnel utility retains its original parameter and return types.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 36336ea4-98b5-4bb6-9bcf-14da6e153152

📥 Commits

Reviewing files that changed from the base of the PR and between 701eb91 and 7182699.

📒 Files selected for processing (4)
  • frontend/src-tauri/src/services/tunnel.rs
  • frontend/src/hooks/__tests__/useShareTunnel.test.ts
  • frontend/src/hooks/useShareTunnel.ts
  • frontend/src/pages/__tests__/Album.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/hooks/useShareTunnel.ts
  • frontend/src-tauri/src/services/tunnel.rs

Comment thread frontend/src/hooks/__tests__/useShareTunnel.test.ts
Comment thread frontend/src/hooks/__tests__/useShareTunnel.test.ts
@rohan-pandeyy
rohan-pandeyy merged commit d1ccba1 into AOSSIE-Org:main Aug 9, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Share an album beyond the local network

1 participant