Skip to main content

strava_wrapper/
api.rs

1use crate::endpoints::{
2    ActivitiesEndpoint, AthleteEndpoint, AthletesEndpoint, ClubsEndpoint, GearEndpoint,
3    RoutesEndpoint, SegmentsEndpoint, StreamsEndpoint, UploadsEndpoint,
4};
5use crate::query::{last_rate_limit, RateLimit};
6use std::sync::{Arc, RwLock};
7
8/// Entry point into the Strava API wrapper.
9///
10/// `StravaAPI` is cheap to clone: it only contains an `Arc` reference to the
11/// shared token. Mutating the token via [`StravaAPI::set_token`] is visible to
12/// all clones, which lets long-running applications refresh the access token
13/// without rebuilding the whole call stack.
14#[derive(Clone)]
15pub struct StravaAPI {
16    url: String,
17    token: Arc<RwLock<String>>,
18}
19
20impl StravaAPI {
21    pub fn new(url: &str, token: impl Into<String>) -> Self {
22        Self {
23            url: url.into(),
24            token: Arc::new(RwLock::new(token.into())),
25        }
26    }
27
28    /// Returns a clone of the current access token.
29    pub fn token(&self) -> String {
30        self.token.read().expect("token lock poisoned").clone()
31    }
32
33    /// Replaces the access token. Use after calling
34    /// [`auth::refresh_token`](crate::auth::refresh_token) to swap the expired
35    /// access token for the newly issued one.
36    pub fn set_token(&self, token: impl Into<String>) {
37        *self.token.write().expect("token lock poisoned") = token.into();
38    }
39
40    /// Latest rate-limit snapshot observed from any Strava response in this
41    /// process. Returns `None` until the first request with valid
42    /// `X-RateLimit-*` headers lands.
43    ///
44    /// Strava rate limits are per-application, so the snapshot is shared
45    /// across every `StravaAPI` instance in the process.
46    pub fn rate_limit(&self) -> Option<RateLimit> {
47        last_rate_limit()
48    }
49
50    pub fn activities(&self) -> ActivitiesEndpoint {
51        ActivitiesEndpoint::new(&self.url, self.token())
52    }
53
54    pub fn athlete(&self) -> AthleteEndpoint {
55        AthleteEndpoint::new(&self.url, self.token())
56    }
57
58    pub fn athletes(&self) -> AthletesEndpoint {
59        AthletesEndpoint::new(&self.url, self.token())
60    }
61
62    pub fn clubs(&self) -> ClubsEndpoint {
63        ClubsEndpoint::new(&self.url, self.token())
64    }
65
66    pub fn gear(&self) -> GearEndpoint {
67        GearEndpoint::new(&self.url, self.token())
68    }
69
70    pub fn routes(&self) -> RoutesEndpoint {
71        RoutesEndpoint::new(&self.url, self.token())
72    }
73
74    pub fn segments(&self) -> SegmentsEndpoint {
75        SegmentsEndpoint::new(&self.url, self.token())
76    }
77
78    pub fn streams(&self) -> StreamsEndpoint {
79        StreamsEndpoint::new(&self.url, self.token())
80    }
81
82    pub fn uploads(&self) -> UploadsEndpoint {
83        UploadsEndpoint::new(&self.url, self.token())
84    }
85}