main.go
1484 bytes
1package main
2
3import (
4 "context"
5 "fmt"
6 "log/slog"
7 "net/http"
8 "os"
9 "os/signal"
10 "syscall"
11 "time"
12
13 "git.theedgeofrage.com/TheEdgeOfRage/kaiwari/internal/bootstrap"
14 "git.theedgeofrage.com/TheEdgeOfRage/kaiwari/internal/config"
15 "git.theedgeofrage.com/TheEdgeOfRage/kaiwari/internal/server"
16)
17
18const shutdownTimeout = 10 * time.Second
19
20func main() {
21 slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, nil)))
22 cfg := config.ParseServerConfig()
23 if cfg.Token == "" {
24 fatalf("token is required: set --token or JP_SERVER_TOKEN")
25 }
26
27 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
28 defer stop()
29
30 svc, err := bootstrap.New(ctx, &cfg.Config)
31 if err != nil {
32 fatalf("%v", err)
33 }
34 defer svc.Close()
35
36 srv := server.New(svc, cfg.Token)
37 httpSrv := &http.Server{Addr: cfg.Listen, Handler: srv.Handler()}
38 errCh := make(chan error, 1)
39 go func() {
40 if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
41 errCh <- err
42 }
43 }()
44
45 fmt.Printf("kaiwari-server: listening on %s\n", cfg.Listen)
46 select {
47 case err := <-errCh:
48 svc.Close()
49 fatalf("%v", err)
50 case <-ctx.Done():
51 shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
52 defer cancel()
53 if err := httpSrv.Shutdown(shutdownCtx); err != nil {
54 svc.Close()
55 fatalf("shutdown: %v", err)
56 }
57 }
58}
59
60func fatalf(format string, args ...any) {
61 fmt.Fprintf(os.Stderr, "kaiwari-server: "+format+"\n", args...)
62 os.Exit(1)
63}