Fetch assets in parallel

dev
gravel 1 year ago
parent 0f5d03d23c
commit d0c6186fb4
Signed by: gravel
GPG Key ID: C0538F3C906B308F

@ -272,7 +272,7 @@
* Launches all coroutines in parallel. * Launches all coroutines in parallel.
* @return int CURLM_* status. * @return int CURLM_* status.
*/ */
public function fetch_all(): int { public function run_all(): int {
do { do {
$curlm_status = curl_multi_exec($this->transfers, $curlm_active_transfer); $curlm_status = curl_multi_exec($this->transfers, $curlm_active_transfer);
if ($curlm_active_transfer) { if ($curlm_active_transfer) {

@ -31,22 +31,15 @@
} }
/** /**
* Fetch the icon of the given room and return its relative path. * @return \Generator<int,CurlHandle,CurlHandle|false,void>
* @param \CommunityRoom $room
* @param string $size Image dimensions.
* @return string Relative path or null if icon is absent.
*/ */
function room_icon(\CommunityRoom $room, string $size): ?string { function fetch_room_icon_coroutine(\CommunityRoom $room): Generator {
list($width, $height) = explode("x", $size);
$width = intval($width);
$height = intval($height);
assert(!empty($width) && !empty($height));
if (room_icon_safety($room) < 0) { if (room_icon_safety($room) < 0) {
return null; return;
} }
$room_id = $room->get_room_identifier(); $room_id = $room->get_room_identifier();
$icon_cached = room_icon_path($room_id); $icon_cached = room_icon_path($room_id);
$icon_resized = room_icon_path_resized($room_id, $size);
$icon_expired = file_exists($icon_cached) && filemtime($icon_cached) < strtotime("-1 day"); $icon_expired = file_exists($icon_cached) && filemtime($icon_cached) < strtotime("-1 day");
// Re-fetch icons periodically. // Re-fetch icons periodically.
@ -56,7 +49,8 @@
return null; return null;
} }
log_debug("Fetching icon for $room_id."); log_debug("Fetching icon for $room_id.");
$icon = file_get_contents($icon_url); $icon_response = yield from FetchingCoroutine::from_url($icon_url)->run();
$icon = $icon_response ? curl_multi_getcontent($icon_response) : null;
if (empty($icon)) { if (empty($icon)) {
log_info("$room_id returned an empty icon."); log_info("$room_id returned an empty icon.");
} }
@ -65,6 +59,33 @@
file_put_contents($icon_cached, $icon); file_put_contents($icon_cached, $icon);
} }
} }
}
/**
* Fetch the icon of the given room and return its relative path.
* @param \CommunityRoom $room
* @param string $size Image dimensions.
* @return string Relative path or null if icon is absent.
*/
function room_icon(\CommunityRoom $room, string $size): ?string {
list($width, $height) = explode("x", $size);
$width = intval($width);
$height = intval($height);
assert(!empty($width) && !empty($height));
if (room_icon_safety($room) < 0) {
return null;
}
$room_id = $room->get_room_identifier();
$icon_cached = room_icon_path($room_id);
$icon_resized = room_icon_path_resized($room_id, $size);
$icon_expired = file_exists($icon_cached) && filemtime($icon_cached) < strtotime("-1 day");
if (!file_exists($icon_cached)) {
log_debug("Missing icon asset for $room_id");
return "";
}
if (!file_exists($icon_resized) || $icon_expired) { if (!file_exists($icon_resized) || $icon_expired) {
$icon_cached_contents = file_get_contents($icon_cached); $icon_cached_contents = file_get_contents($icon_cached);
if (empty($icon_cached_contents)) { if (empty($icon_cached_contents)) {

@ -19,11 +19,9 @@
/** /**
* Fetch QR invite of the given room and return its relative path. * @return \Generator<int,CurlHandle,CurlHandle|false,void>
* @param \CommunityRoom $room
* @return string
*/ */
function room_qr_code($room): string { function fetch_qr_code_coroutine(\CommunityRoom $room): Generator {
$room_id = $room->get_room_identifier(); $room_id = $room->get_room_identifier();
$png_cached = room_qr_code_path($room_id); $png_cached = room_qr_code_path($room_id);
$image_expired = file_exists($png_cached) && $image_expired = file_exists($png_cached) &&
@ -32,7 +30,8 @@
return room_qr_code_path_relative($room_id); return room_qr_code_path_relative($room_id);
} }
log_debug("Fetching QR code for $room_id."); log_debug("Fetching QR code for $room_id.");
$png = file_get_contents($room->get_invite_url()); $png_response = yield from FetchingCoroutine::from_url($room->get_invite_url())->run();
$png = $png_response ? curl_multi_getcontent($png_response) : null;
if (empty($png)) { if (empty($png)) {
log_warning("$room_id returned an empty QR code."); log_warning("$room_id returned an empty QR code.");
} }
@ -40,6 +39,19 @@
if (!(file_exists($png_cached) && filesize($png_cached) > 0 && empty($png))) { if (!(file_exists($png_cached) && filesize($png_cached) > 0 && empty($png))) {
file_put_contents($png_cached, $png); file_put_contents($png_cached, $png);
} }
}
/**
* Fetch QR invite of the given room and return its relative path.
* @param \CommunityRoom $room
* @return string
*/
function room_qr_code(\CommunityRoom $room): string {
$room_id = $room->get_room_identifier();
if (!file_exists(room_qr_code_path($room_id))) {
log_warning("Missing QR code asset for $room_id.");
return "";
}
return room_qr_code_path_relative($room_id); return room_qr_code_path_relative($room_id);
} }

@ -1,9 +1,11 @@
<?php <?php
include_once "$PROJECT_ROOT/languages/language_flags.php"; require_once "$PROJECT_ROOT/languages/language_flags.php";
include_once "$PROJECT_ROOT/php/servers/known-servers.php"; require_once "$PROJECT_ROOT/php/servers/known-servers.php";
include_once 'tags.php'; require_once 'tags.php';
include_once 'fetching-coroutines.php'; require_once 'fetching-coroutines.php';
require_once 'room-icons.php';
require_once 'room-invites.php';
$MINUTE_SECONDS = 60; $MINUTE_SECONDS = 60;
$HOUR_SECONDS = 60 * $MINUTE_SECONDS; $HOUR_SECONDS = 60 * $MINUTE_SECONDS;
@ -735,7 +737,7 @@
$runner = new FetchingCoroutineRunner($coroutines); $runner = new FetchingCoroutineRunner($coroutines);
$runner->fetch_all(); $runner->run_all();
return $reachable_servers; return $reachable_servers;
} }
@ -918,8 +920,9 @@
foreach ($this->room_hints as $token) { foreach ($this->room_hints as $token) {
log_debug("Testing room /$token at $base_url."); log_debug("Testing room /$token at $base_url.");
// FIXME: This fetches room hints sequentially per each server // Note: This fetches room hints sequentially per each server
// Would need to allow yielding handle arrays // Would need to allow yielding handle arrays
// More than good enough for now
$room_api_response = yield from FetchingCoroutine $room_api_response = yield from FetchingCoroutine
::from_url($this->get_room_api_url($token)) ::from_url($this->get_room_api_url($token))
@ -1082,6 +1085,23 @@
return true; return true;
} }
/**
* @param \CommunityServer $servers
*/
public static function fetch_assets(array $servers) {
// Sequential in each server, see note in fetch_room_hints_coroutine()
$coroutines = [];
foreach (CommunityServer::enumerate_rooms($servers) as $room) {
$coroutines[] = new FetchingCoroutine((function() use ($room) {
yield from fetch_qr_code_coroutine($room);
yield from fetch_room_icon_coroutine($room);
})());
}
(new FetchingCoroutineRunner($coroutines))->run_all();
}
/** /**
* Checks whether this server belongs to Session / OPTF. * Checks whether this server belongs to Session / OPTF.
*/ */

@ -1,5 +1,5 @@
<?php <?php
include "$PROJECT_ROOT/php/utils/room-icons.php"; include_once "$PROJECT_ROOT/php/utils/room-icons.php";
/** /**
* @var \CommunityRoom[] $rooms * @var \CommunityRoom[] $rooms

@ -13,6 +13,9 @@
// Re-build server instances from cached server data. // Re-build server instances from cached server data.
$servers = CommunityServer::from_details_array($server_data); $servers = CommunityServer::from_details_array($server_data);
// Fetch all server assets ahead of time.
CommunityServer::fetch_assets($servers);
// List all rooms from the cached servers. // List all rooms from the cached servers.
$rooms = CommunityServer::enumerate_rooms($servers); $rooms = CommunityServer::enumerate_rooms($servers);

Loading…
Cancel
Save