loadbalance.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package loadbalance
  2. import (
  3. "strings"
  4. "sync"
  5. "sync/atomic"
  6. "github.com/google/uuid"
  7. "github.com/gorilla/sessions"
  8. "imuslab.com/zoraxy/mod/dynamicproxy/dpcore"
  9. "imuslab.com/zoraxy/mod/geodb"
  10. "imuslab.com/zoraxy/mod/info/logger"
  11. )
  12. /*
  13. Load Balancer
  14. Handleing load balance request for upstream destinations
  15. */
  16. type Options struct {
  17. SystemUUID string //Use for the session store
  18. UseActiveHealthCheck bool //Use active health check, default to false
  19. Geodb *geodb.Store //GeoIP resolver for checking incoming request origin country
  20. Logger *logger.Logger
  21. }
  22. type RouteManager struct {
  23. SessionStore *sessions.CookieStore
  24. LoadBalanceMap sync.Map //Sync map to store the last load balance state of a given node
  25. OnlineStatusMap sync.Map //Sync map to store the online status of a given ip address or domain name
  26. onlineStatusTickerStop chan bool //Stopping channel for the online status pinger
  27. Options Options //Options for the load balancer
  28. }
  29. /* Upstream or Origin Server */
  30. type Upstream struct {
  31. //Upstream Proxy Configs
  32. OriginIpOrDomain string //Target IP address or domain name with port
  33. RequireTLS bool //Require TLS connection
  34. SkipCertValidations bool //Set to true to accept self signed certs
  35. SkipWebSocketOriginCheck bool //Skip origin check on websocket upgrade connections
  36. //Load balancing configs
  37. Weight int //Random weight for round robin, 0 for fallback only
  38. MaxConn int //Maxmium connection to this server, 0 for unlimited
  39. currentConnectionCounts atomic.Uint64 //Counter for number of client currently connected
  40. proxy *dpcore.ReverseProxy
  41. }
  42. // Create a new load balancer
  43. func NewLoadBalancer(options *Options) *RouteManager {
  44. if options.SystemUUID == "" {
  45. //System UUID not passed in. Use random key
  46. options.SystemUUID = uuid.New().String()
  47. }
  48. //Generate a session store for stickySession
  49. store := sessions.NewCookieStore([]byte("something-very-secret"))
  50. return &RouteManager{
  51. SessionStore: store,
  52. LoadBalanceMap: sync.Map{},
  53. OnlineStatusMap: sync.Map{},
  54. onlineStatusTickerStop: nil,
  55. Options: *options,
  56. }
  57. }
  58. // UpstreamsReady checks if the group of upstreams contains at least one
  59. // origin server that is ready
  60. func (m *RouteManager) UpstreamsReady(upstreams []*Upstream) bool {
  61. for _, upstream := range upstreams {
  62. if upstream.IsReady() {
  63. return true
  64. }
  65. }
  66. return false
  67. }
  68. // String format and convert a list of upstream into a string representations
  69. func GetUpstreamsAsString(upstreams []*Upstream) string {
  70. targets := []string{}
  71. for _, upstream := range upstreams {
  72. targets = append(targets, upstream.String())
  73. }
  74. return strings.Join(targets, ", ")
  75. }
  76. func (m *RouteManager) Close() {
  77. if m.onlineStatusTickerStop != nil {
  78. m.onlineStatusTickerStop <- true
  79. }
  80. }
  81. // Print debug message
  82. func (m *RouteManager) debugPrint(message string, err error) {
  83. m.Options.Logger.PrintAndLog("LoadBalancer", message, err)
  84. }