|
@@ -1,9 +1,11 @@
|
|
|
package loadbalance
|
|
|
|
|
|
import (
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+
|
|
|
"imuslab.com/zoraxy/mod/geodb"
|
|
|
"imuslab.com/zoraxy/mod/info/logger"
|
|
|
- "imuslab.com/zoraxy/mod/uptime"
|
|
|
)
|
|
|
|
|
|
/*
|
|
@@ -14,47 +16,81 @@ import (
|
|
|
|
|
|
type BalancePolicy int
|
|
|
|
|
|
-const (
|
|
|
- BalancePolicy_RoundRobin BalancePolicy = 0 //Round robin, will ignore upstream if down
|
|
|
- BalancePolicy_Fallback BalancePolicy = 1 //Fallback only. Will only switch to next node if the first one failed
|
|
|
- BalancePolicy_Random BalancePolicy = 2 //Random, randomly pick one from the list that is online
|
|
|
- BalancePolicy_GeoRegion BalancePolicy = 3 //Use the one defined for this geo-location, when down, pick the next avaible node
|
|
|
-)
|
|
|
+// Data structure to hold the upstream server information
|
|
|
+type Upstream struct {
|
|
|
+ ProxyTargetIpOrDomain string //Target IP address or domain name with port
|
|
|
+ RequireTLS bool //Require TLS connection
|
|
|
+ PreferedCountryCode []string //Prefered country codes, default to empty string slice (not assigned)
|
|
|
+ Priority int //Prirotiy of fallback, set all to 0 for round robin
|
|
|
+}
|
|
|
|
|
|
+// LoadBalanceRule stores the load balance option of this host. If there are no usable upstreams for lb, the primary one will be used
|
|
|
type LoadBalanceRule struct {
|
|
|
- Upstreams []string //Reverse proxy upstream servers
|
|
|
- LoadBalancePolicy BalancePolicy //Policy in deciding which target IP to proxy
|
|
|
- UseRegionLock bool //If this is enabled with BalancePolicy_Geo, when the main site failed, it will not pick another node
|
|
|
- UseStickySession bool //Use sticky session, if you are serving EU countries, make sure to add the "Do you want cookie" warning
|
|
|
+ Upstreams []Upstream //Reverse proxy upstream servers
|
|
|
+ UseStickySession bool //Enable stick session
|
|
|
+}
|
|
|
|
|
|
- parent *RouteManager
|
|
|
+// PrimaryRoutingRule stores the primary routing target of this host
|
|
|
+type PrimaryRoutingRule struct {
|
|
|
+ MatchingDomainOrIp string //Primary proxy upstream origin server
|
|
|
+ RequireTLS bool //Target require TLS
|
|
|
}
|
|
|
|
|
|
type Options struct {
|
|
|
- Geodb *geodb.Store //GeoIP resolver for checking incoming request origin country
|
|
|
- UptimeMonitor *uptime.Monitor //For checking if the target is online, this might be nil when the module starts
|
|
|
+ Geodb *geodb.Store //GeoIP resolver for checking incoming request origin country
|
|
|
+ Logger *logger.Logger
|
|
|
}
|
|
|
|
|
|
type RouteManager struct {
|
|
|
- Options Options
|
|
|
- Logger *logger.Logger
|
|
|
+ LoadBalanceMap sync.Map //Sync map to store the last load balance state of a given node
|
|
|
+ OnlineStatusMap sync.Map //Sync map to store the online status of a given ip address or domain name
|
|
|
+
|
|
|
+ onlineStatusTickerStop chan bool //Stopping channel for the online status pinger
|
|
|
+ Options Options //Options for the load balancer
|
|
|
}
|
|
|
|
|
|
-// Create a new load balance route manager
|
|
|
-func NewRouteManager(options *Options, logger *logger.Logger) *RouteManager {
|
|
|
- newManager := RouteManager{
|
|
|
- Options: *options,
|
|
|
- Logger: logger,
|
|
|
+// Create a new load balancer
|
|
|
+func NewLoadBalancer(options *Options) *RouteManager {
|
|
|
+ onlineStatusCheckerStopChan := make(chan bool)
|
|
|
+
|
|
|
+ return &RouteManager{
|
|
|
+ LoadBalanceMap: sync.Map{},
|
|
|
+ OnlineStatusMap: sync.Map{},
|
|
|
+ onlineStatusTickerStop: onlineStatusCheckerStopChan,
|
|
|
+ Options: *options,
|
|
|
}
|
|
|
- logger.PrintAndLog("INFO", "Load Balance Route Manager started", nil)
|
|
|
- return &newManager
|
|
|
}
|
|
|
|
|
|
-func (b *LoadBalanceRule) GetProxyTargetIP() {
|
|
|
-//TODO: Implement get proxy target IP logic here
|
|
|
+func (m *RouteManager) UpdateKeepAliveTargets(pingTargets []*PrimaryRoutingRule) {
|
|
|
+ ticker := time.NewTicker(1 * time.Minute)
|
|
|
+ defer ticker.Stop()
|
|
|
+
|
|
|
+ go func() {
|
|
|
+ for {
|
|
|
+ select {
|
|
|
+ case <-m.onlineStatusTickerStop:
|
|
|
+ ticker.Stop()
|
|
|
+ return
|
|
|
+ case <-ticker.C:
|
|
|
+ for _, target := range pingTargets {
|
|
|
+ isOnline := PingTarget(target)
|
|
|
+ m.LoadBalanceMap.Store(target.MatchingDomainOrIp, isOnline)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
+// GetProxyTargetIP Get the proxy target given the primary routing rule and load balance options
|
|
|
+func (m *RouteManager) GetProxyTargetIP(pr *PrimaryRoutingRule, lbr *LoadBalanceRule) {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func (m *RouteManager) Close() {
|
|
|
+ m.onlineStatusTickerStop <- true
|
|
|
}
|
|
|
|
|
|
// Print debug message
|
|
|
func (m *RouteManager) debugPrint(message string, err error) {
|
|
|
- m.Logger.PrintAndLog("LB", message, err)
|
|
|
+ m.Options.Logger.PrintAndLog("LoadBalancer", message, err)
|
|
|
}
|