1+ use std:: time:: Duration ;
2+
13use futures:: future:: join_all;
24use octocrab:: models:: repos;
35use octocrab:: repos:: RepoHandler ;
46use octocrab:: { Octocrab , OctocrabBuilder } ;
7+ use reqwest:: StatusCode ;
58use semver:: Version ;
69
710use crate :: config:: ApiConfig ;
811use crate :: errors:: { InternalError , Result } ;
9- use crate :: game_data:: { Asset , Assets , GameRelease , Repo } ;
12+ use crate :: game_data:: { Asset , AssetList , AssetPerPlatform , GameReleases , Repo } ;
1013
1114pub struct Fetcher {
1215 octocrab : Octocrab ,
@@ -16,7 +19,7 @@ pub struct Fetcher {
1619 checksum_fetcher : ChecksumFetcher ,
1720}
1821
19- struct ChecksumFetcher ( reqwest :: Client ) ;
22+ struct ChecksumFetcher ( reqwest_middleware :: ClientWithMiddleware ) ;
2023
2124impl Fetcher {
2225 pub fn from_config ( config : & ApiConfig ) -> Result < Self > {
@@ -38,11 +41,12 @@ impl Fetcher {
3841 self . octocrab . repos ( repo. owner ( ) , repo. repository ( ) )
3942 }
4043
41- pub async fn get_latest_game_release ( & self ) -> Result < GameRelease > {
44+ pub async fn get_latest_game_releases ( & self ) -> Result < GameReleases > {
4245 let releases = self
4346 . on_repo ( & self . game_repo )
4447 . releases ( )
4548 . list ( )
49+ . per_page ( 100 )
4650 . send ( )
4751 . await ?;
4852
@@ -58,36 +62,52 @@ impl Fetcher {
5862 let mut binaries = self
5963 . get_assets_and_checksums ( & latest_release. assets , & latest_version, None )
6064 . await
61- . map ( |( ( platform, mut asset) , sha256) | {
62- asset. sha256 = sha256?;
63- Ok ( ( platform. to_string ( ) , asset) )
65+ . filter_map ( |( ( platform, mut asset) , sha256) | {
66+ match sha256 {
67+ Ok ( checksum) => {
68+ asset. sha256 = checksum;
69+ Some ( Ok ( ( platform. to_string ( ) , asset) ) )
70+ } ,
71+ Err ( err) => {
72+ log:: error!( "ignoring asset {0} (version: {1}) because an error occurred for checksum: {2:?}" , asset. name, asset. version, err) ;
73+ None
74+ }
75+ }
6476 } )
65- . collect :: < Result < Assets > > ( ) ?;
77+ . collect :: < Result < AssetPerPlatform > > ( ) ?;
78+
79+ let mut assets = AssetList :: new ( ) ;
6680
6781 for ( version, release) in versions_released {
6882 for ( ( platform, mut asset) , sha256) in self
6983 . get_assets_and_checksums ( & release. assets , & version, Some ( & binaries) )
7084 . await
7185 {
72- asset. sha256 = sha256?;
73- binaries. insert ( platform. to_string ( ) , asset) ;
86+ match sha256 {
87+ Ok ( checksum) => {
88+ asset. sha256 = checksum;
89+
90+ if platform == "assets" {
91+ assets. push ( asset) ;
92+ } else {
93+ binaries. insert ( platform. to_string ( ) , asset) ;
94+ }
95+ } ,
96+ Err ( err) => {
97+ log:: error!( "ignoring asset {0} (version: {1}) because an error occurred for checksum: {2:?}" , asset. name, asset. version, err) ;
98+ }
99+ }
74100 }
75101 }
76102
77- let latest_assets = binaries. remove ( "assets" ) ;
78-
79- match latest_assets {
80- Some ( assets) => Ok ( GameRelease {
81- assets_version : assets. version . clone ( ) ,
82- assets,
83- binaries,
84- version : latest_version,
85- } ) ,
86- None => Err ( InternalError :: NoReleaseFound ) ,
103+ if binaries. is_empty ( ) {
104+ return Err ( InternalError :: NoReleaseFound ) ;
87105 }
106+
107+ Ok ( GameReleases { assets, binaries } )
88108 }
89109
90- pub async fn get_latest_updater_release ( & self ) -> Result < Assets > {
110+ pub async fn get_latest_updater_release ( & self ) -> Result < AssetPerPlatform > {
91111 let last_release = self
92112 . on_repo ( & self . updater_repo )
93113 . releases ( )
@@ -98,18 +118,26 @@ impl Fetcher {
98118
99119 self . get_assets_and_checksums ( & last_release. assets , & version, None )
100120 . await
101- . map ( |( ( platform, mut asset) , sha256) | {
102- asset. sha256 = sha256?;
103- Ok ( ( platform. to_string ( ) , asset) )
121+ . filter_map ( |( ( platform, mut asset) , sha256) | {
122+ match sha256 {
123+ Ok ( checksum) => {
124+ asset. sha256 = checksum;
125+ Some ( Ok ( ( platform. to_string ( ) , asset) ) )
126+ } ,
127+ Err ( err) => {
128+ log:: error!( "ignoring updater {0} (version: {1}) because an error occurred for checksum: {2:?}" , asset. name, asset. version, err) ;
129+ None
130+ }
131+ }
104132 } )
105- . collect :: < Result < Assets > > ( )
133+ . collect :: < Result < AssetPerPlatform > > ( )
106134 }
107135
108136 async fn get_assets_and_checksums < ' a : ' b , ' b , A > (
109137 & self ,
110138 assets : A ,
111139 version : & Version ,
112- binaries : Option < & Assets > ,
140+ binaries : Option < & AssetPerPlatform > ,
113141 ) -> impl Iterator < Item = ( ( & ' b str , Asset ) , Result < Option < String > > ) >
114142 where
115143 A : IntoIterator < Item = & ' a repos:: Asset > ,
@@ -140,7 +168,16 @@ impl Fetcher {
140168
141169impl ChecksumFetcher {
142170 fn new ( ) -> Self {
143- Self ( reqwest:: Client :: new ( ) )
171+ let retry_policy = reqwest_retry:: policies:: ExponentialBackoff :: builder ( )
172+ . build_with_total_retry_duration_and_max_retries ( Duration :: from_secs ( 15 ) ) ;
173+
174+ let client = reqwest_middleware:: ClientBuilder :: new ( reqwest:: Client :: new ( ) )
175+ . with ( reqwest_retry:: RetryTransientMiddleware :: new_with_policy (
176+ retry_policy,
177+ ) )
178+ . build ( ) ;
179+
180+ Self ( client)
144181 }
145182
146183 async fn resolve ( & self , asset : & Asset ) -> Result < Option < String > > {
@@ -151,10 +188,9 @@ impl ChecksumFetcher {
151188 . send ( )
152189 . await ?;
153190
154- match response. status ( ) . is_client_error ( ) {
155- // No SHA256 found
156- true => Ok ( None ) ,
157- false => {
191+ match response. status ( ) {
192+ StatusCode :: NOT_FOUND => Ok ( None ) ,
193+ _ => {
158194 let content = response. text ( ) . await ?;
159195 self . parse_response ( asset. name . as_str ( ) , content. as_str ( ) )
160196 . map ( Some )
0 commit comments