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
38#[cfg(not(target_arch = "wasm32"))]
55pub async fn check_rate_limit(client: &octocrab::Octocrab) -> Result<RateLimitStatus> {
56 debug!("Checking GitHub API rate limit");
57
58 let rate_limit = client.ratelimit().get().await?;
59
60 #[allow(clippy::cast_possible_truncation)]
61 let status = RateLimitStatus {
62 remaining: rate_limit.resources.core.remaining as u32,
63 limit: rate_limit.resources.core.limit as u32,
64 reset_at: rate_limit.resources.core.reset,
65 };
66
67 debug!(
68 remaining = status.remaining,
69 limit = status.limit,
70 "GitHub rate limit status"
71 );
72
73 Ok(status)
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_rate_limit_status_is_low_true() {
82 let status = RateLimitStatus {
83 remaining: 50,
84 limit: 5000,
85 reset_at: 1_234_567_890,
86 };
87 assert!(status.is_low());
88 }
89
90 #[test]
91 fn test_rate_limit_status_is_low_false() {
92 let status = RateLimitStatus {
93 remaining: 150,
94 limit: 5000,
95 reset_at: 1_234_567_890,
96 };
97 assert!(!status.is_low());
98 }
99
100 #[test]
101 fn test_rate_limit_status_is_low_boundary() {
102 let status = RateLimitStatus {
103 remaining: 100,
104 limit: 5000,
105 reset_at: 1_234_567_890,
106 };
107 assert!(!status.is_low());
108 }
109
110 #[test]
111 fn test_rate_limit_status_message() {
112 let status = RateLimitStatus {
113 remaining: 42,
114 limit: 5000,
115 reset_at: 1_234_567_890,
116 };
117 assert_eq!(status.message(), "GitHub API: 42/5000 calls remaining");
118 }
119}