diff --git a/package.json b/package.json index f89d139..1c853b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.1.18-unstable3", + "version": "0.1.18-unstable4", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/docker/events.go b/src/docker/events.go index a52b009..0408053 100644 --- a/src/docker/events.go +++ b/src/docker/events.go @@ -62,5 +62,5 @@ func onDockerDestroyed(containerID string) { func onNetworkDisconnect(networkID string) { utils.Debug("onNetworkDisconnect: " + networkID) - NetworkCleanUp(networkID) + DebouncedNetworkCleanUp(networkID) } \ No newline at end of file diff --git a/src/docker/network.go b/src/docker/network.go index a23815a..4a5f5f7 100644 --- a/src/docker/network.go +++ b/src/docker/network.go @@ -4,6 +4,7 @@ import ( "os" "time" "errors" + "sync" "github.com/azukaar/cosmos-server/src/utils" @@ -221,11 +222,29 @@ func ConnectToNetworkSync(networkName string, containerID string) error { return nil } -func NetworkCleanUp(networkId string) { - if(networkId == "bridge" || networkId == "host" || networkId == "none") { - return - } +func _debounceNetworkCleanUp() func(string) { + var mu sync.Mutex + var timer *time.Timer + return func(networkId string) { + if(networkId == "bridge" || networkId == "host" || networkId == "none") { + return + } + + mu.Lock() + defer mu.Unlock() + + if timer != nil { + timer.Stop() + } + + timer = time.AfterFunc(30*time.Minute, NetworkCleanUp) + } +} + +var DebouncedNetworkCleanUp = _debounceNetworkCleanUp() + +func NetworkCleanUp() { DockerNetworkLock <- true defer func() { <-DockerNetworkLock }() diff --git a/src/proxy/shield.go b/src/proxy/shield.go index 5e9985d..c390de7 100644 --- a/src/proxy/shield.go +++ b/src/proxy/shield.go @@ -7,6 +7,8 @@ import ( "net/http" "fmt" "net" + "math" + "strconv" ) /* @@ -168,6 +170,16 @@ func (shield *smartShieldState) computeThrottle(policy utils.SmartShieldPolicy, return throttle } +func calculateLowestExhaustedPercentage(policy utils.SmartShieldPolicy, userConsumed userUsedBudget) int64 { + timeExhaustedPercentage := 100 - (userConsumed.Time / policy.PerUserTimeBudget) * 100 + requestsExhaustedPercentage := 100 - (float64(userConsumed.Requests) / float64(policy.PerUserRequestLimit)) * 100 + bytesExhaustedPercentage := 100 - (float64(userConsumed.Bytes) / float64(policy.PerUserByteLimit)) * 100 + + // utils.Debug(fmt.Sprintf("Time: %f, Requests: %d, Bytes: %d", timeExhaustedPercentage, requestsExhaustedPercentage, bytesExhaustedPercentage)) + + return int64(math.Max(0, math.Min(math.Min(timeExhaustedPercentage, requestsExhaustedPercentage), bytesExhaustedPercentage))) +} + func GetClientID(r *http.Request) string { ip, _, _ := net.SplitHostPort(r.RemoteAddr) return ip @@ -216,6 +228,12 @@ func SmartShieldMiddleware(policy utils.SmartShieldPolicy) func(http.Handler) ht policy: policy, } + // add rate limite headers + In20Minutes := strconv.FormatInt(time.Now().Add(20 * time.Minute).Unix(), 10) + w.Header().Set("X-RateLimit-Remaining", strconv.FormatInt(calculateLowestExhaustedPercentage(policy, userConsumed), 10)) + w.Header().Set("X-RateLimit-Limit", strconv.FormatInt(int64(policy.PerUserRequestLimit), 10)) + w.Header().Set("X-RateLimit-Reset", In20Minutes) + utils.Debug("SmartShield: Adding request") shield.Lock() shield.requests = append(shield.requests, wrapper) diff --git a/src/utils/utils.go b/src/utils/utils.go index 69a95fa..9019682 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -302,4 +302,4 @@ func GetAvailableRAM() uint64 { // Use total available memory as an approximation return vmStat.Available -} +} \ No newline at end of file