5013148ffe
User-reported install fixes: - Branding: every user-facing 'SSO Manager' string now says 'Theta Directory' (agent logs, CLI usage, agent.yml.example, installer wizard). - Wizard page: the URL/join-key text boxes were never shown. The layout used Surface.Width (0 at wizard init) instead of SurfaceWidth and combined WordWrap with AutoSize (mutually exclusive in VCL). Rewritten with the canonical Inno pattern (SurfaceWidth + ScaleY + explicit label height). - No console window after install: the tray and helper now build as GUI-subsystem binaries (-H=windowsgui) in build_all.sh and scripts/setup-build-env.ps1. The agent stays a console app for foreground debugging (as a service it never shows a console). - The daemon never came up after install: install-service now starts the service immediately, so the tray IPC socket exists right away and the tray connects instead of logging 'actively refused' until a reboot. Verified: go build/vet/test green; tray+helper PE subsystem = GUI (2), agent = console (3); installer compiles; tray runs silently.
105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"syscall"
|
|
)
|
|
|
|
// wsConnected is flipped atomically by connectWebSocket as the connection
|
|
// comes up and drops, so StartHomeMonitor can read it without a mutex.
|
|
var wsConnected atomic.Bool
|
|
|
|
// agentStopCh closes once the agent should exit: a SIGINT/SIGTERM in the
|
|
// foreground, or the SCM stop request when running as a Windows service. Both
|
|
// runAgent (foreground) and the service handler wait on it.
|
|
var (
|
|
agentStopOnce sync.Once
|
|
agentStopCh = make(chan struct{})
|
|
)
|
|
|
|
// currentCM lets the tray IPC server persist preferences (auto_vpn) and reset
|
|
// enrollment into the live config file. Set once in runAgent.
|
|
var currentCM *ConfigManager
|
|
|
|
// stopAgent signals the running agent to shut down. Idempotent.
|
|
func stopAgent() {
|
|
agentStopOnce.Do(func() { close(agentStopCh) })
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 && handleCLI(os.Args[1:]) {
|
|
return
|
|
}
|
|
|
|
// Windows: when installed as a service the SCM starts us and svc.Run takes
|
|
// over the process lifecycle. Foreground (or any other OS) falls through to
|
|
// runAgent, which blocks until a signal arrives.
|
|
if maybeRunAsService() {
|
|
return
|
|
}
|
|
|
|
runAgent()
|
|
}
|
|
|
|
// runAgent runs the agent daemon until stopAgent is called.
|
|
func runAgent() {
|
|
log.Println("Starting Theta Agent...")
|
|
|
|
// Attempt to load configuration
|
|
configPath := defaultConfigPath()
|
|
if len(os.Args) > 1 && !strings.HasPrefix(os.Args[1], "-") {
|
|
configPath = os.Args[1]
|
|
}
|
|
|
|
cm, err := NewConfigManager(configPath)
|
|
if err != nil {
|
|
log.Fatalf("Error loading configuration from %s: %v", configPath, err)
|
|
}
|
|
cfg := cm.Get()
|
|
|
|
log.Printf("Connecting to Theta Directory at %s", cfg.ServerURL)
|
|
log.Printf("Loaded capabilities: Telemetry=%v, LDAP=%v, Reboot=%v, Bash=%v",
|
|
cfg.Capabilities.Telemetry,
|
|
cfg.Capabilities.ConfigureLDAP,
|
|
cfg.Capabilities.Reboot,
|
|
cfg.Capabilities.ArbitraryBash,
|
|
)
|
|
|
|
// Initialize system executor and pin the platform ops the command
|
|
// dispatcher runs behind.
|
|
exec := &SystemExecutor{}
|
|
defaultPlatformOps = NewPlatformOps(cfg, exec)
|
|
currentCM = cm
|
|
|
|
// Seed the auto-VPN preference from disk; the tray checkbox updates it.
|
|
SetAutoVPN(cfg.AutoVPN)
|
|
|
|
// Tray IPC server — desktop tray connects here for status updates.
|
|
go globalTrayServer.Start()
|
|
|
|
// WebSocket connection to Theta Directory
|
|
go connectWebSocket(cm, exec)
|
|
|
|
// Home detection + tray status push (polls public IP every 60s).
|
|
go StartHomeMonitor(cfg, func() bool { return wsConnected.Load() })
|
|
|
|
// Foreground: exit on SIGINT/SIGTERM. A Windows service ignores these and
|
|
// is driven by its own handler.
|
|
go func() {
|
|
sigs := make(chan os.Signal, 1)
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
<-sigs
|
|
stopAgent()
|
|
}()
|
|
|
|
<-agentStopCh
|
|
|
|
fmt.Println("Shutting down Theta Agent...")
|
|
}
|