feat(daemon): Enhances the display of daemon startup information and the reading of configuration data.

- Added support for parsing the --address/-a and --server/-s parameters.
- At startup, attempt to load the server address from the configuration file.
- Wait and retrieve runtime information for the daemon (such as the URL).
- Optimized UI display: Shows forwarding address, server address, and access link.
- Supports centering the generated tunnel URL information in the terminal.
- Added the utility functions parseFlagValue and waitForDaemonInfo for parameter parsing and status waiting.
This commit is contained in:
Gouryella
2025-12-13 21:54:43 +08:00
parent 0c19c3300c
commit f1a65ac965
2 changed files with 105 additions and 7 deletions

View File

@@ -8,6 +8,7 @@ import (
"time"
"drip/internal/shared/ui"
"drip/pkg/config"
json "github.com/goccy/go-json"
)
@@ -196,11 +197,64 @@ func StartDaemon(tunnelType string, port int, args []string) error {
_ = logFile.Close()
_ = devNull.Close()
fmt.Println(ui.RenderDaemonStarted(tunnelType, port, cmd.Process.Pid, logPath))
localHost := parseFlagValue(cleanArgs, "--address", "-a", "127.0.0.1")
displayHost := localHost
if displayHost == "127.0.0.1" {
displayHost = "localhost"
}
forwardAddr := fmt.Sprintf("%s:%d", displayHost, port)
serverAddr := parseFlagValue(cleanArgs, "--server", "-s", "")
if serverAddr == "" {
if cfg, err := config.LoadClientConfig(""); err == nil {
serverAddr = cfg.Server
}
}
var url string
info, err := waitForDaemonInfo(tunnelType, port, cmd.Process.Pid, 30*time.Second)
if err == nil && info != nil && info.PID == cmd.Process.Pid && info.URL != "" {
url = info.URL
if info.Server != "" {
serverAddr = info.Server
}
}
fmt.Println(ui.RenderDaemonStarted(tunnelType, port, cmd.Process.Pid, logPath, url, forwardAddr, serverAddr))
return nil
}
func parseFlagValue(args []string, longName string, shortName string, defaultValue string) string {
for i := 0; i < len(args); i++ {
if args[i] == longName || args[i] == shortName {
if i+1 < len(args) && args[i+1] != "" {
return args[i+1]
}
}
}
return defaultValue
}
func waitForDaemonInfo(tunnelType string, port int, pid int, timeout time.Duration) (*DaemonInfo, error) {
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
if !IsProcessRunning(pid) {
return nil, nil
}
info, err := LoadDaemonInfo(tunnelType, port)
if err == nil && info != nil && info.PID == pid {
if info.URL != "" {
return info, nil
}
}
time.Sleep(50 * time.Millisecond)
}
return nil, nil
}
// CleanupStaleDaemons removes daemon info for processes that are no longer running
func CleanupStaleDaemons() error {
daemons, err := ListAllDaemons()

View File

@@ -2,6 +2,9 @@ package ui
import (
"fmt"
"strings"
"github.com/charmbracelet/lipgloss"
)
// RenderConfigInit renders config initialization UI
@@ -100,18 +103,59 @@ func RenderConfigValidation(serverValid bool, serverMsg string, tokenSet bool, t
}
// RenderDaemonStarted renders daemon started message
func RenderDaemonStarted(tunnelType string, port int, pid int, logPath string) string {
func RenderDaemonStarted(tunnelType string, port int, pid int, logPath string, url string, forwardAddr string, serverAddr string) string {
if forwardAddr == "" {
forwardAddr = fmt.Sprintf("localhost:%d", port)
}
urlLine := Muted("(resolving...)")
if url != "" {
urlBadge := lipgloss.NewStyle().
Background(successColor).
Foreground(lipgloss.Color("#f8fafc")).
Bold(true).
Padding(0, 1).
Render(url)
urlLine = urlBadge
}
headline := successStyle.Render("✓ Tunnel Started in Background")
lines := []string{
KeyValue("Type", Highlight(tunnelType)),
KeyValue("Port", fmt.Sprintf("%d", port)),
KeyValue("PID", fmt.Sprintf("%d", pid)),
KeyValue("Forward", forwardAddr),
}
if serverAddr != "" {
lines = append(lines, KeyValue("Server", serverAddr))
}
lines = append(lines,
"",
Muted("Commands:"),
Cyan(" drip list") + Muted(" Check tunnel status"),
Cyan(fmt.Sprintf(" drip attach %s %d", tunnelType, port)) + Muted(" View logs"),
Cyan(fmt.Sprintf(" drip stop %s %d", tunnelType, port)) + Muted(" Stop tunnel"),
Cyan(" drip list")+Muted(" Check tunnel status"),
Cyan(fmt.Sprintf(" drip attach %s %d", tunnelType, port))+Muted(" View logs"),
Cyan(fmt.Sprintf(" drip stop %s %d", tunnelType, port))+Muted(" Stop tunnel"),
"",
Muted("Logs: ") + mutedStyle.Render(logPath),
Muted("Logs: ")+mutedStyle.Render(logPath),
)
contentWidth := 0
for _, line := range append([]string{headline}, lines...) {
if w := lipgloss.Width(line); w > contentWidth {
contentWidth = w
}
}
return SuccessBox("Tunnel Started in Background", lines...)
if w := lipgloss.Width(urlLine); w > contentWidth {
contentWidth = w
}
centeredURL := lipgloss.PlaceHorizontal(contentWidth, lipgloss.Center, urlLine)
contentLines := make([]string, 0, len(lines)+4)
contentLines = append(contentLines, headline, "", centeredURL, "")
contentLines = append(contentLines, lines...)
return successBoxStyle.Render(strings.Join(contentLines, "\n"))
}