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  }