use tea model for showing server runnign and closing
This commit is contained in:
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/LazyBachelor/LazyPM/cmd/pm/tasks"
|
||||
@@ -19,11 +18,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
err := godotenv.Load(".env")
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error loading .env file")
|
||||
}
|
||||
godotenv.Load(".env")
|
||||
|
||||
models.BaseConfig = models.BaseConfig.LoadFromEnv()
|
||||
|
||||
|
||||
112
pkg/web/web.go
112
pkg/web/web.go
@@ -6,14 +6,19 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/LazyBachelor/LazyPM/internal/app"
|
||||
"github.com/LazyBachelor/LazyPM/internal/models"
|
||||
"github.com/LazyBachelor/LazyPM/internal/utils/browser"
|
||||
"github.com/LazyBachelor/LazyPM/pkg/web/handler"
|
||||
"github.com/LazyBachelor/LazyPM/pkg/web/server"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type Config = models.Config
|
||||
@@ -32,12 +37,50 @@ func New() *Web {
|
||||
//go:embed assets/*
|
||||
var assets embed.FS
|
||||
|
||||
type tuiModel struct {
|
||||
width int
|
||||
height int
|
||||
address string
|
||||
quitChan chan struct{}
|
||||
}
|
||||
|
||||
func (m tuiModel) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
return m, nil
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "q", "esc", "ctrl+c":
|
||||
select {
|
||||
case <-m.quitChan:
|
||||
default:
|
||||
close(m.quitChan)
|
||||
}
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m tuiModel) View() string {
|
||||
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, fmt.Sprintf(
|
||||
"Web server running at %s\n\nPress q, esc, or Ctrl+C to stop the task and server.\n",
|
||||
m.address,
|
||||
))
|
||||
}
|
||||
|
||||
func (w *Web) Run(ctx context.Context, config Config) error {
|
||||
app, cleanup, err := app.New(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer cleanup()
|
||||
|
||||
httpServer := server.NewServer(server.Server{
|
||||
@@ -46,21 +89,39 @@ func (w *Web) Run(ctx context.Context, config Config) error {
|
||||
App: app,
|
||||
})
|
||||
|
||||
fmt.Printf("Starting web server on %s...\n", config.WebAddress)
|
||||
|
||||
address := config.WebAddress
|
||||
if !strings.Contains(address, "http") {
|
||||
address = "http://localhost" + address
|
||||
}
|
||||
|
||||
err = browser.Open(address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open browser: %w", err)
|
||||
}
|
||||
|
||||
serverErr := make(chan error, 1)
|
||||
uiQuitChan := make(chan struct{})
|
||||
|
||||
screen := tea.NewProgram(
|
||||
tuiModel{
|
||||
address: address,
|
||||
quitChan: uiQuitChan,
|
||||
},
|
||||
tea.WithAltScreen(),
|
||||
)
|
||||
|
||||
screenDone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
defer close(screenDone)
|
||||
|
||||
if _, err := screen.Run(); err != nil {
|
||||
fmt.Printf("failed to start terminal UI: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(sigChan)
|
||||
|
||||
go func() {
|
||||
if err := httpServer.ListenAndServe(); err != nil &&
|
||||
!errors.Is(err, http.ErrServerClosed) {
|
||||
serverErr <- err
|
||||
}
|
||||
}()
|
||||
@@ -77,17 +138,36 @@ func (w *Web) Run(ctx context.Context, config Config) error {
|
||||
handler.SetSubmitChan(w.submitChan)
|
||||
}
|
||||
|
||||
if err := browser.Open(address); err != nil {
|
||||
fmt.Printf("failed to open browser: %s\n", err)
|
||||
}
|
||||
|
||||
var shutdownMsg string
|
||||
|
||||
select {
|
||||
case <-w.quitChan:
|
||||
fmt.Println("Task completed! Shutting down server...")
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
return httpServer.Shutdown(shutdownCtx)
|
||||
case err := <-serverErr:
|
||||
return err
|
||||
shutdownMsg = "Task completed! Ending task and server..."
|
||||
case <-uiQuitChan:
|
||||
shutdownMsg = "Quit key pressed. Ending task and server..."
|
||||
case sig := <-sigChan:
|
||||
shutdownMsg = fmt.Sprintf("Received signal %s. Ending task and server...", sig)
|
||||
case <-ctx.Done():
|
||||
return httpServer.Shutdown(context.Background())
|
||||
shutdownMsg = "Context cancelled. Ending task and server..."
|
||||
case err := <-serverErr:
|
||||
screen.Quit()
|
||||
<-screenDone
|
||||
return err
|
||||
}
|
||||
|
||||
screen.Quit()
|
||||
<-screenDone
|
||||
|
||||
fmt.Println(shutdownMsg)
|
||||
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
return httpServer.Shutdown(shutdownCtx)
|
||||
}
|
||||
|
||||
func (w *Web) SetChannels(feedbackChan chan ValidationFeedback, quitChan chan bool) {
|
||||
|
||||
Reference in New Issue
Block a user