Skip to content

Commit

Permalink
update afragen/translations-updater with error caching/logging (#199)
Browse files Browse the repository at this point in the history
* update afragen/translations-updater with error caching/logging

* fix return of false due to validation failure

* return WP_Error instead of false

* better error handling

* updates to afragen/translations-updater

* composer update

* update error log messaging

* update library
  • Loading branch information
afragen authored Nov 23, 2024
1 parent e91fe5d commit 974b8fe
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 20 deletions.
10 changes: 5 additions & 5 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions vendor/afragen/translations-updater/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
#### [unreleased]

#### 1.2.0 / 2024-11-19
* return `WP_Error` in `Language_Pack_API::get_language_pack()` with validation error
* exit gracefully if `Language_Pack_API::get_language_pack()` returns `WP_Error`
* updated error logging for GitHub API rate limits

#### 1.1.0 / 2024-11-16
* add API error caching/logging
* always return `$this->repo` in `Language_Pack_API::get_language_pack()`

#### 1.0.1 / 2024-11-12
* fixed a hard-coded 'master' branch in `Language_Pack_API::process_language_pack_package()`

Expand Down
6 changes: 3 additions & 3 deletions vendor/afragen/translations-updater/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@

This framework allows for decoupled language pack updates for your WordPress plugins or themes that are hosted on public repositories in GitHub, Bitbucket, GitLab, or Gitea.

The URI should point to a repository that contains the translations files. Refer to [GitHub Updater Translations](https://github.com/afragen/github-updater-translations) as an example. It is created using the [Language Pack Maker](https://github.com/afragen/language-pack-maker). The repo **must** be a public repo.
The URI should point to a repository that contains the translations files. Refer to [Git Updater Translations](https://github.com/afragen/git-updater-translations) as an example. It is created using the [Language Pack Maker](https://github.com/afragen/language-pack-maker). The repo **must** be a public repo.

## Usage

Install via Composer: `composer require afragen/translations-updater:dev-master`
Install via Composer: `composer require afragen/translations-updater:^1`

**Prior to release use the following command**
`composer require afragen/translations-updater:dev-<branch>` currently `dev-master`
Expand All @@ -34,7 +34,7 @@ add_action( 'admin_init', function() {
'slug' => 'my-repo-slug', // Should be lowercase.
'version' => 'my-repo-version', // Current version of plugin|theme.
'languages' => 'https://my-path-to/language-packs',
'branch' => 'master', // Default.
'branch' => 'master', // Default (optional).
];

( new \Fragen\Translations_Updater\Init() )->run( $config );
Expand Down
2 changes: 1 addition & 1 deletion vendor/afragen/translations-updater/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "This framework provides automatic decoupled languate pack updates from a public repository for your WordPress plugin or theme.",
"type": "library",
"license": "MIT",
"version": "1.0.1",
"version": "1.2.0",
"keywords": [
"wordpress",
"plugin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ trait API {
*/
protected $response = [];

/**
* Holds HTTP error code from API call.
*
* @var array ( $this->repo->slug => $code )
*/
protected static $error_code = [];

/**
* Return repo data for API calls.
*
Expand Down Expand Up @@ -82,10 +89,59 @@ final protected function return_repo_type() {
* @return boolean|\stdClass
*/
final protected function api( $url ) {
$response = wp_remote_get( $this->get_api_url( $url ) );
$url = $this->get_api_url( $url );
$args = [];

// Use cached API failure data to avoid hammering the API.
$response = $this->get_repo_cache( md5( $url ) );
$cached = isset( $response['error_cache'] );
$response = $response ? $response['error_cache'] : $response;
$response = empty( $response )
? wp_remote_get( $url, $args )
: $response;

$code = (int) wp_remote_retrieve_response_code( $response );
$allowed_codes = [ 200 ];

if ( is_wp_error( $response ) ) {
return false;
// phpcs:ignore WordPress.PHP.DevelopmentFunctions
error_log( var_export( $response, true ) );

return $response;
}

// Cache HTTP API error code for 60 minutes.
if ( ! in_array( $code, $allowed_codes, true ) && ! $cached ) {
$timeout = 60;

// Set timeout to GitHub rate limit reset.
$timeout = static::ratelimit_reset( $response, $this->repo->slug );
$response['timeout'] = $timeout;
$this->set_repo_cache( 'error_cache', $response, md5( $url ), "+{$timeout} minutes" );
}

static::$error_code[ $this->repo->slug ] = static::$error_code[ $this->repo->slug ] ?? [];
static::$error_code[ $this->repo->slug ] = array_merge(
static::$error_code[ $this->repo->slug ],
[
'repo' => $this->repo->slug,
'code' => $code,
'name' => $this->repo->name ?? $this->repo->slug,
'git' => $this->repo->git,
]
);
if ( isset( $response['timeout'] ) ) {
static::$error_code[ $this->repo->slug ]['wait'] = static::ratelimit_reset( $response, $this->repo->slug );
}

if ( isset( $response['timeout'] ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$response_body = json_decode( wp_remote_retrieve_body( $response ) );
if ( null !== $response_body && property_exists( $response_body, 'message' ) ) {
$log_message = "Translations Updater Error: {$this->repo->slug} - {$response_body->message}"
. "\nTime remaining for rate limiting: {$this->ratelimit_reset($response, $this->repo->slug)} minutes";
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( $log_message );
}
}

return json_decode( wp_remote_retrieve_body( $response ) );
Expand Down Expand Up @@ -137,7 +193,7 @@ final protected function validate_response( $response ) {
*/
final protected function get_repo_cache( $repo = false ) {
if ( ! $repo ) {
$repo = isset( $this->type->slug ) ? $this->type->slug : 'tu';
$repo = isset( $this->repo->slug ) ? $this->repo->slug : 'tu';
}
$cache_key = 'tu-' . md5( $repo );
$cache = get_site_option( $cache_key );
Expand All @@ -158,12 +214,12 @@ final protected function get_repo_cache( $repo = false ) {
*
* @return bool
*/
final protected function set_repo_cache( $id, $response, $repo = false ) {
final protected function set_repo_cache( $id, $response, $repo = false, $timeout = false ) {
if ( ! $repo ) {
$repo = isset( $this->type->slug ) ? $this->type->slug : 'tu';
$repo = isset( $this->repo->slug ) ? $this->repo->slug : 'tu';
}
$cache_key = 'tu-' . md5( $repo );
$timeout = '+' . self::$hours . ' hours';
$timeout = $timeout ? $timeout : '+' . static::$hours . ' hours';

$this->response['timeout'] = strtotime( $timeout );
$this->response[ $id ] = $response;
Expand All @@ -172,4 +228,27 @@ final protected function set_repo_cache( $id, $response, $repo = false ) {

return true;
}

/**
* Calculate and store time until rate limit reset.
*
* @param array $response HTTP headers.
* @param string $repo Repo name.
*
* @return void|int
*/
final public static function ratelimit_reset( $response, $repo ) {
$headers = wp_remote_retrieve_headers( $response );
$data = $headers->getAll();
$wait = 0;
if ( isset( $data['x-ratelimit-reset'] ) ) {
$reset = (int) $data['x-ratelimit-reset'];
//phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
$wait = date( 'i', $reset - time() );
static::$error_code[ $repo ] = static::$error_code[ $repo ] ?? [];
static::$error_code[ $repo ] = array_merge( static::$error_code[ $repo ], [ 'wait' => $wait ] );

return $wait;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ public function __construct( $config, Language_Pack_API $api ) {
* Do the Language Pack integration.
*/
public function run() {
$headers = $this->parse_header_uri( $this->repo->languages );
$repo = $this->repo_api->get_language_pack( $headers );
$headers = $this->parse_header_uri( $this->repo->languages );
$repo = $this->repo_api->get_language_pack( $headers );
if ( is_wp_error( $repo ) ) {
return;
}
$this->config[ $repo->slug ] = $repo;

add_filter( 'site_transient_update_plugins', [ $this, 'update_site_transient' ] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function __construct( $config ) {
*
* @param array $headers Array of headers of Language Pack.
*
* @return bool When invalid response.
* @return \stdClass|\WP_Error
*/
public function get_language_pack( $headers ) {
$response = ! empty( $this->response['languages'] ) ? $this->response['languages'] : false;
Expand All @@ -65,7 +65,11 @@ public function get_language_pack( $headers ) {
}
$this->set_repo_cache( 'languages', $response, $this->repo->slug );
} else {
return false;
return new \WP_Error(
'language_pack_validation_error',
'API timeout error',
[ self::$error_code ]
);
}
}
$this->repo->language_packs = $response;
Expand Down Expand Up @@ -124,7 +128,7 @@ private function get_language_pack_json( $git, $headers ) {
* @param \stdClass $locale Site locale.
* @param array $headers Repository headers.
*
* @return array|null|string
* @return string
*/
private function process_language_pack_package( $git, $locale, $headers ) {
$package = null;
Expand Down

0 comments on commit 974b8fe

Please sign in to comment.