mirror of
https://github.com/standardebooks/web.git
synced 2025-07-07 15:20:32 -04:00
Rebuild web caches immediately on ebook updates
This commit is contained in:
parent
60a58e9a95
commit
e857e4e9e6
9 changed files with 115 additions and 70 deletions
|
@ -281,13 +281,13 @@ Define webroot /standardebooks.org/web
|
|||
RewriteCond %{QUERY_STRING} \bquery=
|
||||
RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
||||
|
||||
RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&name=$2
|
||||
RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&class=$2
|
||||
|
||||
RewriteRule ^/feeds/(.+\.xml)$ /feeds/download.php?path=$1
|
||||
|
||||
# Rewrite rules for bulk downloads
|
||||
RewriteRule ^/bulk-downloads/(.+\.zip)$ /bulk-downloads/download.php?path=$1
|
||||
RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?name=$1
|
||||
RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?class=$1
|
||||
|
||||
# Specific config for /bulk-downloads
|
||||
<DirectoryMatch "${webroot}/www/bulk-downloads">
|
||||
|
|
|
@ -263,13 +263,13 @@ Define webroot /standardebooks.org/web
|
|||
RewriteCond %{QUERY_STRING} \bquery=
|
||||
RewriteRule ^/feeds/(opds|atom|rss)/all.xml$ /feeds/$1/search.php [QSA]
|
||||
|
||||
RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&name=$2
|
||||
RewriteRule ^/feeds/(atom|rss)/([^/\.]+)$ /feeds/collection.php?type=$1&class=$2
|
||||
|
||||
RewriteRule ^/feeds/(.+\.xml)$ /feeds/download.php?path=$1
|
||||
|
||||
# Rewrite rules for bulk downloads
|
||||
RewriteRule ^/bulk-downloads/(.+\.zip)$ /bulk-downloads/download.php?path=$1
|
||||
RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?name=$1
|
||||
RewriteRule ^/bulk-downloads/([^/\.]+)$ /bulk-downloads/collection.php?class=$1
|
||||
|
||||
# Specific config for /bulk-downloads
|
||||
<DirectoryMatch "${webroot}/www/bulk-downloads">
|
||||
|
|
|
@ -380,6 +380,54 @@ class Library{
|
|||
return ['months' => $months, 'subjects' => $subjects, 'collections' => $collections, 'authors' => $authors];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<int|string, array<int|string, mixed>>>
|
||||
*/
|
||||
public static function RebuildFeedsCache(?string $returnType = null, ?string $returnClass = null): ?array{
|
||||
$feedTypes = ['opds', 'atom', 'rss'];
|
||||
$feedClasses = ['authors', 'collections', 'subjects'];
|
||||
$retval = null;
|
||||
$collator = Collator::create('en_US'); // Used for sorting letters with diacritics like in author names
|
||||
if($collator === null){
|
||||
throw new Exceptions\SeException('Couldn\'t create collator object when rebuilding feeds cache.');
|
||||
}
|
||||
|
||||
foreach($feedTypes as $type){
|
||||
foreach($feedClasses as $class){
|
||||
$files = glob(WEB_ROOT . '/feeds/' . $type . '/' . $class . '/*.xml');
|
||||
|
||||
$feeds = [];
|
||||
|
||||
foreach($files as $file){
|
||||
$obj = new stdClass();
|
||||
$obj->Url = '/feeds/' . $type . '/' . $class . '/' . basename($file, '.xml');
|
||||
|
||||
$obj->Label = exec('attr -g se-label ' . escapeshellarg($file)) ?: null;
|
||||
if($obj->Label == null){
|
||||
$obj->Label = basename($file, '.xml');
|
||||
}
|
||||
|
||||
$obj->LabelSort = exec('attr -g se-label-sort ' . escapeshellarg($file)) ?: null;
|
||||
if($obj->LabelSort == null){
|
||||
$obj->LabelSort = basename($file, '.xml');
|
||||
}
|
||||
|
||||
$feeds[] = $obj;
|
||||
}
|
||||
|
||||
usort($feeds, function($a, $b) use($collator){ return $collator->compare($a->LabelSort, $b->LabelSort); });
|
||||
|
||||
if($type == $returnType && $class == $returnClass){
|
||||
$retval = $feeds;
|
||||
}
|
||||
|
||||
apcu_store('feeds-index-' . $type . '-' . $class, $feeds);
|
||||
}
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
public static function RebuildCache(): void{
|
||||
// We check a lockfile because this can be a long-running command.
|
||||
// We don't want to queue up a bunch of these in case someone is refreshing the index constantly.
|
||||
|
|
|
@ -67,7 +67,7 @@ class Session extends PropertiesBase{
|
|||
return null;
|
||||
}
|
||||
|
||||
public static function SetSessionCookie($sessionId): void{
|
||||
public static function SetSessionCookie(string $sessionId): void{
|
||||
setcookie('sessionid', $sessionId, time() + 60 * 60 * 24 * 14 * 1, '/', SITE_DOMAIN, true, false); // Expires in two weeks
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,10 @@ if ! [ -f "${scriptsDir}"/generate-feeds ]; then
|
|||
die "\"${scriptsDir}\"/generate-feeds\" is not a file or could not be found."
|
||||
fi
|
||||
|
||||
if ! [ -f "${scriptsDir}"/generate-bulk-downloads ]; then
|
||||
die "\"${scriptsDir}\"/generate-bulk-downloads\" is not a file or could not be found."
|
||||
fi
|
||||
|
||||
mkdir -p "${webRoot}"/images/covers/
|
||||
|
||||
for dir in "$@"
|
||||
|
@ -391,7 +395,7 @@ if [ "${queuedTasks}" = "false" ]; then
|
|||
printf "Rebuilding web library cache ... "
|
||||
fi
|
||||
|
||||
"${scriptsDir}"/rebuild-library-cache
|
||||
"${scriptsDir}"/rebuild-cache library
|
||||
|
||||
if [ "${verbose}" = "true" ]; then
|
||||
printf "Done.\n"
|
||||
|
@ -410,6 +414,7 @@ if [ "${feeds}" = "true" ]; then
|
|||
fi
|
||||
|
||||
"${scriptsDir}/generate-feeds" --webroot "${webRoot}" --weburl "${webUrl}"
|
||||
"${scriptsDir}"/rebuild-cache feeds
|
||||
|
||||
if [ "${verbose}" = "true" ]; then
|
||||
printf "Done.\n"
|
||||
|
@ -429,6 +434,7 @@ if [ "${bulkDownloads}" = "true" ]; then
|
|||
fi
|
||||
|
||||
"${scriptsDir}/generate-bulk-downloads" --webroot "${webRoot}"
|
||||
"${scriptsDir}"/rebuild-cache bulk-downloads
|
||||
|
||||
if [ "${verbose}" = "true" ]; then
|
||||
printf "Done.\n"
|
||||
|
|
43
scripts/rebuild-cache
Executable file
43
scripts/rebuild-cache
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
|
||||
usage(){
|
||||
echo -n
|
||||
fmt <<EOF
|
||||
DESCRIPTION
|
||||
Rebuild one of three caches stored in APCu for the standardebooks.org FPM pool.
|
||||
|
||||
USAGE
|
||||
rebuild-cache {library,bulk-downloads,feeds}
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
usage
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
# If this script is run by a user without sudo powers, they can be given permission to run this command by creating a file in sudoers.d with:
|
||||
# MY_USERNAME ALL=(www-data) NOPASSWD: /usr/bin/env SCRIPT_FILENAME=/tmp/rebuild-cache.php REQUEST_METHOD=GET cgi-fcgi -bind -connect *
|
||||
|
||||
type="$1"
|
||||
|
||||
if [ "${type}" = "library" ]; then
|
||||
echo "<?php require_once('Core.php'); Library::RebuildCache(); ?>" > /tmp/rebuild-cache.php
|
||||
fi
|
||||
|
||||
if [ "${type}" = "bulk-downloads" ]; then
|
||||
echo "<?php require_once('Core.php'); Library::RebuildBulkDownloadsCache(); ?>" > /tmp/rebuild-cache.php
|
||||
fi
|
||||
|
||||
if [ "${type}" = "feeds" ]; then
|
||||
echo "<?php require_once('Core.php'); Library::RebuildFeedsCache(); ?>" > /tmp/rebuild-cache.php
|
||||
fi
|
||||
|
||||
sudo -u www-data env SCRIPT_FILENAME=/tmp/rebuild-cache.php REQUEST_METHOD=GET cgi-fcgi -bind -connect "/run/php/standardebooks.org.sock" &> /dev/null
|
||||
rm /tmp/rebuild-cache.php
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
usage(){
|
||||
echo -n
|
||||
fmt <<EOF
|
||||
DESCRIPTION
|
||||
Rebuild the library cache stored in APCu for the standardebooks.org FPM pool.
|
||||
|
||||
USAGE
|
||||
rebuild-library-cache
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
usage
|
||||
fi
|
||||
fi
|
||||
|
||||
# If this script is run by a user without sudo powers, they can be given for this command by creating a file in sudoers.d with:
|
||||
# MY_USERNAME ALL=(www-data) NOPASSWD: /usr/bin/env SCRIPT_FILENAME=/tmp/rebuild-library-cache.php REQUEST_METHOD=GET cgi-fcgi -bind -connect *
|
||||
|
||||
echo "<?php require_once('Core.php'); Library::RebuildCache(); ?>" > /tmp/rebuild-library-cache.php
|
||||
sudo -u www-data env SCRIPT_FILENAME=/tmp/rebuild-library-cache.php REQUEST_METHOD=GET cgi-fcgi -bind -connect "/run/php/standardebooks.org.sock" &> /dev/null
|
||||
rm /tmp/rebuild-library-cache.php
|
|
@ -5,9 +5,9 @@ use function Safe\apcu_fetch;
|
|||
use function Safe\preg_replace;
|
||||
|
||||
$canDownload = false;
|
||||
$name = HttpInput::Str(GET, 'name', false) ?? '';
|
||||
$class = HttpInput::Str(GET, 'class', false) ?? '';
|
||||
|
||||
if($name != 'authors' && $name != 'collections' && $name != 'subjects' && $name != 'months'){
|
||||
if($class != 'authors' && $class != 'collections' && $class != 'subjects' && $class != 'months'){
|
||||
Template::Emit404();
|
||||
}
|
||||
|
||||
|
@ -18,14 +18,14 @@ if($GLOBALS['User'] !== null && $GLOBALS['User']->Benefits->CanBulkDownload){
|
|||
$collection = [];
|
||||
|
||||
try{
|
||||
$collection = apcu_fetch('bulk-downloads-' . $name);
|
||||
$collection = apcu_fetch('bulk-downloads-' . $class);
|
||||
}
|
||||
catch(Safe\Exceptions\ApcuException $ex){
|
||||
$result = Library::RebuildBulkDownloadsCache();
|
||||
$collection = $result[$name];
|
||||
$collection = $result[$class];
|
||||
}
|
||||
|
||||
$title = preg_replace('/s$/', '', ucfirst($name));
|
||||
$title = preg_replace('/s$/', '', ucfirst($class));
|
||||
|
||||
?><?= Template::Header(['title' => 'Downloads by ' . $title, 'highlight' => '', 'description' => 'Download zip files containing all of the Standard Ebooks in a given collection.']) ?>
|
||||
<main>
|
||||
|
@ -34,8 +34,8 @@ $title = preg_replace('/s$/', '', ucfirst($name));
|
|||
<? if(!$canDownload){ ?>
|
||||
<p><a href="/about#patrons-circle">Patrons circle members</a> get convenient access to zip files containing collections of different categories of ebooks. You can <a href="/donate#patrons-circle">join the Patrons Circle</a> with a small donation in support of our continuing mission to create free, beautiful digital literature, and download these collections files too.</p>
|
||||
<? } ?>
|
||||
<p>These zip files contain each ebook in every format we offer, and are updated once daily with the latest versions of each ebook. Read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which file format to download</a>.</p>
|
||||
<? if($name == 'months'){ ?>
|
||||
<p>These zip files contain each ebook in every format we offer, and are kept updated with the latest versions of each ebook. Read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which file format to download</a>.</p>
|
||||
<? if($class == 'months'){ ?>
|
||||
<table class="download-list">
|
||||
<caption aria-hidden="hidden">Scroll right →</caption>
|
||||
<tbody>
|
||||
|
|
|
@ -6,10 +6,10 @@ use function Safe\glob;
|
|||
use function Safe\preg_replace;
|
||||
use function Safe\usort;
|
||||
|
||||
$name = HttpInput::Str(GET, 'name', false) ?? '';
|
||||
$class = HttpInput::Str(GET, 'class', false) ?? '';
|
||||
$type = HttpInput::Str(GET, 'type', false) ?? '';
|
||||
|
||||
if($name != 'authors' && $name != 'collections' && $name != 'subjects'){
|
||||
if($class != 'authors' && $class != 'collections' && $class != 'subjects'){
|
||||
Template::Emit404();
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ if($type != 'rss' && $type != 'atom'){
|
|||
|
||||
$feeds = [];
|
||||
|
||||
$lcTitle = preg_replace('/s$/', '', $name);
|
||||
$lcTitle = preg_replace('/s$/', '', $class);
|
||||
$ucTitle = ucfirst($lcTitle);
|
||||
$ucType = 'RSS 2.0';
|
||||
if($type === 'atom'){
|
||||
|
@ -27,36 +27,10 @@ if($type === 'atom'){
|
|||
}
|
||||
|
||||
try{
|
||||
$feeds = apcu_fetch('feeds-index-' . $type . '-' . $name);
|
||||
$feeds = apcu_fetch('feeds-index-' . $type . '-' . $class);
|
||||
}
|
||||
catch(Safe\Exceptions\ApcuException $ex){
|
||||
$files = glob(WEB_ROOT . '/feeds/' . $type . '/' . $name . '/*.xml');
|
||||
|
||||
$feeds = [];
|
||||
|
||||
foreach($files as $file){
|
||||
$obj = new stdClass();
|
||||
$obj->Url = '/feeds/' . $type . '/' . $name . '/' . basename($file, '.xml');
|
||||
|
||||
$obj->Label = exec('attr -g se-label ' . escapeshellarg($file)) ?: null;
|
||||
if($obj->Label == null){
|
||||
$obj->Label = basename($file, '.xml');
|
||||
}
|
||||
|
||||
$obj->LabelSort = exec('attr -g se-label-sort ' . escapeshellarg($file)) ?: null;
|
||||
if($obj->LabelSort == null){
|
||||
$obj->LabelSort = basename($file, '.xml');
|
||||
}
|
||||
|
||||
$feeds[] = $obj;
|
||||
}
|
||||
|
||||
$collator = Collator::create('en_US'); // Used for sorting letters with diacritics like in author names
|
||||
if($collator !== null){
|
||||
usort($feeds, function($a, $b) use($collator){ return $collator->compare($a->LabelSort, $b->LabelSort); });
|
||||
}
|
||||
|
||||
apcu_store('feeds-index-' . $type . '-' . $name, $feeds, 43200); // 12 hours
|
||||
$feeds = Library::RebuildFeedsCache($type, $class);
|
||||
}
|
||||
?><?= Template::Header(['title' => $ucType . ' Ebook Feeds by ' . $ucTitle, 'description' => 'A list of available ' . $ucType . ' feeds of Standard Ebooks ebooks by ' . $lcTitle . '.']) ?>
|
||||
<main>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue