RateLimitingService::getStatus()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 13
c 1
b 0
f 1
dl 0
loc 18
rs 9.8333
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Usamamuneerchaudhary\Notifier\Services;
4
5
use Illuminate\Support\Facades\Cache;
6
use Illuminate\Support\Facades\Log;
7
use Usamamuneerchaudhary\Notifier\Models\NotificationSetting;
8
9
class RateLimitingService
10
{
11
    /**
12
     * Check if notification can be sent based on rate limits
13
     */
14
    public function canSend(): bool
15
    {
16
        $rateLimiting = NotificationSetting::getRateLimiting();
17
18
        if (!($rateLimiting['enabled'] ?? config('notifier.settings.rate_limiting.enabled', true))) {
19
            return true;
20
        }
21
22
        $maxPerMinute = $rateLimiting['max_per_minute'] ?? config('notifier.settings.rate_limiting.max_per_minute', 60);
23
        $maxPerHour = $rateLimiting['max_per_hour'] ?? config('notifier.settings.rate_limiting.max_per_hour', 1000);
24
        $maxPerDay = $rateLimiting['max_per_day'] ?? config('notifier.settings.rate_limiting.max_per_day', 10000);
25
26
        return $this->checkLimit('minute', $maxPerMinute)
27
            && $this->checkLimit('hour', $maxPerHour)
28
            && $this->checkLimit('day', $maxPerDay);
29
    }
30
31
    /**
32
     * Get current count for a time period
33
     */
34
    public function getCurrentCount(string $period): int
35
    {
36
        $key = $this->getCacheKey($period);
37
        return Cache::get($key, 0);
38
    }
39
40
    /**
41
     * Increment rate limit counter
42
     */
43
    public function increment(): void
44
    {
45
        $now = now();
46
47
        $minuteKey = $this->getCacheKey('minute', $now);
48
        Cache::increment($minuteKey);
49
        Cache::put($minuteKey, Cache::get($minuteKey, 0), now()->addMinutes(2));
50
51
        $hourKey = $this->getCacheKey('hour', $now);
52
        Cache::increment($hourKey);
53
        Cache::put($hourKey, Cache::get($hourKey, 0), now()->addHours(2));
54
55
        $dayKey = $this->getCacheKey('day', $now);
56
        Cache::increment($dayKey);
57
        Cache::put($dayKey, Cache::get($dayKey, 0), now()->addDays(2));
58
    }
59
60
    /**
61
     * Check if limit is exceeded for a given period
62
     */
63
    protected function checkLimit(string $period, int $maxLimit): bool
64
    {
65
        $key = $this->getCacheKey($period);
66
        $count = Cache::get($key, 0);
67
68
        if ($count >= $maxLimit) {
69
            Log::warning("Rate limit exceeded: {$period} limit ({$maxLimit})", [
70
                'current_count' => $count,
71
                'limit' => $maxLimit,
72
                'period' => $period,
73
            ]);
74
            return false;
75
        }
76
77
        return true;
78
    }
79
80
    /**
81
     * Get cache key for a time period
82
     */
83
    protected function getCacheKey(string $period, ?\Carbon\Carbon $time = null): string
84
    {
85
        $time = $time ?? now();
86
87
        return match ($period) {
88
            'minute' => "notifier:rate_limit:minute:" . $time->format('Y-m-d-H-i'),
89
            'hour' => "notifier:rate_limit:hour:" . $time->format('Y-m-d-H'),
90
            'day' => "notifier:rate_limit:day:" . $time->format('Y-m-d'),
91
            default => "notifier:rate_limit:{$period}:" . $time->timestamp,
92
        };
93
    }
94
95
    /**
96
     * Get rate limit status information
97
     */
98
    public function getStatus(): array
99
    {
100
        $rateLimiting = NotificationSetting::getRateLimiting();
101
102
        return [
103
            'enabled' => $rateLimiting['enabled'] ?? config('notifier.settings.rate_limiting.enabled', true),
104
            'limits' => [
105
                'minute' => [
106
                    'max' => $rateLimiting['max_per_minute'] ?? config('notifier.settings.rate_limiting.max_per_minute', 60),
107
                    'current' => $this->getCurrentCount('minute'),
108
                ],
109
                'hour' => [
110
                    'max' => $rateLimiting['max_per_hour'] ?? config('notifier.settings.rate_limiting.max_per_hour', 1000),
111
                    'current' => $this->getCurrentCount('hour'),
112
                ],
113
                'day' => [
114
                    'max' => $rateLimiting['max_per_day'] ?? config('notifier.settings.rate_limiting.max_per_day', 10000),
115
                    'current' => $this->getCurrentCount('day'),
116
                ],
117
            ],
118
        ];
119
    }
120
}
121
122