github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/httptransport/transport.go (about) 1 package httptransport 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "net" 8 "net/http" 9 "os" 10 "os/signal" 11 "sort" 12 "strconv" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/julienschmidt/httprouter" 18 "github.com/pkg/errors" 19 20 "github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/handlers" 21 "github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/transformer" 22 "github.com/machinefi/w3bstream/pkg/depends/kit/kit" 23 "github.com/machinefi/w3bstream/pkg/depends/kit/logr" 24 "github.com/machinefi/w3bstream/pkg/depends/kit/validator" 25 _ "github.com/machinefi/w3bstream/pkg/depends/kit/validator/strfmt" 26 ) 27 28 func MiddlewareChain(mw ...HttpMiddleware) HttpMiddleware { 29 return func(final http.Handler) http.Handler { 30 last := final 31 for i := len(mw) - 1; i >= 0; i-- { 32 last = mw[i](last) 33 } 34 return last 35 } 36 } 37 38 type HttpMiddleware func(http.Handler) http.Handler 39 40 func NewHttpTransport(modifiers ...ServerModifier) *HttpTransport { 41 return &HttpTransport{Modifiers: modifiers} 42 } 43 44 type HttpTransport struct { 45 ServiceMeta 46 Protocol string 47 Addr string 48 Port int 49 Modifiers []ServerModifier // for modifying http.Server 50 Middlewares []HttpMiddleware // Middlewares https://github.com/gorilla/handlers 51 Vldt validator.Factory // Vldt validator factory 52 Tsfm transformer.Factory // transformer mgr for parameter transforming 53 CertFile string 54 KeyFile string 55 httpRouter *httprouter.Router 56 57 srv *http.Server 58 } 59 60 type ServerModifier func(server *http.Server) error 61 62 func (t *HttpTransport) SetDefault() { 63 t.ServiceMeta.SetDefault() 64 65 if t.Vldt == nil { 66 t.Vldt = validator.DefaultFactory 67 } 68 69 if t.Tsfm == nil { 70 t.Tsfm = transformer.DefaultFactory 71 } 72 73 if t.Middlewares == nil { 74 t.Middlewares = []HttpMiddleware{handlers.LogHandler()} 75 } 76 77 if t.Port == 0 { 78 t.Port = 80 79 } 80 } 81 82 func (t *HttpTransport) ServeHTTP(w http.ResponseWriter, req *http.Request) { 83 t.httpRouter.ServeHTTP(w, req) 84 } 85 86 func (t *HttpTransport) Serve(router *kit.Router) error { 87 return t.ServeContext(context.Background(), router) 88 } 89 90 func (t *HttpTransport) IsTLS() bool { return t.CertFile != "" && t.KeyFile != "" } 91 92 func (t *HttpTransport) ServeContext(ctx context.Context, router *kit.Router) error { 93 t.SetDefault() 94 95 logger := logr.FromContext(ctx) 96 97 t.httpRouter = t.toHttpRouter(router) 98 99 t.srv = &http.Server{ 100 Addr: fmt.Sprintf(":%d", t.Port), 101 Handler: MiddlewareChain(t.Middlewares...)(t), 102 } 103 104 for i := range t.Modifiers { 105 if err := t.Modifiers[i](t.srv); err != nil { 106 log.Fatal(err) 107 } 108 } 109 110 go func() { 111 outputln("%s listen on %s", t.ServiceMeta, t.srv.Addr) 112 113 var ( 114 ln net.Listener 115 err error 116 addr = t.srv.Addr 117 ) 118 119 defer func() { 120 if ln != nil { 121 _ = ln.Close() 122 } 123 }() 124 125 if strings.HasPrefix(addr, ":unix@") { 126 file := strings.Split(addr, "@")[1] 127 _ = os.Remove(file) 128 ln, err = net.Listen("unix", file) 129 } else { 130 if t.Port != 0 { 131 addr = ":" + strconv.Itoa(t.Port) 132 } 133 if addr == "" { 134 addr = ":http" 135 if t.IsTLS() { 136 addr = ":https" 137 } 138 } 139 ln, err = net.Listen("tcp", addr) 140 } 141 142 if err != nil { 143 logger.Error(err) 144 log.Fatal(err) 145 } 146 147 if t.IsTLS() { 148 err = t.srv.ServeTLS(ln, t.CertFile, t.KeyFile) 149 } else { 150 err = t.srv.Serve(ln) 151 } 152 logger.Error(err) 153 return 154 }() 155 156 stopCh := make(chan os.Signal, 1) 157 signal.Notify(stopCh, os.Interrupt, syscall.SIGTERM) 158 <-stopCh 159 160 timeout := 10 * time.Second 161 162 ctx, cancel := context.WithTimeout(context.Background(), timeout) 163 defer cancel() 164 165 log.Println("Server shutdown in 10 second") 166 167 return t.srv.Shutdown(ctx) 168 } 169 170 func (t *HttpTransport) Shutdown(ctx context.Context) error { 171 return t.srv.Shutdown(ctx) 172 } 173 174 func (t *HttpTransport) toHttpRouter(rt *kit.Router) *httprouter.Router { 175 routes := rt.Routes() 176 177 if len(routes) == 0 { 178 panic(errors.Errorf( 179 "need to register Operator to Router %#v before serve", rt, 180 )) 181 } 182 183 metas := make([]*HttpRouteMeta, len(routes)) 184 for i := range routes { 185 metas[i] = NewHttpRouteMeta(routes[i]) 186 } 187 188 router := httprouter.New() 189 190 sort.Slice(metas, func(i, j int) bool { 191 return metas[i].Key() < metas[j].Key() 192 }) 193 194 for i := range metas { 195 route := metas[i] 196 route.Log() 197 198 if err := tryCatch(func() { 199 router.HandlerFunc( 200 route.Method(), 201 route.Path(), 202 NewRouteHandler( 203 &t.ServiceMeta, 204 route, 205 NewRequestTsfmFactory(t.Tsfm, t.Vldt), 206 ).ServeHTTP, 207 ) 208 }); err != nil { 209 panic(errors.Errorf("register http route `%s` failed: %s", route, err)) 210 } 211 } 212 213 return router 214 }