浏览代码

Move team-data API access to separate module

This also adds retries (up to three total requests) if we timeout on connection.
It's possible we should be less restrictive and always retry, but the hope is
that timeouts are sufficient. This may not cover (for example) a "connection
reset by peer" error though, even if fundamentally that's also a timeout, just
of a different kind.
Mark Rousskov 5 年之前
父节点
当前提交
12a2b3cb58
共有 4 个文件被更改,包括 43 次插入25 次删除
  1. 3 15
      src/github.rs
  2. 1 0
      src/lib.rs
  3. 37 0
      src/team_data.rs
  4. 2 10
      src/zulip.rs

+ 3 - 15
src/github.rs

@@ -56,11 +56,7 @@ impl User {
     }
 
     pub async fn is_team_member<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result<bool> {
-        let url = format!("{}/teams.json", rust_team_data::v1::BASE_URL);
-        let permission: rust_team_data::v1::Teams = client
-            .json(client.raw().get(&url))
-            .await
-            .context("could not get team data")?;
+        let permission = crate::team_data::teams(client).await?;
         let map = permission.teams;
         let is_triager = map
             .get("wg-triage")
@@ -70,11 +66,7 @@ impl User {
 
     // Returns the ID of the given user, if the user is in the `all` team.
     pub async fn get_id<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result<Option<usize>> {
-        let url = format!("{}/teams.json", rust_team_data::v1::BASE_URL);
-        let permission: rust_team_data::v1::Teams = client
-            .json(client.raw().get(&url))
-            .await
-            .context("could not get team data")?;
+        let permission = crate::team_data::teams(client).await?;
         let map = permission.teams;
         Ok(map["all"]
             .members
@@ -88,11 +80,7 @@ pub async fn get_team(
     client: &GithubClient,
     team: &str,
 ) -> anyhow::Result<Option<rust_team_data::v1::Team>> {
-    let url = format!("{}/teams.json", rust_team_data::v1::BASE_URL);
-    let permission: rust_team_data::v1::Teams = client
-        .json(client.raw().get(&url))
-        .await
-        .context("could not get team data")?;
+    let permission = crate::team_data::teams(client).await?;
     let mut map = permission.teams;
     Ok(map.swap_remove(team))
 }

+ 1 - 0
src/lib.rs

@@ -13,6 +13,7 @@ pub mod interactions;
 pub mod notification_listing;
 pub mod payload;
 pub mod team;
+mod team_data;
 pub mod zulip;
 
 #[derive(Debug)]

+ 37 - 0
src/team_data.rs

@@ -0,0 +1,37 @@
+use crate::github::GithubClient;
+use anyhow::Context as _;
+use rust_team_data::v1::{Teams, ZulipMapping, BASE_URL};
+use serde::de::DeserializeOwned;
+
+async fn by_url<T: DeserializeOwned>(client: &GithubClient, path: &str) -> anyhow::Result<T> {
+    let url = format!("{}{}", BASE_URL, path);
+    for _ in 0i32..3 {
+        let map: Result<T, _> = client.json(client.raw().get(&url)).await;
+        match map {
+            Ok(v) => return Ok(v),
+            Err(e) => {
+                if e.downcast_ref::<reqwest::Error>()
+                    .map_or(false, |e| e.is_timeout())
+                {
+                    continue;
+                } else {
+                    return Err(e);
+                }
+            }
+        }
+    }
+
+    Err(anyhow::anyhow!("Failed to retrieve {} in 3 requests", url))
+}
+
+pub async fn zulip_map(client: &GithubClient) -> anyhow::Result<ZulipMapping> {
+    by_url(client, "/zulip-map.json")
+        .await
+        .context("team-api: zulip-map.json")
+}
+
+pub async fn teams(client: &GithubClient) -> anyhow::Result<Teams> {
+    by_url(client, "/teams.json")
+        .await
+        .context("team-api: teams.json")
+}

+ 2 - 10
src/zulip.rs

@@ -31,20 +31,12 @@ struct Response<'a> {
 }
 
 pub async fn to_github_id(client: &GithubClient, zulip_id: usize) -> anyhow::Result<Option<i64>> {
-    let url = format!("{}/zulip-map.json", rust_team_data::v1::BASE_URL);
-    let map: rust_team_data::v1::ZulipMapping = client
-        .json(client.raw().get(&url))
-        .await
-        .context("could not get team data")?;
+    let map = crate::team_data::zulip_map(client).await?;
     Ok(map.users.get(&zulip_id).map(|v| *v as i64))
 }
 
 pub async fn to_zulip_id(client: &GithubClient, github_id: i64) -> anyhow::Result<Option<usize>> {
-    let url = format!("{}/zulip-map.json", rust_team_data::v1::BASE_URL);
-    let map: rust_team_data::v1::ZulipMapping = client
-        .json(client.raw().get(&url))
-        .await
-        .context("could not get team data")?;
+    let map = crate::team_data::zulip_map(client).await?;
     Ok(map
         .users
         .iter()