Skip to content

Conversation

@dkaser
Copy link
Collaborator

@dkaser dkaser commented Dec 30, 2025

Summary by CodeRabbit

  • New Features

    • Pages now display a "Tailscale is not yet ready." warning while the service initializes.
  • Bug Fixes

    • Dashboard and other Tailscale pages perform a centralized readiness check before showing data to prevent incomplete or missing information.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot added the fix label Dec 30, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

Warning

Rate limit exceeded

@dkaser has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 34 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1057f56 and efea023.

📒 Files selected for processing (1)
  • src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php
📝 Walkthrough

Walkthrough

Adds LocalAPI readiness detection and a centralized page gate. Introduces LocalAPI::isReady() and Utils::pageChecks($tr). Several page controllers now call the gate and return early if checks fail. Dashboard shows warnings.not_ready and skips building dashboard rows when LocalAPI isn't ready.

Changes

Cohort / File(s) Summary
Page validation refactoring
src/usr/local/emhttp/plugins/tailscale/include/Pages/Info.php, src/usr/local/emhttp/plugins/tailscale/include/Pages/Lock.php, src/usr/local/emhttp/plugins/tailscale/include/Pages/Status.php, src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php
Replaced per-page Config-based enable checks and inline disable messages with a centralized Utils::pageChecks($tr) guard; pages now return early if the gate fails.
Dashboard readiness handling
src/usr/local/emhttp/plugins/tailscale/include/Pages/Dashboard.php
Added LocalAPI readiness check; if not ready emits warnings.not_ready and skips initializing Info or building dashboard rows; otherwise proceeds to build Online, HostName, DNSName, and IPs rows.
Utility validation method
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php
Added public static function pageChecks(Translator $tr): bool that verifies Config->Enable and LocalAPI::isReady(), emitting translated messages and returning false when checks fail.
LocalAPI readiness method
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php
Added public function isReady(): bool that checks socket existence and queries local API v0/status; returns true when BackendState is Running, NeedsLogin, or NeedsMachineAuth; suppresses exceptions and returns false on errors or missing socket.
Localization
src/usr/local/emhttp/plugins/tailscale/locales/en_US.json
Added warnings.not_ready key with value "Tailscale is not yet ready.".

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Page as Page Controller
participant Utils as Utils::pageChecks
participant LocalAPI as LocalAPI
participant Translator as Translator
Note over Page,Utils: Page rendering begins
Page->>Utils: call pageChecks(tr)
Utils->>LocalAPI: instantiate / call isReady()
LocalAPI->>LocalAPI: check socket; call v0/status
alt LocalAPI ready
LocalAPI-->>Utils: true
Utils-->>Page: true
Page->>Page: proceed to initialize Info / build dashboard rows
else Not ready or disabled
LocalAPI-->>Utils: false
Utils-->>Page: false + translated message via Translator
Page->>Page: emit warnings.not_ready and return early
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: blocking dependent pages when the local API is not ready, which aligns with the core modifications across Dashboard, Info, Lock, Status, and Tailscale pages.

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (1)

169-182: Excellent centralization of page validation logic.

The new pageChecks() method effectively consolidates readiness validation across multiple pages, reducing code duplication and ensuring consistent behavior.

Optional: Consider caching instances to reduce overhead

