Skip to content
Snippets Groups Projects
Commit 1ce5f246 authored by Simon Kirsten's avatar Simon Kirsten
Browse files

Added TLS support, namespaces and monitoring

parent 4470a41a
Branches
No related tags found
No related merge requests found
...@@ -15,11 +15,15 @@ import ( ...@@ -15,11 +15,15 @@ import (
const docURL = "https://stream-server.h-da.io" const docURL = "https://stream-server.h-da.io"
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
var port int var port int
var flagBrowser bool var tlsport int
var flagLocal bool var tlsCert, tlsKey string
var listenAddr string
var flagUseHostNamespace bool
var flagHelp bool var flagHelp bool
app.Usage = docURL app.Usage = docURL
...@@ -29,20 +33,37 @@ func main() { ...@@ -29,20 +33,37 @@ func main() {
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.IntFlag{ cli.IntFlag{
Name: "port, p", Name: "port",
Value: 8080, Value: 8080,
Usage: "http port to listen on", Usage: "http port to listen on",
Destination: &port, Destination: &port,
}, },
cli.BoolFlag{ cli.IntFlag{
Name: "browser, b", Name: "tlsport",
Usage: "automatically open the default browser", Value: 8443,
Destination: &flagBrowser, Usage: "https port to listen on",
Destination: &tlsport,
},
cli.StringFlag{
Name: "listen",
Value: "0.0.0.0",
Usage: "address to listen on",
Destination: &listenAddr,
},
cli.StringFlag{
Name: "tlscert",
Usage: "TLS cert",
Destination: &tlsCert,
},
cli.StringFlag{
Name: "tlskey",
Usage: "TLS key",
Destination: &tlsKey,
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "local, l", Name: "use-host-namespace",
Usage: "only listen on 127.0.0.1 (see doc)", Usage: "use the Host header as namespace",
Destination: &flagLocal, Destination: &flagUseHostNamespace,
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "help, h", Name: "help, h",
...@@ -61,36 +82,56 @@ func main() { ...@@ -61,36 +82,56 @@ func main() {
return fmt.Errorf("Unknown arguments: %v", c.Args()) return fmt.Errorf("Unknown arguments: %v", c.Args())
} }
localhost := fmt.Sprintf("127.0.0.1:%d", port) withTLS := tlsCert != "" && tlsKey != ""
all := fmt.Sprintf("0.0.0.0:%d", port)
outbound := localhost
if outboundIP, err := util.GetOutboundIP(); err == nil {
outbound = fmt.Sprintf("%s:%d", outboundIP, port)
}
var listenAddr string fmt.Print("Serving on\n")
if flagLocal { if listenAddr == "0.0.0.0" {
listenAddr = localhost fmt.Printf(" http://%s:%d\n", "localhost", port)
if withTLS {
fmt.Printf(" https://%s:%d\n", "localhost", tlsport)
}
fmt.Printf("Serving on http://%s\n", localhost) if outboundIP, err := util.GetOutboundIP(); err == nil {
fmt.Printf(" http://%s:%d\n", outboundIP, port)
if withTLS {
fmt.Printf(" https://%s:%d\n", outboundIP, tlsport)
}
}
} else { } else {
listenAddr = all fmt.Printf(" http://%s:%d\n", listenAddr, port)
if withTLS {
fmt.Printf("Serving on\n http://%s\n http://%s\n", localhost, outbound) fmt.Printf(" https://%s:%d\n", listenAddr, tlsport)
}
if flagBrowser {
err := util.OpenBrowser(fmt.Sprintf("http://%s", localhost))
if err != nil {
fmt.Printf("Could not automatically open browser: %v\n", err)
} }
} }
fmt.Printf("Read the quickstart at %s/quickstart to get started.\n", docURL) fmt.Printf("Read the quickstart at %s/quickstart to get started.\n", docURL)
fmt.Printf("Stop with Ctrl-C or close this terminal.\n") fmt.Printf("Stop with Ctrl-C or close this terminal.\n")
return server.ListenAndServe(listenAddr) router := server.GetRouter(flagUseHostNamespace)
for {
errs := make(chan error)
go func() {
if err := server.ServeHTTP(fmt.Sprintf("%s:%d", listenAddr, port), router); err != nil {
errs <- err
}
}()
if withTLS {
go func() {
if err := server.ServeHTTPS(fmt.Sprintf("%s:%d", listenAddr, tlsport), router, tlsCert, tlsKey); err != nil {
errs <- err
}
}()
}
select {
case err := <-errs:
return err
}
}
} }
err := app.Run(os.Args) err := app.Run(os.Args)
......
...@@ -4,9 +4,12 @@ go 1.13 ...@@ -4,9 +4,12 @@ go 1.13
require ( require (
github.com/JamesStewy/sse v0.3.0 github.com/JamesStewy/sse v0.3.0
github.com/dyson/certman v0.2.1
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/chi v4.0.2+incompatible
github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-multierror v1.0.0
github.com/markbates/pkger v0.12.8 github.com/markbates/pkger v0.12.8
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.7.0
github.com/urfave/cli v1.21.0 github.com/urfave/cli v1.21.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
) )
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/JamesStewy/sse v0.3.0 h1:1CABzcQydehMc54Vypki6b5+/WMmGZVWi7owRvDKo7g= github.com/JamesStewy/sse v0.3.0 h1:1CABzcQydehMc54Vypki6b5+/WMmGZVWi7owRvDKo7g=
github.com/JamesStewy/sse v0.3.0/go.mod h1:i60+CezIhaOZYviCbCRqXCDB7cVCWvUqlD2AYnxPVRE= github.com/JamesStewy/sse v0.3.0/go.mod h1:i60+CezIhaOZYviCbCRqXCDB7cVCWvUqlD2AYnxPVRE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dyson/certman v0.2.1 h1:+EJdgffbfwIkBvnyx97mfS3slfn2o4UN/LWGm+mWVrQ=
github.com/dyson/certman v0.2.1/go.mod h1:Z2ho3wmP4oCGON+c/RF+FJVsMb9zYZVsupp0c1a+SlQ=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
...@@ -17,17 +57,77 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= ...@@ -17,17 +57,77 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/pkger v0.12.8 h1:4mEUzWb1HzRnxPwUevBX8g8ntsQ4rWw2R8CRB2QdZVI= github.com/markbates/pkger v0.12.8 h1:4mEUzWb1HzRnxPwUevBX8g8ntsQ4rWw2R8CRB2QdZVI=
github.com/markbates/pkger v0.12.8/go.mod h1:C7e5A6bnWZT+nXkUwkvysGW7sxl/IGd63HEa6N/JY8s= github.com/markbates/pkger v0.12.8/go.mod h1:C7e5A6bnWZT+nXkUwkvysGW7sxl/IGd63HEa6N/JY8s=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE= github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
...@@ -2,7 +2,7 @@ package server ...@@ -2,7 +2,7 @@ package server
import ( import (
"encoding/json" "encoding/json"
"log" "fmt"
"net/http" "net/http"
"strconv" "strconv"
"sync" "sync"
...@@ -22,26 +22,42 @@ type displayState struct { ...@@ -22,26 +22,42 @@ type displayState struct {
ShowChat bool `json:"show_chat"` ShowChat bool `json:"show_chat"`
} }
// state is the current state of the display. // Display struct defines the Display itself
// It is initialized with default values. type Display struct {
var state = displayState{ State displayState
LargeChannel: "", clientsMu sync.Mutex
SmallChannel: "", // clients holds the clients that are connected to the event handler. It is used to broadcast state changes to all SSE (Server-Sent Events) clients.
Volume: 0.5, // Must acquire clientsMu before accessing the map.
SmallScale: 0.3, // Note: the only reason we use a sse.Client => bool map is that we can call *delete* with the client as key. The actual bool value that is stored holds no significance whatsoever.
ShowChat: false, // This is basically a *set* in go.
clients map[*sse.Client]bool
// the prefix used for logging
loggingPrefix string
} }
// clients holds the clients that are connected to the event handler. It is used to broadcast state changes to all SSE (Server-Sent Events) clients. // NewDisplay creates a new Display with default values
// Must acquire clientsMu before accessing the map. func NewDisplay(namespace string) *Display {
// Note: the only reason we use a sse.Client => bool map is that we can call *delete* with the client as key. The actual bool value that is stored holds no significance whatsoever. var loggingPrefix string
// This is basically a *set* in go. if namespace == "default" {
var ( loggingPrefix = "display"
clientsMu sync.Mutex } else {
clients map[*sse.Client]bool = make(map[*sse.Client]bool) loggingPrefix = fmt.Sprintf("display[%s]", namespace)
) }
return &Display{
State: displayState{
LargeChannel: "",
SmallChannel: "",
Volume: 0.5,
SmallScale: 0.3,
ShowChat: false,
},
clients: make(map[*sse.Client]bool),
loggingPrefix: loggingPrefix,
}
}
// displayStateHandler updated the state based on the query string. // stateHandler updated the state based on the query string.
// For example // For example
// /display?large_channel=asdf&small_channel=null&volume=&small_scale=0.25&show_chat=true // /display?large_channel=asdf&small_channel=null&volume=&small_scale=0.25&show_chat=true
// will // will
...@@ -52,9 +68,9 @@ var ( ...@@ -52,9 +68,9 @@ var (
// - set show_chat to true // - set show_chat to true
// //
// If the floats (volume and small_scale) or the boolean (show_chat) could not be parsed, no changes are made at all and an error gets returned even if other fields could be parsed. // If the floats (volume and small_scale) or the boolean (show_chat) could not be parsed, no changes are made at all and an error gets returned even if other fields could be parsed.
func displayStateHandler(w http.ResponseWriter, r *http.Request) { func (d *Display) stateHandler(w http.ResponseWriter, r *http.Request) {
// the new state we will replace the current state with IF everything parses correctly. // the new state we will replace the current state with IF everything parses correctly.
newState := state newState := d.State
// we save the error messages of the 5 parsing steps here. // we save the error messages of the 5 parsing steps here.
var errs error var errs error
...@@ -117,18 +133,18 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) { ...@@ -117,18 +133,18 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) {
if errs != nil { // we had errors if errs != nil { // we had errors
http.Error(w, errs.Error(), http.StatusBadRequest) http.Error(w, errs.Error(), http.StatusBadRequest)
log.Printf("Error(s) while parsing /display query: %v\n", errs) logger.Printf("%s: Error(s) while parsing /display query: %v\n", d.loggingPrefix, errs)
return return
} }
if state != newState { if d.State != newState {
state = newState d.State = newState
body, err := json.Marshal(state) body, err := json.Marshal(d.State)
if err != nil { if err != nil {
return return
} }
log.Printf("Updated display (%s):\n%s\n", r.URL.RawQuery, string(body)) logger.Printf("%s: Updated (%s):\n%s\n", d.loggingPrefix, r.URL.RawQuery, string(body))
// craft the SSE message // craft the SSE message
msg := sse.Msg{ msg := sse.Msg{
...@@ -142,11 +158,11 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) { ...@@ -142,11 +158,11 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) {
// of clients to send to (while holding clientsMu) and start // of clients to send to (while holding clientsMu) and start
// sending only after giving up the lock again. // sending only after giving up the lock again.
var sendingTo []*sse.Client var sendingTo []*sse.Client
clientsMu.Lock() d.clientsMu.Lock()
for client := range clients { for client := range d.clients {
sendingTo = append(sendingTo, client) sendingTo = append(sendingTo, client)
} }
clientsMu.Unlock() d.clientsMu.Unlock()
// now broadcast it to all clients // now broadcast it to all clients
for _, client := range sendingTo { for _, client := range sendingTo {
...@@ -154,11 +170,11 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) { ...@@ -154,11 +170,11 @@ func displayStateHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
util.ServeIndentedJSON(w, r, &state) util.ServeIndentedJSON(w, r, d.State)
} }
// displayEventsHandler serves a SSE (Server-sent events) endpoint that the website(s) can connect to. It publishes the state when it gets changed. // eventsHandler serves a SSE (Server-sent events) endpoint that the website(s) can connect to. It publishes the state when it gets changed.
func displayEventsHandler(w http.ResponseWriter, r *http.Request) { func (d *Display) eventsHandler(w http.ResponseWriter, r *http.Request) {
client, err := sse.ClientInit(w) client, err := sse.ClientInit(w)
// return error if unable to initialize sse connection // return error if unable to initialize sse connection
...@@ -169,18 +185,18 @@ func displayEventsHandler(w http.ResponseWriter, r *http.Request) { ...@@ -169,18 +185,18 @@ func displayEventsHandler(w http.ResponseWriter, r *http.Request) {
// Add client to broadcast set. Need to serialize access to clients as // Add client to broadcast set. Need to serialize access to clients as
// we're running concurrently with other requests. // we're running concurrently with other requests.
clientsMu.Lock() d.clientsMu.Lock()
clients[client] = true d.clients[client] = true
clientsMu.Unlock() d.clientsMu.Unlock()
// remove client from broadcast set on exit // remove client from broadcast set on exit
defer func() { defer func() {
clientsMu.Lock() d.clientsMu.Lock()
delete(clients, client) delete(d.clients, client)
clientsMu.Unlock() d.clientsMu.Unlock()
}() }()
body, err := json.Marshal(state) body, err := json.Marshal(d.State)
if err != nil { if err != nil {
return return
} }
......
package server
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
displayListernersMetric = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "display_listeners",
Help: "Active clients listening to /display",
})
counterMetric = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "requests_total",
Help: "Count the total number of requests.",
},
[]string{"path", "code"},
)
durationMetric = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "requests_duration_seconds",
Help: "A histogram of duration for requests.",
Buckets: []float64{.25, .5, 1, 2.5, 5, 10},
},
[]string{"path"},
)
)
func init() {
prometheus.MustRegister(displayListernersMetric, durationMetric, counterMetric)
}
func monitoringMiddleware(handler string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return promhttp.InstrumentHandlerDuration(
durationMetric.MustCurryWith(prometheus.Labels{"path": handler}),
promhttp.InstrumentHandlerCounter(counterMetric.MustCurryWith(prometheus.Labels{"path": handler}), next))
}
}
package server
import (
"net/http"
"sync"
"github.com/go-chi/chi"
"github.com/markbates/pkger"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
displaysMu sync.Mutex
displays map[string]*Display = make(map[string]*Display)
)
// GetRouter gets the router for the server
func GetRouter(useHostNamespace bool) *chi.Mux {
r := chi.NewRouter()
r.Route("/twitch", func(r chi.Router) {
r.With(monitoringMiddleware("/twitch/getTopGames")).Get("/getTopGames", twitchGetTopGamesHandler)
r.With(monitoringMiddleware("/twitch/searchGames")).Get("/searchGames", twitchSearchGamesHandler)
r.With(monitoringMiddleware("/twitch/getTopStreams")).Get("/getTopStreams", twitchGetTopStreamsHandler)
r.With(monitoringMiddleware("/twitch/getFeaturedStreams")).Get("/getFeaturedStreams", twitchGetFeaturedStreamsHandler)
})
r.With(monitoringMiddleware("/display")).Get("/display", func(w http.ResponseWriter, r *http.Request) {
namespace := "default"
if useHostNamespace {
namespace = r.Host
}
displaysMu.Lock()
display, ok := displays[namespace]
if !ok {
display = NewDisplay(namespace)
displays[namespace] = display
}
displaysMu.Unlock()
if r.Header.Get("Accept") == "text/event-stream" {
displayListernersMetric.Inc()
defer displayListernersMetric.Dec()
display.eventsHandler(w, r)
} else {
display.stateHandler(w, r)
}
})
// Export Prometheus metrics
r.Handle("/metrics", promhttp.Handler())
r.With(monitoringMiddleware("/")).Mount("/", http.FileServer(pkger.Dir("/internal/static")))
return r
}
package server package server
import ( import (
"crypto/tls"
"log"
"net/http" "net/http"
"os"
"github.com/go-chi/chi" "github.com/dyson/certman"
"github.com/markbates/pkger"
) )
// ListenAndServe will listen and serve on the provided listenAddr var logger = log.New(os.Stdout, "", log.LstdFlags)
func ListenAndServe(listenAddr string) error {
r := chi.NewRouter()
r.Route("/twitch", func(r chi.Router) { // ServeHTTP serves http requests on addr with handler
r.Get("/getTopGames", twitchGetTopGamesHandler) func ServeHTTP(addr string, handler http.Handler) error {
r.Get("/searchGames", twitchSearchGamesHandler) server := &http.Server{
r.Get("/getTopStreams", twitchGetTopStreamsHandler) Addr: addr,
r.Get("/getFeaturedStreams", twitchGetFeaturedStreamsHandler) Handler: handler,
}) }
r.Get("/display", func(w http.ResponseWriter, r *http.Request) { return server.ListenAndServe()
if r.Header.Get("Accept") == "text/event-stream" { }
displayEventsHandler(w, r)
} else { // ServeHTTPS serves https requests on addr with handler
displayStateHandler(w, r) func ServeHTTPS(addr string, handler http.Handler, certFile, keyFile string) error {
} certManager, err := certman.New(certFile, keyFile)
}) if err != nil {
return err
}
certManager.Logger(logger)
if err := certManager.Watch(); err != nil {
return err
}
r.Mount("/", http.FileServer(pkger.Dir("/internal/static"))) server := &http.Server{
Addr: addr,
Handler: handler,
TLSConfig: &tls.Config{
GetCertificate: certManager.GetCertificate,
},
}
return http.ListenAndServe(listenAddr, r) return server.ListenAndServeTLS("", "")
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment