1use std::collections::HashSet;
4use std::ops::{Deref, DerefMut};
5
6use octorust::auth::Credentials;
7use octorust::Client;
8use tracing::{info, instrument, Level};
9
10type Result<T> = std::result::Result<T, octorust::ClientError>;
11
12#[derive(Clone)]
25#[repr(transparent)]
26pub struct GitHub(Client);
27
28impl Deref for GitHub {
29 type Target = Client;
30
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36impl DerefMut for GitHub {
37 fn deref_mut(&mut self) -> &mut Self::Target {
38 &mut self.0
39 }
40}
41
42impl GitHub {
43 const USER_AGENT: &'static str = "gfas";
44
45 pub fn new(token: String) -> Result<Self> {
47 Ok(Self(Client::new(Self::USER_AGENT, Credentials::Token(token))?))
48 }
49
50 #[instrument(skip(self), ret(level = Level::TRACE), err)]
57 pub async fn explore(&self, user: &str, following: bool) -> Result<HashSet<String>> {
58 let mut res = HashSet::new();
59
60 const PER_PAGE: i64 = 100;
61
62 let users = self.users();
63
64 for page in 1.. {
65 let response = if following {
66 users.list_following_for_user(user, PER_PAGE, page).await
67 } else {
68 users.list_followers_for_user(user, PER_PAGE, page).await
69 }?;
70
71 let explored = response.body.into_iter().map(|u| u.login);
72
73 let len = explored.len() as i64;
74
75 res.extend(explored);
76
77 info!("{}(+{len})", res.len());
78
79 if len < PER_PAGE {
80 break;
81 }
82 }
83
84 Ok(res)
85 }
86}