loadbalance.go 3.0 KB

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