From 3eba8fbd243c0ffcb1c396526a4e19d1abc1eaf9 Mon Sep 17 00:00:00 2001 From: hachem Date: Sat, 29 Aug 2026 19:15:28 +0200 Subject: add: control flow --- internal/cli/commands.go | 20 ++++++++++++ internal/cli/server.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 internal/cli/server.go (limited to 'internal/cli') diff --git a/internal/cli/commands.go b/internal/cli/commands.go index d76402d..437fff2 100644 --- a/internal/cli/commands.go +++ b/internal/cli/commands.go @@ -16,6 +16,26 @@ func defaultCommands() []command { desc: "Manage mods โ€” list, search, add, pin versions, remove", run: runMods, }, + { + name: "start", + desc: "Start the server in the background", + run: runStart, + }, + { + name: "stop", + desc: "Stop the running server", + run: runStop, + }, + { + name: "restart", + desc: "Restart the server", + run: runRestart, + }, + { + name: "status", + desc: "Show whether the server is running, players, and version", + run: runStatus, + }, { name: "check", desc: "Check whether the configured mods are compatible", diff --git a/internal/cli/server.go b/internal/cli/server.go new file mode 100644 index 0000000..9ed0fea --- /dev/null +++ b/internal/cli/server.go @@ -0,0 +1,84 @@ +package cli + +import ( + "fmt" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + + "github.com/hachem-wtf/benson/internal/config" + "github.com/hachem-wtf/benson/internal/server" +) + +func runStart(m *model) tea.Cmd { + pid, err := server.Start(m.cfg) + if err != nil { + return tea.Println(errorStyle.Render(err.Error())) + } + return tea.Println(successStyle.Render("Server started ") + + mutedStyle.Render(fmt.Sprintf("(pid %d) ยท logs: %s", pid, server.LogPath(m.cfg)))) +} + +func runStop(m *model) tea.Cmd { + return m.runServerJob(func(cfg *config.Config, emit func(string)) tea.Msg { + if err := server.Stop(cfg, emit); err != nil { + return streamDoneMsg{errorStyle.Render(err.Error())} + } + return streamDoneMsg{successStyle.Render("Server stopped.")} + }) +} + +func runRestart(m *model) tea.Cmd { + return m.runServerJob(func(cfg *config.Config, emit func(string)) tea.Msg { + if err := server.Restart(cfg, emit); err != nil { + return streamDoneMsg{errorStyle.Render(err.Error())} + } + return streamDoneMsg{successStyle.Render("Server restarted.")} + }) +} + +func runStatus(m *model) tea.Cmd { + m.busy = true + cfg := m.cfg + return tea.Batch(m.spin.Tick, func() tea.Msg { + return outputMsg{text: renderStatus(server.GetStatus(cfg))} + }) +} + +func (m *model) runServerJob(job func(cfg *config.Config, emit func(string)) tea.Msg) tea.Cmd { + m.busy = true + ch := make(chan tea.Msg, 64) + m.events = ch + cfg := m.cfg + go func() { + emit := func(line string) { ch <- streamMsg{" " + mutedStyle.Render(line)} } + ch <- job(cfg, emit) + }() + return tea.Batch(m.spin.Tick, waitForEvent(ch)) +} + +func renderStatus(s server.Status) string { + rows := []string{headingStyle.Render("Server status"), ""} + + if s.Running { + rows = append(rows, " "+successStyle.Render("โ— running")+mutedStyle.Render(fmt.Sprintf(" (pid %d)", s.PID))) + } else { + rows = append(rows, " "+errorStyle.Render("โ— stopped")) + } + + rows = append(rows, " "+mutedStyle.Render("address ")+s.Address) + + if s.Reachable { + rows = append(rows, + " "+mutedStyle.Render("version ")+s.Version, + " "+mutedStyle.Render("players ")+fmt.Sprintf("%d / %d", s.Players, s.MaxPlayers), + ) + if s.MOTD != "" { + rows = append(rows, " "+mutedStyle.Render("motd ")+s.MOTD) + } + } else if s.Running { + rows = append(rows, " "+warnStyle.Render("not yet accepting connections (still loading?)")) + } + + return lipgloss.JoinVertical(lipgloss.Left, rows...) +} -- cgit v1.3