92 lines
2.2 KiB
Go
92 lines
2.2 KiB
Go
package servercmd
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type Config struct {
|
|
WorkspacesDir string
|
|
ProjectRoot string
|
|
Port int
|
|
Addr string
|
|
}
|
|
|
|
type RunnerDeps struct {
|
|
StdErr io.Writer
|
|
InitRuntime func(Config) (io.Closer, error)
|
|
BuildMux func(Config) http.Handler
|
|
ListenAndServe func(string, http.Handler) error
|
|
}
|
|
|
|
func Run(args []string, deps RunnerDeps) error {
|
|
cfg, err := parseConfig(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if deps.BuildMux == nil {
|
|
return fmt.Errorf("server mux builder is not configured")
|
|
}
|
|
|
|
listenAndServe := deps.ListenAndServe
|
|
if listenAndServe == nil {
|
|
listenAndServe = http.ListenAndServe
|
|
}
|
|
|
|
stderr := deps.StdErr
|
|
if stderr == nil {
|
|
stderr = os.Stderr
|
|
}
|
|
|
|
return runWithConfig(cfg, deps, stderr, listenAndServe)
|
|
}
|
|
|
|
func parseConfig(args []string) (Config, error) {
|
|
flagSet := flag.NewFlagSet("server", flag.ExitOnError)
|
|
port := flagSet.Int("port", 3000, "HTTP server port")
|
|
wsDir := flagSet.String("workspaces-dir", "", "directory containing workspace worktrees (required)")
|
|
flagSet.Parse(args)
|
|
|
|
if *wsDir == "" {
|
|
return Config{}, fmt.Errorf("--workspaces-dir is required")
|
|
}
|
|
|
|
absDir, err := filepath.Abs(*wsDir)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("resolving workspaces-dir: %w", err)
|
|
}
|
|
info, err := os.Stat(absDir)
|
|
if err != nil || !info.IsDir() {
|
|
return Config{}, fmt.Errorf("workspaces-dir does not exist or is not a directory: %s", absDir)
|
|
}
|
|
return Config{
|
|
WorkspacesDir: absDir,
|
|
ProjectRoot: filepath.Dir(absDir),
|
|
Port: *port,
|
|
Addr: fmt.Sprintf(":%d", *port),
|
|
}, nil
|
|
}
|
|
|
|
func runWithConfig(cfg Config, deps RunnerDeps, stderr io.Writer, listenAndServe func(string, http.Handler) error) error {
|
|
var closer io.Closer
|
|
var err error
|
|
if deps.InitRuntime != nil {
|
|
closer, err = deps.InitRuntime(cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("opening central database: %w", err)
|
|
}
|
|
if closer != nil {
|
|
defer closer.Close()
|
|
}
|
|
}
|
|
|
|
handler := deps.BuildMux(cfg)
|
|
fmt.Fprintf(stderr, "inbox API server listening on http://localhost%s\n", cfg.Addr)
|
|
fmt.Fprintf(stderr, "workspaces dir: %s\n", cfg.WorkspacesDir)
|
|
return listenAndServe(cfg.Addr, handler)
|
|
}
|