1package cmd
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "log/slog"
8 "os"
9 "os/signal"
10 "time"
11
12 "github.com/charmbracelet/crush/internal/config"
13 "github.com/charmbracelet/crush/internal/server"
14 "github.com/charmbracelet/log/v2"
15 "github.com/spf13/cobra"
16)
17
18var serverCmd = &cobra.Command{
19 Use: "server",
20 Short: "Start the Crush server",
21 RunE: func(cmd *cobra.Command, args []string) error {
22 dataDir, err := cmd.Flags().GetString("data-dir")
23 if err != nil {
24 return fmt.Errorf("failed to get data directory: %v", err)
25 }
26 debug, err := cmd.Flags().GetBool("debug")
27 if err != nil {
28 return fmt.Errorf("failed to get debug flag: %v", err)
29 }
30
31 cfg, err := config.Load("", dataDir, debug)
32 if err != nil {
33 return fmt.Errorf("failed to load configuration: %v", err)
34 }
35
36 logger := log.New(os.Stderr)
37 logger.SetReportTimestamp(true)
38 slog.SetDefault(slog.New(logger))
39 if debug {
40 logger.SetLevel(log.DebugLevel)
41 slog.SetLogLoggerLevel(slog.LevelDebug)
42 }
43
44 srv := server.NewServer(cfg, "unix", server.DefaultAddr())
45 srv.SetLogger(slog.Default())
46 slog.Info("Starting Crush server...", "addr", srv.Addr)
47
48 errch := make(chan error, 1)
49 sigch := make(chan os.Signal, 1)
50 sigs := []os.Signal{os.Interrupt}
51 sigs = append(sigs, addSignals(sigs)...)
52 signal.Notify(sigch, sigs...)
53
54 go func() {
55 errch <- srv.ListenAndServe()
56 }()
57
58 select {
59 case <-sigch:
60 slog.Info("Received interrupt signal...")
61 case err := <-errch:
62 if err != nil && !errors.Is(err, server.ErrServerClosed) {
63 _ = srv.Close()
64 slog.Error("Server error", "error", err)
65 return fmt.Errorf("server error: %v", err)
66 }
67 }
68
69 ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
70 defer cancel()
71
72 slog.Info("Shutting down...")
73
74 if err := srv.Shutdown(ctx); err != nil {
75 slog.Error("Failed to shutdown server", "error", err)
76 return fmt.Errorf("failed to shutdown server: %v", err)
77 }
78
79 return nil
80 },
81}
82
83func init() {
84 rootCmd.AddCommand(serverCmd)
85}