Skip to content

feat(tray): enforce single instance and expose reachable URLs#986

Merged
rsdmike merged 2 commits into
mainfrom
singleton
May 18, 2026
Merged

feat(tray): enforce single instance and expose reachable URLs#986
rsdmike merged 2 commits into
mainfrom
singleton

Conversation

@rsdmike
Copy link
Copy Markdown
Member

@rsdmike rsdmike commented May 18, 2026

A second invocation now detects the running instance via a per-user
flock (Unix) or named mutex (Windows), opens the existing tray's URL
in the browser, and exits cleanly rather than racing on port 8181.
The lock FD is inherited across the background re-exec so it survives
parent exit.

Default HTTP_HOST changes from "localhost" to wildcard so the tray
is reachable from other devices on the LAN. The tray menu and
startup log enumerate every routable IPv4, filtering virtual bridges
(docker, veth, br-, tun/tap, virbr, vmnet, vboxnet, wg, zt, awdl,
llw) and deduping.

When bound to a wildcard, the UI's injected ##CONSOLE_SERVER_API##
resolves to a relative URL so same-origin fetches match the user's
actual host/SNI.

Refs: Package Console as an installer #870

Copilot AI review requested due to automatic review settings May 18, 2026 21:08
@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

Codecov Report

❌ Patch coverage is 93.33333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 41.47%. Comparing base (3c696e6) to head (9780cea).

Files with missing lines Patch % Lines
internal/controller/httpapi/ui.go 92.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #986      +/-   ##
==========================================
+ Coverage   41.41%   41.47%   +0.06%     
==========================================
  Files         134      134              
  Lines       12321    12334      +13     
==========================================
+ Hits         5103     5116      +13     
  Misses       6672     6672              
  Partials      546      546              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates tray-mode startup behavior to enforce a single running instance, expose LAN-reachable URLs when binding wildcard hosts, and make the UI use same-origin API calls for wildcard bindings.

Changes:

  • Default HTTP binding changes from localhost to wildcard/empty host.
  • Tray mode now computes reachable URLs, logs them, and attempts single-instance handling on Unix/Windows.
  • UI config injection now returns a relative API base for wildcard hosts and adds tests for URL generation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
internal/controller/httpapi/ui.go Adds wildcard host detection and API base URL construction via net.JoinHostPort.
internal/controller/httpapi/ui_test.go Adds tests for API base URL generation.
config/config.go Makes HTTP_HOST optional and defaults it to wildcard binding.
config/config_test.go Updates default host expectation.
cmd/app/tray.go Adds reachable URL discovery, tray startup logging, and single-instance invocation flow.
cmd/app/tray_windows.go Adds named-mutex based single-instance handling and browser/message surfacing.
cmd/app/tray_unix.go Adds flock-based single-instance handling and lock FD inheritance across re-exec.
cmd/app/tray_test.go Adds tray helper tests for wildcard hosts and virtual interface filtering.
.env.example Documents empty HTTP_HOST as binding all interfaces.
Comments suppressed due to low confidence (2)

cmd/app/tray.go:49

  • The PR description says the tray menu enumerates every reachable URL, but this still passes only primaryURL into tray.Config, whose menu renders a single status/open URL. The startup log lists all URLs, but the tray UI does not expose the additional LAN addresses.
	trayManager := tray.New(tray.Config{
		AppName:  "DMT Console",
		URL:      primaryURL,
		Headless: isHeadlessBuild,

cmd/app/tray_windows.go:36

  • If creating the named mutex fails, the function returns and startup proceeds without single-instance protection, so duplicate tray processes can still race on the HTTP port. Treat mutex creation failures as startup errors or provide a fallback rather than silently disabling the guard.
	handle, _, lastErr := createMutex.Call(0, 0, uintptr(unsafe.Pointer(namePtr)))
	if handle == 0 {
		return

Comment thread cmd/app/tray_windows.go Outdated
Comment thread internal/controller/httpapi/ui.go Outdated
Comment thread cmd/app/tray.go Outdated
Comment thread config/config.go
Comment thread .env.example
Comment thread cmd/app/tray.go
Comment thread cmd/app/tray_unix.go
Comment thread cmd/app/tray_unix.go
  A second invocation now detects the running instance via a per-user
  flock (Unix) or named mutex (Windows), opens the existing tray's URL
  in the browser, and exits cleanly rather than racing on port 8181.
  The lock FD is inherited across the background re-exec so it survives
  parent exit.

  Default HTTP_HOST changes from "localhost" to wildcard so the tray
  is reachable from other devices on the LAN. The tray menu and
  startup log enumerate every routable IPv4, filtering virtual bridges
  (docker, veth, br-, tun/tap, virbr, vmnet, vboxnet, wg, zt, awdl,
  llw) and deduping.

  When bound to a wildcard, the UI's injected ##CONSOLE_SERVER_API##
  resolves to a relative URL so same-origin fetches match the user's
  actual host/SNI.

Refs: Package Console as an installer #870
@rsdmike rsdmike merged commit 676bd75 into main May 18, 2026
20 checks passed
@rsdmike rsdmike deleted the singleton branch May 18, 2026 21:52
@RosieAMT
Copy link
Copy Markdown

🎉 This PR is included in version 1.27.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@graikhel-intel graikhel-intel linked an issue May 18, 2026 that may be closed by this pull request
5 tasks
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.

Package Console as an installer

4 participants