...
1 package services
2
3 import (
4
5 "context"
6 "crypto/tls"
7 "fmt"
8 "net/http"
9 "strings"
10
11
12 "google.golang.org/grpc"
13
14
15 "github.com/datawire/dlib/dgroup"
16 "github.com/datawire/dlib/dhttp"
17 "github.com/datawire/dlib/dlog"
18 )
19
20
21 type Service interface {
22 Start(context.Context) <-chan bool
23 }
24
25 type HTTPListener struct {
26 CleartextPort int16
27 TLSPort int16
28 TLSCert string
29 TLSKey string
30 }
31
32 func (hl HTTPListener) Run(ctx context.Context, name string, httpHandler *http.ServeMux, grpcHandler *grpc.Server) <-chan bool {
33 dlog.Printf(ctx, "GRPCRLS: %s listening on cleartext :%d and tls :%d", name, hl.CleartextPort, hl.TLSPort)
34
35 cer, err := tls.LoadX509KeyPair(hl.TLSCert, hl.TLSKey)
36 if err != nil {
37 dlog.Error(ctx, err)
38 panic(err)
39 }
40
41 sc := &dhttp.ServerConfig{
42 Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
43 dlog.Infof(r.Context(), "handling request to %q...", r.RequestURI)
44 if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
45 grpcHandler.ServeHTTP(w, r)
46 } else {
47 httpHandler.ServeHTTP(w, r)
48 }
49 }),
50 TLSConfig: &tls.Config{
51 Certificates: []tls.Certificate{cer},
52 },
53 }
54
55 grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{})
56 grp.Go("cleartext", func(ctx context.Context) error {
57 return sc.ListenAndServe(ctx, fmt.Sprintf(":%v", hl.CleartextPort))
58 })
59 grp.Go("tls", func(ctx context.Context) error {
60 return sc.ListenAndServeTLS(ctx, fmt.Sprintf(":%v", hl.TLSPort), "", "")
61 })
62
63 dlog.Printf(ctx, "starting %s", name)
64
65 exited := make(chan bool)
66 go func() {
67 if err := grp.Wait(); err != nil {
68 dlog.Error(ctx, err)
69 panic(err)
70 }
71 close(exited)
72 }()
73 return exited
74 }
75
View as plain text