github.com/vicanso/pike@v1.0.1-0.20210630235453-9099e041f6ec/server/server.go (about) 1 // MIT License 2 3 // Copyright (c) 2020 Tree Xie 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 23 package server 24 25 import ( 26 "net" 27 "net/http" 28 "regexp" 29 "sync" 30 "time" 31 32 "github.com/dustin/go-humanize" 33 "github.com/vicanso/elton" 34 "github.com/vicanso/elton/middleware" 35 "github.com/vicanso/pike/cache" 36 "github.com/vicanso/pike/config" 37 "github.com/vicanso/pike/log" 38 "github.com/vicanso/pike/util" 39 "go.uber.org/atomic" 40 "go.uber.org/zap" 41 ) 42 43 type ( 44 // server pike server 45 server struct { 46 mutex *sync.RWMutex 47 logFormat string 48 listening bool 49 listenAddr string 50 addr string 51 locations []string 52 cache string 53 compress string 54 compressMinLength int 55 compressContentTypeFilter *regexp.Regexp 56 processing atomic.Int32 57 ln net.Listener 58 e *elton.Elton 59 } 60 // servers pike server list 61 servers struct { 62 m *sync.Map 63 } 64 ServerOption struct { 65 // 访问日志格式化 66 LogFormat string 67 // 监听地址 68 Addr string 69 // 使用的location列表 70 Locations []string 71 // 使用的缓存 72 Cache string 73 // 使用的压缩服务 74 Compress string 75 // 压缩最小尺寸 76 CompressMinLength int 77 // 压缩数据类型 78 CompressContentTypeFilter *regexp.Regexp 79 } 80 ) 81 82 const ( 83 // statusKey 保存该请求对应的status: fetching, pass 等 84 statusKey = "_status" 85 // httpRespKey 保存请求对应的响应数据 86 httpRespKey = "_httpResp" 87 // httpRespAgeKey 保存缓存响应的age 88 httpRespAgeKey = "_httpRespAge" 89 // httpCacheMaxAgeKey 缓存有效期 90 httpCacheMaxAgeKey = "_httpCacheMaxAge" 91 ) 92 93 const defaultCompressMinLength = 1024 94 95 var defaultServers = NewServers(nil) 96 97 const ( 98 headerAge = "Age" 99 headerCacheStatus = "X-Status" 100 ) 101 102 var ( 103 ErrInvalidResponse = util.NewError("Invalid response", http.StatusServiceUnavailable) 104 105 ErrCacheDispatcherNotFound = util.NewError("Available cache dispatcher not found", http.StatusServiceUnavailable) 106 107 ErrLocationNotFound = util.NewError("Available location not found", http.StatusServiceUnavailable) 108 109 ErrUpstreamNotFound = util.NewError("Available upstream not found", http.StatusBadGateway) 110 ) 111 112 func getCacheStatus(c *elton.Context) cache.Status { 113 return cache.Status(c.GetInt(statusKey)) 114 } 115 func setCacheStatus(c *elton.Context, cacheStatus cache.Status) { 116 c.Set(statusKey, int(cacheStatus)) 117 } 118 119 func getHTTPResp(c *elton.Context) *cache.HTTPResponse { 120 value, exists := c.Get(httpRespKey) 121 if !exists { 122 return nil 123 } 124 resp, ok := value.(*cache.HTTPResponse) 125 if !ok { 126 return nil 127 } 128 return resp 129 } 130 func setHTTPResp(c *elton.Context, resp *cache.HTTPResponse) { 131 c.Set(httpRespKey, resp) 132 } 133 134 func setHTTPRespAge(c *elton.Context, age int) { 135 c.Set(httpRespAgeKey, age) 136 } 137 func getHTTPRespAge(c *elton.Context) int { 138 return c.GetInt(httpRespAgeKey) 139 } 140 141 func setHTTPCacheMaxAge(c *elton.Context, age int) { 142 c.Set(httpCacheMaxAgeKey, age) 143 } 144 func getHTTPCacheMaxAge(c *elton.Context) int { 145 return c.GetInt(httpCacheMaxAgeKey) 146 } 147 148 // NewServer create a new server 149 func NewServer(opt ServerOption) *server { 150 minLength := opt.CompressMinLength 151 // 如果未设置最少压缩长度,则设置为1KB 152 if minLength == 0 { 153 minLength = defaultCompressMinLength 154 } 155 return &server{ 156 mutex: &sync.RWMutex{}, 157 logFormat: opt.LogFormat, 158 addr: opt.Addr, 159 locations: opt.Locations, 160 cache: opt.Cache, 161 compress: opt.Compress, 162 compressMinLength: minLength, 163 compressContentTypeFilter: opt.CompressContentTypeFilter, 164 } 165 } 166 167 // NewServers create new server list 168 func NewServers(opts []ServerOption) *servers { 169 m := &sync.Map{} 170 for _, opt := range opts { 171 m.Store(opt.Addr, NewServer(opt)) 172 } 173 return &servers{ 174 m: m, 175 } 176 } 177 178 // Start start all server 179 func (ss *servers) Start() (err error) { 180 ss.m.Range(func(key, value interface{}) bool { 181 s, ok := value.(*server) 182 if ok { 183 err := s.Start(true) 184 if err != nil { 185 log.Default().Error("server start fail", 186 zap.String("addr", s.addr), 187 zap.Error(err), 188 ) 189 } 190 } 191 return true 192 }) 193 return nil 194 } 195 196 // Reset reset server list 197 func (ss *servers) Reset(opts []ServerOption) { 198 // 删除不再存在的server 199 result := util.MapDelete(ss.m, func(key string) bool { 200 exists := false 201 for _, opt := range opts { 202 if opt.Addr == key { 203 exists = true 204 break 205 } 206 } 207 return !exists 208 }) 209 for _, item := range result { 210 s, _ := item.(*server) 211 if s != nil { 212 // 由于close需要等待,因此切换时,使用goroutine来关闭 213 go func() { 214 err := s.Close() 215 if err != nil { 216 log.Default().Error("close server fail", 217 zap.String("addr", s.addr), 218 zap.Error(err), 219 ) 220 } 221 }() 222 } 223 } 224 for _, opt := range opts { 225 value, ok := ss.m.Load(opt.Addr) 226 // 如果该服务存在,则修改属性 227 if ok { 228 s, _ := value.(*server) 229 if s != nil { 230 s.Update(opt) 231 } 232 } else { 233 ss.m.Store(opt.Addr, NewServer(opt)) 234 } 235 } 236 } 237 238 // Close close the server list 239 func (ss *servers) Close() error { 240 ss.m.Range(func(_, value interface{}) bool { 241 s, _ := value.(*server) 242 if s != nil { 243 err := s.Close() 244 log.Default().Error("close server fail", 245 zap.String("addr", s.addr), 246 zap.Error(err), 247 ) 248 } 249 return true 250 }) 251 return nil 252 } 253 254 // Get get server for server list 255 func (ss *servers) Get(name string) *server { 256 value, ok := ss.m.Load(name) 257 if !ok { 258 return nil 259 } 260 s, ok := value.(*server) 261 if !ok { 262 return nil 263 } 264 return s 265 } 266 267 // Update 更新配置 268 func (s *server) Update(opt ServerOption) { 269 s.mutex.Lock() 270 defer s.mutex.Unlock() 271 s.locations = opt.Locations 272 s.cache = opt.Cache 273 s.compress = opt.Compress 274 s.compressMinLength = opt.CompressMinLength 275 s.compressContentTypeFilter = opt.CompressContentTypeFilter 276 } 277 278 // GetCache get the cache of server 279 func (s *server) GetCache() string { 280 s.mutex.RLock() 281 defer s.mutex.RUnlock() 282 return s.cache 283 } 284 285 // GetLocations get the locations of server 286 func (s *server) GetLocations() []string { 287 s.mutex.RLock() 288 defer s.mutex.RUnlock() 289 return s.locations 290 } 291 292 // GetCompress get the compress option of server 293 func (s *server) GetCompress() (name string, minLength int, filter *regexp.Regexp) { 294 s.mutex.RLock() 295 defer s.mutex.RUnlock() 296 return s.compress, s.compressMinLength, s.compressContentTypeFilter 297 } 298 299 // Start start the server 300 func (s *server) Start(useGoRoutine bool) (err error) { 301 s.mutex.Lock() 302 defer s.mutex.Unlock() 303 // 如监听中,则直接返回 304 if s.listening { 305 return 306 } 307 308 logger := log.Default() 309 310 // TODO 如果发生panic,停止处理新请求,程序退出 311 e := elton.New() 312 if s.logFormat != "" { 313 e.Use(middleware.NewLogger(middleware.LoggerConfig{ 314 DefaultFill: "-", 315 OnLog: func(str string, _ *elton.Context) { 316 logger.Info(str) 317 }, 318 Format: s.logFormat, 319 })) 320 } 321 e.Use(func(c *elton.Context) error { 322 s.processing.Add(1) 323 defer s.processing.Dec() 324 return c.Next() 325 }) 326 // TODO 考虑是否自定义出错中间件,对于系统的error(category: "pike")触发告警 327 e.Use(middleware.NewDefaultError()) 328 e.Use(middleware.NewDefaultFresh()) 329 e.Use(NewResponder()) 330 e.Use(NewCache(s)) 331 e.Use(NewProxy(s)) 332 e.ALL("/*", func(c *elton.Context) error { 333 return nil 334 }) 335 // TODO 一般使用时,pike的前置还有nginx或haproxy, 336 // 因此与客户端的各类超时由前置反向代理处理, 337 // 后续确认是否需要增加更多的参数设置, 338 // 如ReadTimeout ReadHeaderTimeout等 339 srv := &http.Server{ 340 Handler: e, 341 } 342 ln, err := net.Listen("tcp", s.addr) 343 if err != nil { 344 return 345 } 346 s.listening = true 347 s.e = e 348 s.ln = ln 349 s.listenAddr = ln.Addr().String() 350 if !useGoRoutine { 351 return srv.Serve(ln) 352 } 353 go func() { 354 err := srv.Serve(ln) 355 log.Default().Error("server serve fail", 356 zap.String("addr", s.addr), 357 zap.Error(err), 358 ) 359 }() 360 return nil 361 } 362 363 // Close close the server 364 func (s *server) Close() error { 365 s.mutex.Lock() 366 defer s.mutex.Unlock() 367 if !s.listening { 368 return nil 369 } 370 s.listening = false 371 err := s.e.GracefulClose(10 * time.Second) 372 if err != nil { 373 return err 374 } 375 return s.ln.Close() 376 } 377 378 // GetAddr get listen addr of server 379 func (s *server) GetListenAddr() string { 380 return s.listenAddr 381 } 382 383 func convertConfig(configs []config.ServerConfig) []ServerOption { 384 opts := make([]ServerOption, 0) 385 for _, item := range configs { 386 minLength, _ := humanize.ParseBytes(item.CompressMinLength) 387 var reg *regexp.Regexp 388 // 如果有配置则生成 389 if item.CompressContentTypeFilter != "" { 390 reg, _ = regexp.Compile(item.CompressContentTypeFilter) 391 } 392 opts = append(opts, ServerOption{ 393 LogFormat: item.LogFormat, 394 Addr: item.Addr, 395 Locations: item.Locations, 396 Cache: item.Cache, 397 Compress: item.Compress, 398 CompressMinLength: int(minLength), 399 CompressContentTypeFilter: reg, 400 }) 401 } 402 return opts 403 } 404 405 // Reset reset the default server list 406 func Reset(configs []config.ServerConfig) { 407 defaultServers.Reset(convertConfig(configs)) 408 } 409 410 // Get get server from default server list 411 func Get(name string) *server { 412 return defaultServers.Get(name) 413 } 414 415 // Start start the default server list 416 func Start() error { 417 return defaultServers.Start() 418 } 419 420 // CLose close the default server list 421 func Close() error { 422 return defaultServers.Close() 423 }