99
1010use const FAIR \CACHE_BASE ;
1111use const FAIR \CACHE_LIFETIME ;
12+ use const FAIR \CACHE_LIFETIME_FAILURE ;
1213use FAIR \Packages \DID \Document as DIDDocument ;
1314use FAIR \Packages \DID \PLC ;
1415use FAIR \Packages \DID \Web ;
2223const CACHE_KEY = CACHE_BASE . 'packages- ' ;
2324const CACHE_METADATA_DOCUMENTS = CACHE_BASE . 'metadata-documents- ' ;
2425const CACHE_RELEASE_PACKAGES = CACHE_BASE . 'release-packages ' ;
26+ const CACHE_UPDATE_ERRORS = CACHE_BASE . 'update-errors- ' ;
2527const CACHE_DID_FOR_INSTALL = 'fair-install-did ' ;
2628const CONTENT_TYPE = 'application/json+fair ' ;
2729const SERVICE_ID = 'FairPackageManagementRepo ' ;
2830
2931// phpcs:disable WordPress.NamingConventions.ValidVariableName
3032
33+ /**
34+ * Cache an update error for a package.
35+ *
36+ * @param string $did DID of the package.
37+ * @param WP_Error $error The error to cache.
38+ */
39+ function cache_update_error ( string $ did , WP_Error $ error ): void {
40+ $ error ->add_data ( [ 'timestamp ' => time () ], $ error ->get_error_code () );
41+ set_site_transient ( CACHE_UPDATE_ERRORS . $ did , $ error , CACHE_LIFETIME_FAILURE );
42+ }
43+
44+ /**
45+ * Clear a cached update error for a package.
46+ *
47+ * @param string $did DID of the package.
48+ */
49+ function clear_update_error ( string $ did ): void {
50+ delete_site_transient ( CACHE_UPDATE_ERRORS . $ did );
51+ }
52+
3153/**
3254 * Bootstrap.
3355 *
@@ -93,6 +115,12 @@ function get_did_hash( string $id ) {
93115 * @return DIDDocument|WP_Error
94116 */
95117function get_did_document ( string $ id ) {
118+ // Check for cached error from previous failed request.
119+ $ cached_error = get_site_transient ( CACHE_UPDATE_ERRORS . $ id );
120+ if ( is_wp_error ( $ cached_error ) ) {
121+ return $ cached_error ;
122+ }
123+
96124 $ cached = get_site_transient ( CACHE_METADATA_DOCUMENTS . $ id );
97125 if ( $ cached ) {
98126 return $ cached ;
@@ -101,13 +129,18 @@ function get_did_document( string $id ) {
101129 // Parse the DID, then fetch the details.
102130 $ did = parse_did ( $ id );
103131 if ( is_wp_error ( $ did ) ) {
132+ cache_update_error ( $ id , $ did );
104133 return $ did ;
105134 }
106135
107136 $ document = $ did ->fetch_document ();
108137 if ( is_wp_error ( $ document ) ) {
138+ cache_update_error ( $ id , $ document );
109139 return $ document ;
110140 }
141+
142+ // Clear any previous error on success.
143+ clear_update_error ( $ id );
111144 set_site_transient ( CACHE_METADATA_DOCUMENTS . $ id , $ document , CACHE_LIFETIME );
112145
113146 return $ document ;
@@ -177,30 +210,38 @@ function fetch_package_metadata( string $id ) {
177210 // Fetch data from the repository.
178211 $ service = $ document ->get_service ( SERVICE_ID );
179212 if ( empty ( $ service ) ) {
180- return new WP_Error ( 'fair.packages.fetch_metadata.no_service ' , __ ( 'DID is not a valid package to fetch metadata for. ' , 'fair ' ) );
213+ $ error = new WP_Error ( 'fair.packages.fetch_metadata.no_service ' , __ ( 'DID is not a valid package to fetch metadata for. ' , 'fair ' ) );
214+ cache_update_error ( $ id , $ error );
215+ return $ error ;
181216 }
182217 $ repo_url = $ service ->serviceEndpoint ;
183218
184- $ metadata = fetch_metadata_doc ( $ repo_url );
219+ $ metadata = fetch_metadata_doc ( $ repo_url, $ id );
185220
186221 if ( is_wp_error ( $ metadata ) ) {
187222 return $ metadata ;
188223 }
189224
190225 if ( $ metadata ->id !== $ id ) {
191- return new WP_Error ( 'fair.packages.fetch_metadata.mismatch ' , __ ( 'Fetched metadata does not match the requested DID. ' , 'fair ' ) );
226+ $ error = new WP_Error ( 'fair.packages.fetch_metadata.mismatch ' , __ ( 'Fetched metadata does not match the requested DID. ' , 'fair ' ) );
227+ cache_update_error ( $ id , $ error );
228+ return $ error ;
192229 }
193230
231+ // Clear any previous error on success.
232+ clear_update_error ( $ id );
233+
194234 return $ metadata ;
195235}
196236
197237/**
198238 * Fetch the metadata document for a package.
199239 *
200240 * @param string $url URL for the metadata document.
241+ * @param string $did DID of the package.
201242 * @return MetadataDocument|WP_Error
202243 */
203- function fetch_metadata_doc ( string $ url ) {
244+ function fetch_metadata_doc ( string $ url, string $ did ) {
204245 $ cache_key = CACHE_KEY . md5 ( $ url );
205246 $ response = get_site_transient ( $ cache_key );
206247 $ response = fetch_metadata_from_local ( $ response , $ url );
@@ -219,9 +260,15 @@ function fetch_metadata_doc( string $url ) {
219260 $ response = wp_remote_get ( $ url , $ options );
220261 $ code = wp_remote_retrieve_response_code ( $ response );
221262 if ( is_wp_error ( $ response ) ) {
263+ cache_update_error ( $ did , $ response );
222264 return $ response ;
223265 } elseif ( $ code !== 200 ) {
224- return new WP_Error ( 'fair.packages.metadata.failure ' , __ ( 'HTTP error code received ' , 'fair ' ) );
266+ $ error = new WP_Error (
267+ 'fair.packages.metadata.http_error ' ,
268+ sprintf ( __ ( 'HTTP %d error received ' , 'fair ' ), $ code )
269+ );
270+ cache_update_error ( $ did , $ error );
271+ return $ error ;
225272 }
226273
227274 // Reorder sections before caching.
@@ -727,6 +774,9 @@ function cache_did_for_install( array $options ): array {
727774 $ did = array_find_key (
728775 $ releases ,
729776 function ( $ release ) use ( $ options ) {
777+ if ( ! is_array ( $ release ->artifacts ->package ) ) {
778+ return false ;
779+ }
730780 $ artifact = pick_artifact_by_lang ( $ release ->artifacts ->package );
731781 return $ artifact && $ artifact ->url === $ options ['package ' ];
732782 }
@@ -754,7 +804,7 @@ function delete_cached_did_for_install(): void {
754804 *
755805 * This is commonly required for packages from Git hosts.
756806 *
757- * @param string $source Path of $source.
807+ * @param string|WP_Error $source Path of $source, or a WP_Error object .
758808 * @param string $remote_source Path of $remote_source.
759809 * @param WP_Upgrader $upgrader An Upgrader object.
760810 * @param array $hook_extra Array of hook data.
0 commit comments