This repository was archived by the owner on Oct 13, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.go
More file actions
129 lines (104 loc) · 2.55 KB
/
Copy pathapp.go
File metadata and controls
129 lines (104 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"context"
"errors"
"flag"
"fmt"
"io"
"log/slog"
"runtime/debug"
"golang.org/x/sync/errgroup"
)
// getVCSRevision returns the git commit SHA if present else "devel".
func getVCSRevision() string {
if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
if setting.Key == "vcs.revision" {
return setting.Value
}
}
}
return "devel"
}
// App is our application instance.
type App struct {
config Config
logger *slog.Logger
subber *Subber
ws *WebServer
version string
}
// NewApp creates an instance of our application, based on the supplied args and output locations.
func NewApp(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) (*App, error) {
logHandler := slog.NewTextHandler(stderr, nil).
WithAttrs(
[]slog.Attr{slog.String("version", getVCSRevision())},
)
logger := slog.New(logHandler)
logger.Info("starting gosubs")
fs := flag.NewFlagSet("gosubs", flag.ContinueOnError)
configFile := fs.String("configFile", "config.json", "json file to read configuration from")
showVersion := fs.Bool("version", false, "show version and exit")
if err := fs.Parse(args[1:]); err != nil {
return nil, fmt.Errorf("parsing args: %w", err)
}
if *showVersion {
return nil, nil
}
config := DefaultConfiguration()
var err error
if configFile != nil {
config, err = loadConfig(*configFile)
if err != nil {
return nil, fmt.Errorf("loading config from file: %v", err)
}
logger.Info("loaded configuration from file", "file", *configFile)
}
subber := NewSubber(
logger.WithGroup("subber"),
config.Players,
)
ws, err := NewWebServer(
logger.WithGroup("webserver"),
config.ListenAddr,
subber,
)
if err != nil {
return nil, err
}
app := &App{
config: config,
logger: logger,
subber: subber,
ws: ws,
version: getVCSRevision(),
}
return app, nil
}
// Run starts the application and gracefully shuts down when the provided
// context is cancelled.
func (app *App) Run(ctx context.Context) error {
cctx, cancel := context.WithCancelCause(ctx)
defer cancel(nil)
g, gctx := errgroup.WithContext(cctx)
// listen for cancellations
g.Go(func() error {
<-gctx.Done()
if errors.Is(context.Cause(gctx), context.Canceled) {
app.logger.Info("received OS signal to shutdown, use Ctrl+C again to force")
}
return nil
})
// start HTTP server
g.Go(func() error {
err := app.ws.Run(gctx)
cancel(err)
return err
})
err := g.Wait()
if err != nil {
return err
}
app.logger.Info("shutdown completed successfully")
return nil
}