If performance becomes a concern, you could cache the Config and LocalAPI instances to avoid recreating them on every call:

 public static function pageChecks(Translator $tr): bool
 {
-    if ( ! (new Config())->Enable) {
+    static $config = null;
+    static $localAPI = null;
+    
+    if ($config === null) {
+        $config = new Config();
+        $localAPI = new LocalAPI();
+    }
+    
+    if ( ! $config->Enable) {
         echo($tr->tr("tailscale_disabled"));
         return false;
     }

-    if ( ! (new LocalAPI())->isReady()) {
+    if ( ! $localAPI->isReady()) {
         echo($tr->tr("warnings.not_ready"));
         return false;
     }

     return true;
 }

Note: Only implement this if profiling shows the current approach is a bottleneck.

src/usr/local/emhttp/plugins/tailscale/locales/en_US.json (1)

105-105: Clear and helpful warning message added.

The new not_ready warning appropriately informs users about the temporary unavailability.

For enhanced user experience, consider implementing an auto-refresh mechanism (e.g., meta refresh tag or JavaScript polling) so users don't need to manually refresh the page. This could be added in a future iteration.

src/usr/local/emhttp/plugins/tailscale/include/Pages/Dashboard.php (1)

34-47: Consider aligning Dashboard validation with other pages.

Unlike Info, Lock, Status, and Tailscale pages which use Utils::pageChecks(), Dashboard implements its own readiness validation. While the logic is correct, this inconsistency creates a maintenance burden and could lead to behavioral drift over time.

Consider refactoring to use a pattern closer to the other pages. Since Dashboard needs to display content rather than early-return, you could separate the checks:

Suggested approach
 $tr = $tr ?? new Translator(PLUGIN_ROOT);
 
 $tailscaleConfig = $tailscaleConfig ?? new Config();
 
-$tailscale_dashboard = "<tr><td>" . $tr->tr("tailscale_disabled") . "</td></tr>";
-
-if ($tailscaleConfig->Enable) {
-    $localAPI = $localAPI ?? new LocalAPI();
-    if ( ! $localAPI->isReady()) {
-        $tailscale_dashboard = "<tr><td>" . $tr->tr("warnings.not_ready") . "</td></tr>";
-    } else {
-        $tailscaleInfo     = $tailscaleInfo ?? new Info($tr);
-        $tailscaleDashInfo = $tailscaleInfo->getDashboardInfo();
-
-        $tailscale_dashboard = Utils::printDash($tr->tr("info.online"), $tailscaleDashInfo->Online);
-        $tailscale_dashboard .= Utils::printDash($tr->tr("info.hostname"), $tailscaleDashInfo->HostName);
-        $tailscale_dashboard .= Utils::printDash($tr->tr("info.dns"), $tailscaleDashInfo->DNSName);
-        $tailscale_dashboard .= Utils::printDash($tr->tr("info.ip"), implode("<br><span class='w26'>&nbsp;</span>", $tailscaleDashInfo->TailscaleIPs));
-    }
+if ( ! $tailscaleConfig->Enable) {
+    $tailscale_dashboard = "<tr><td>" . $tr->tr("tailscale_disabled") . "</td></tr>";
+} elseif ( ! (new LocalAPI())->isReady()) {
+    $tailscale_dashboard = "<tr><td>" . $tr->tr("warnings.not_ready") . "</td></tr>";
+} else {
+    $tailscaleInfo     = $tailscaleInfo ?? new Info($tr);
+    $tailscaleDashInfo = $tailscaleInfo->getDashboardInfo();
+
+    $tailscale_dashboard = Utils::printDash($tr->tr("info.online"), $tailscaleDashInfo->Online);
+    $tailscale_dashboard .= Utils::printDash($tr->tr("info.hostname"), $tailscaleDashInfo->HostName);
+    $tailscale_dashboard .= Utils::printDash($tr->tr("info.dns"), $tailscaleDashInfo->DNSName);
+    $tailscale_dashboard .= Utils::printDash($tr->tr("info.ip"), implode("<br><span class='w26'>&nbsp;</span>", $tailscaleDashInfo->TailscaleIPs));
 }

This flattens the nesting and makes the three states (disabled, not ready, ready) more explicit.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3025df7 and 81807a2.

📒 Files selected for processing (8)
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Dashboard.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Info.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Lock.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Status.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php
  • src/usr/local/emhttp/plugins/tailscale/locales/en_US.json
  • src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php
  • src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-11T00:22:27.117Z
Learnt from: dkaser
Repo: unraid/unraid-tailscale PR: 66
File: src/usr/local/emhttp/plugins/tailscale/include/Pages/Settings.php:218-218
Timestamp: 2025-11-11T00:22:27.117Z
Learning: In the unraid-tailscale plugin, pages with `Tabs="true"` (like Tailscale.page) and their submenu pages (like Tailscale-1-Settings.page) share the same JavaScript scope. JavaScript functions defined in Tailscale.php are accessible in Settings.php because they load in the same browser context.

Applied to files:

  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Lock.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Info.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Status.php
  • src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php
🧬 Code graph analysis (5)
src/usr/local/emhttp/plugins/tailscale/include/Pages/Lock.php (1)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (2)
  • Utils (25-183)
  • pageChecks (169-182)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (3)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Info.php (1)
  • tr (66-69)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Config.php (1)
  • Config (22-66)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php (2)
  • LocalAPI (29-247)
  • isReady (105-123)
src/usr/local/emhttp/plugins/tailscale/include/Pages/Dashboard.php (3)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php (2)
  • LocalAPI (29-247)
  • isReady (105-123)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Info.php (3)
  • tr (66-69)
  • Info (24-507)
  • getDashboardInfo (134-146)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (2)
  • Utils (25-183)
  • printDash (42-45)
src/usr/local/emhttp/plugins/tailscale/include/Pages/Status.php (1)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (2)
  • Utils (25-183)
  • pageChecks (169-182)
src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php (1)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (2)
  • Utils (25-183)
  • pageChecks (169-182)
🔇 Additional comments (6)
src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/Utils.php (1)

23-23: LGTM: Translator import added for pageChecks method.

The import is necessary for the new pageChecks() method signature and is correctly placed.

src/usr/local/emhttp/plugins/tailscale/include/Pages/Lock.php (1)

30-32: LGTM: Clean adoption of centralized page validation.

The page correctly uses the new Utils::pageChecks() gate, removing the previous per-page enable check and simplifying the code.

src/usr/local/emhttp/plugins/tailscale/include/Pages/Status.php (1)

30-32: LGTM: Consistent adoption of centralized validation.

The page correctly implements the new Utils::pageChecks() gate, maintaining consistency with other pages in the plugin.

src/usr/local/emhttp/plugins/tailscale/include/Pages/Info.php (1)

30-32: LGTM: Proper use of centralized validation gate.

The page correctly adopts Utils::pageChecks(), replacing the previous per-page enable check with the centralized approach.

src/usr/local/emhttp/plugins/tailscale/include/Pages/Tailscale.php (1)

33-35: LGTM: Consistent implementation of centralized gate.

The page correctly uses Utils::pageChecks(), maintaining consistency with the other pages in the plugin.

src/usr/local/php/unraid-tailscale-utils/unraid-tailscale-utils/LocalAPI.php (1)

105-123: Good implementation of readiness check with appropriate error suppression.

The isReady() method correctly implements a non-intrusive readiness check by:

  • Fast-failing on missing socket
  • Gracefully handling errors without logging (appropriate for a readiness probe)
  • Checking the BackendState for operational status

The check for BackendState === 'Running' is correct—this is the only state that indicates Tailscale is fully operational and ready to handle requests. Other possible states (NoState, NeedsLogin, NeedsMachineAuth, Stopped, Starting) all represent conditions where the system is unavailable or not yet ready.

Signed-off-by: Derek Kaser <[email protected]>
Signed-off-by: Derek Kaser <[email protected]>
Signed-off-by: Derek Kaser <[email protected]>
@dkaser dkaser merged commit 6c9080c into trunk Dec 30, 2025
5 checks passed
@dkaser dkaser deleted the fix/not-ready branch December 30, 2025 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants