-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
158 lines (147 loc) · 3.67 KB
/
main.go
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"errors"
"fmt"
"os"
"os/signal"
"syscall"
"time"
cli "github.com/urfave/cli/v2"
)
// configCheckInterval determines how frequently the config file is checked for
// changes, to see if it needs to be reloaded. Set this to 0 to disable
// checking the config file.
const configCheckInterval = 5 * time.Second
func main() {
app := &cli.App{
Name: "indexstar",
Usage: "indexstar is a point in the content routing galaxy - routes requests in a star topology",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "Path to config file",
TakesFile: true,
},
&cli.StringFlag{
Name: "listen",
Usage: "HTTP server Listen address",
Value: ":8080",
},
&cli.StringFlag{
Name: "metrics",
Usage: "Metrics server listen address",
Value: ":8081",
},
&cli.StringSliceFlag{
Name: backendsArg,
Usage: "Backends to propagate regular requests to.",
Value: cli.NewStringSlice("https://cid.contact/"),
},
&cli.StringSliceFlag{
Name: cascadeBackendsArg,
Usage: "Backends to propagate lookup with SERVER_CASCADE_LABELS env var as query parameter",
},
&cli.StringSliceFlag{
Name: dhBackendsArg,
Usage: "Backends to propagate Double Hashed requests to.",
},
&cli.StringSliceFlag{
Name: providersBackendsArg,
Usage: "Backends to propagate providers requests to.",
},
&cli.BoolFlag{
Name: "translateNonStreaming",
Usage: "Whether to translate non-streaming JSON requests to streaming NDJSON requests before scattering to backends.",
},
&cli.StringFlag{
Name: "homepageURL",
Usage: "The actual webUI backend to be rendered via iframe.",
Value: "https://web-ipni.cid.contact/",
},
},
Action: func(c *cli.Context) error {
exit := make(chan os.Signal, 1)
signal.Notify(exit, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
s, err := NewServer(c)
if err != nil {
return err
}
sighup := make(chan os.Signal, 1)
signal.Notify(sighup, syscall.SIGHUP)
done := s.Serve()
var (
cfgPath string
modTime time.Time
ticker *time.Ticker
timeChan <-chan time.Time
)
if configCheckInterval != 0 {
cfgPath = s.cfgBase
if cfgPath == "" {
cfgPath, err = Path("", "")
if err != nil {
return err
}
}
modTime, _, err = fileChanged(cfgPath, modTime)
if err != nil {
// No config file is not an error.
if !errors.Is(err, os.ErrNotExist) {
log.Error(err)
}
} else {
ticker = time.NewTicker(configCheckInterval)
timeChan = ticker.C
}
}
reloadSig := make(chan struct{}, 1)
for {
select {
case <-sighup:
select {
case reloadSig <- struct{}{}:
default:
}
case <-exit:
return nil
case err := <-done:
return err
case <-reloadSig:
err := s.Reload(c)
if err != nil {
log.Warnf("couldn't reload servers: %s", err)
}
case <-timeChan:
var changed bool
modTime, changed, err = fileChanged(s.cfgBase, modTime)
if err != nil {
log.Errorw("Cannot stat config file", "err", err, "path", cfgPath)
ticker.Stop()
ticker = nil
timeChan = nil // reading from nil channel blocks forever
continue
}
if changed {
reloadSig <- struct{}{}
}
}
}
},
}
err := app.Run(os.Args)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
os.Exit(0)
}
func fileChanged(filePath string, modTime time.Time) (time.Time, bool, error) {
fi, err := os.Stat(filePath)
if err != nil {
return modTime, false, err
}
if fi.ModTime() != modTime {
return fi.ModTime(), true, nil
}
return modTime, false, nil
}