mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-12 15:29:43 -04:00
feat(tailscale): add Tailscale control center widget (#1875)
* feat(tailscale): add Tailscale control center widget Full-stack Tailscale integration for DMS control center: Backend (Go): - Event-driven manager via WatchIPNBus (no polling) - Reconnects with exponential backoff when tailscaled unavailable - Typed conversion from ipnstate.Status to QML-friendly IPC types - Testable via tailscaleClient interface with mock watcher - Manager cleanup in cleanupManagers() - 19 unit tests Frontend (QML): - TailscaleService with WebSocket subscription - TailscaleWidget with peer list, filter chips, search - Copy-to-clipboard for IPs and DNS names - Daemon lifecycle handling (offline/stopped states) Dependencies: - Add tailscale.com v1.96.1 (official local API client) - Bump Go to 1.26.1 (required by tailscale.com) * cleanups --------- Co-authored-by: bbedward <bbedward@gmail.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/network"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/sysupdate"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/tailscale"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/thememode"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/trayrecovery"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland"
|
||||
@@ -65,6 +66,7 @@ var waylandManager *wayland.Manager
|
||||
var bluezManager *bluez.Manager
|
||||
var appPickerManager *apppicker.Manager
|
||||
var cupsManager *cups.Manager
|
||||
var tailscaleManager *tailscale.Manager
|
||||
var dwlManager *dwl.Manager
|
||||
var extWorkspaceManager *extworkspace.Manager
|
||||
var brightnessManager *brightness.Manager
|
||||
@@ -489,6 +491,10 @@ func getCapabilities() Capabilities {
|
||||
caps = append(caps, "cups")
|
||||
}
|
||||
|
||||
if tailscaleManager != nil && tailscaleManager.IsAvailable() {
|
||||
caps = append(caps, "tailscale")
|
||||
}
|
||||
|
||||
if dwlManager != nil {
|
||||
caps = append(caps, "dwl")
|
||||
}
|
||||
@@ -559,6 +565,10 @@ func getServerInfo() ServerInfo {
|
||||
caps = append(caps, "cups")
|
||||
}
|
||||
|
||||
if tailscaleManager != nil && tailscaleManager.IsAvailable() {
|
||||
caps = append(caps, "tailscale")
|
||||
}
|
||||
|
||||
if dwlManager != nil {
|
||||
caps = append(caps, "dwl")
|
||||
}
|
||||
@@ -1039,6 +1049,38 @@ func handleSubscribe(conn net.Conn, req models.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if shouldSubscribe("tailscale") && tailscaleManager != nil && tailscaleManager.IsAvailable() {
|
||||
wg.Add(1)
|
||||
tailscaleChan := tailscaleManager.Subscribe(clientID + "-tailscale")
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer tailscaleManager.Unsubscribe(clientID + "-tailscale")
|
||||
|
||||
initialState := tailscaleManager.GetState()
|
||||
select {
|
||||
case eventChan <- ServiceEvent{Service: "tailscale", Data: initialState}:
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case state, ok := <-tailscaleChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case eventChan <- ServiceEvent{Service: "tailscale", Data: state}:
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
case <-stopChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if shouldSubscribe("dwl") && dwlManager != nil {
|
||||
wg.Add(1)
|
||||
dwlChan := dwlManager.Subscribe(clientID + "-dwl")
|
||||
@@ -1409,11 +1451,22 @@ func cleanupManagers() {
|
||||
if geoClientInstance != nil {
|
||||
geoClientInstance.Close()
|
||||
}
|
||||
if tailscaleManager != nil {
|
||||
tailscaleManager.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Start(printDocs bool) error {
|
||||
cleanupStaleSockets()
|
||||
|
||||
// Tailscale manager always starts — reconnects internally via WatchIPNBus.
|
||||
// The capability is only advertised once tailscaled is reachable; the
|
||||
// callback wakes capability subscribers so QML clients see it transition.
|
||||
tailscaleManager = tailscale.NewManager("")
|
||||
tailscaleManager.SetAvailabilityCallback(func(bool) {
|
||||
notifyCapabilityChange()
|
||||
})
|
||||
|
||||
socketPath := GetSocketPath()
|
||||
os.Remove(socketPath)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user