aptu_core/github/
ratelimit.rs1use anyhow::Result;
8use tracing::debug;
9
10#[derive(Debug, Clone)]
12pub struct RateLimitStatus {
13 pub remaining: u32,
15 pub limit: u32,
17 pub reset_at: u64,
19}
20
21impl RateLimitStatus {
22 #[must_use]
24 pub fn is_low(&self) -> bool {
25 self.remaining < 100
26 }
27
28 #[must_use]
30 pub fn message(&self) -> String {
31 format!(
32 "GitHub API: {}/{} calls remaining",
33 self.remaining, self.limit
34 )
35 }
36}
37
38pub async fn check_rate_limit(client: &octocrab::Octocrab) -> Result<RateLimitStatus> {
55 debug!("Checking GitHub API rate limit");
56
57 let rate_limit = client.ratelimit().get().await?;
58
59 #[allow(clippy::cast_possible_truncation)]
60 let status = RateLimitStatus {
61 remaining: rate_limit.resources.core.remaining as u32,
62 limit: rate_limit.resources.core.limit as u32,
63 reset_at: rate_limit.resources.core.reset,
64 };
65
66 debug!(
67 remaining = status.remaining,
68 limit = status.limit,
69 "GitHub rate limit status"
70 );
71
72 Ok(status)
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_rate_limit_status_is_low_true() {
81 let status = RateLimitStatus {
82 remaining: 50,
83 limit: 5000,
84 reset_at: 1_234_567_890,
85 };
86 assert!(status.is_low());
87 }
88
89 #[test]
90 fn test_rate_limit_status_is_low_false() {
91 let status = RateLimitStatus {
92 remaining: 150,
93 limit: 5000,
94 reset_at: 1_234_567_890,
95 };
96 assert!(!status.is_low());
97 }
98
99 #[test]
100 fn test_rate_limit_status_is_low_boundary() {
101 let status = RateLimitStatus {
102 remaining: 100,
103 limit: 5000,
104 reset_at: 1_234_567_890,
105 };
106 assert!(!status.is_low());
107 }
108
109 #[test]
110 fn test_rate_limit_status_message() {
111 let status = RateLimitStatus {
112 remaining: 42,
113 limit: 5000,
114 reset_at: 1_234_567_890,
115 };
116 assert_eq!(status.message(), "GitHub API: 42/5000 calls remaining");
117 }
118}