diff options
| author | Syndamia <kamen@syndamia.com> | 2025-02-02 20:57:31 +0200 |
|---|---|---|
| committer | Syndamia <kamen@syndamia.com> | 2025-02-02 20:57:31 +0200 |
| commit | cea80fb8fafa21f3e8078be720826da2e4642719 (patch) | |
| tree | f0c0d3d52ab5bd54718f9c9984cd13424e8e1586 | |
| parent | e152b791f45b02c20b00e248f1502bc144e8a9a8 (diff) | |
| download | nowayforward_human-cea80fb8fafa21f3e8078be720826da2e4642719.tar nowayforward_human-cea80fb8fafa21f3e8078be720826da2e4642719.tar.gz nowayforward_human-cea80fb8fafa21f3e8078be720826da2e4642719.zip | |
feat: Async and queued page archival
| -rw-r--r-- | controllers/archive.php | 76 | ||||
| -rw-r--r-- | views/admin/index.php | 18 | ||||
| -rw-r--r-- | views/archive/create/index.php | 47 | ||||
| -rw-r--r-- | views/archive/create/status.php | 5 |
4 files changed, 142 insertions, 4 deletions
diff --git a/controllers/archive.php b/controllers/archive.php index 367acc7..4e4ac77 100644 --- a/controllers/archive.php +++ b/controllers/archive.php @@ -3,24 +3,76 @@ namespace Controller; use Database; use DOMDocument; use Exception; +use TypeError; +use ValueError; function on_post() { + if (!array_key_exists('async', $_POST) || $_POST['async'] !== 'true') { + return; + } + + session_start(); + global $TOKEN; $WEBSITE_CATEGORY = 'url'; $DOWNLOADS_FOLDER = getenv('ARCHIVES_DIR'); $website_url = $_POST[$WEBSITE_CATEGORY]; $uid = 1; + $authorized = false; if ($TOKEN !== "") { try { - $uid = Database\Cookie::fromDB($TOKEN)->UID; + $user = Database\Cookie::fromDB($TOKEN); + $uid = $user->UID; + $authorized = $user->Role === 'Admin'; } catch (Exception $e) {} } - $currentPage = new DownloadPage($website_url, $DOWNLOADS_FOLDER, $uid); - header('Location: /archive/?url=' . $website_url); - exit(); + $manual_start = $authorized + && array_key_exists('manual', $_POST) + && $_POST['manual'] === 'true'; + // The first request to archive a page becomes a "worker", which will archive + // the requested page and any other which might be requested in the meantime + $start_worker = !array_key_exists('archive_queue', $_SESSION) + || count($_SESSION['archive_queue']) === 0 + || $manual_start; + + if (!array_key_exists('archive_queue', $_SESSION)) { + $_SESSION['archive_queue'] = array(); + $_SESSION['archive_current'] = 0; + } + else if ($start_worker) { + $_SESSION['archive_current'] = 0; + } + + $current = $_SESSION['archive_current'] + count($_SESSION['archive_queue']); + if (!$manual_start) { + array_push( + $_SESSION['archive_queue'], + new DownloadInfo($website_url, $DOWNLOADS_FOLDER, $uid) + ); + } + + if ($start_worker) { + while (count($_SESSION['archive_queue']) > 0) { + $downloadInfo = $_SESSION['archive_queue'][0]; + session_write_close(); + + try { + $downloadInfo->download(); + } + catch(Exception $e) { } + catch(TypeError $e) { } + catch(ValueError $e) { } + + session_start(); + array_shift($_SESSION['archive_queue']); + $_SESSION['archive_current']++; + } + } + echo $current; + exit; } function on_delete() { @@ -57,6 +109,22 @@ function on_delete() { exit(); } +class DownloadInfo { + public $page_url; + private $folder_location; + private $requester_uid; + + function __construct(string $page_url, string $folder_location, string $requester_uid) { + $this->page_url = $page_url; + $this->folder_location = $folder_location; + $this->requester_uid = $requester_uid; + } + + function download() : DownloadPage { + return new DownloadPage($this->page_url, $this->folder_location, $this->requester_uid); + } +} + class DownloadPage { private $folder_location; private $folder_name; diff --git a/views/admin/index.php b/views/admin/index.php index 750a246..e633d32 100644 --- a/views/admin/index.php +++ b/views/admin/index.php @@ -35,6 +35,24 @@ <input type="submit" value="Delete"> </form> + <h2>Archive queue</h2> + + <button id="manual-start">Start worker manually</button> + <script type="text/javascript"> + document.getElementById('manual-start').onclick = function() { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState < 4) return; + + console.log(request.responseText); + } + request.open("POST", "/archive/create", true); + request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + request.withCredentials = true; + request.send('async=true&url=localhost&manual=true'); + } + </script> + <?php else: ?> <h2>Permission denied, you're not an admin!</h2> diff --git a/views/archive/create/index.php b/views/archive/create/index.php index 378d2de..b435e4d 100644 --- a/views/archive/create/index.php +++ b/views/archive/create/index.php @@ -1 +1,48 @@ <h2>Archiving <?= $url ?>...</h2> + +<p>Current position in queue: <span id="position">unavailable</span></p> + +<script type="text/javascript"> +// If our request is the one that starts the worker, it's output will be 0 +// and it won't update the variable soon (or ever) +// But if it's not the worker, the variable will be updated (quickly) +var queuePos = 0; + +function requestDownload(url) { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState < 4) return; + + console.log(request.responseText); + queuePos = request.responseText; + } + request.open("POST", "#", true); + request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + request.withCredentials = true; + request.send('async=true&url=' + + url + + '<?php if (array_key_exists("manual", $_POST)) { echo "&manual=" . $_POST["manual"]; } ?>'); +} +requestDownload('<?= $url ?>'); + +const position = document.getElementById('position'); +function updatePosition(url) { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState < 4) return; + + if (queuePos < request.responseText) { + window.location.href = '/archive/?url=' + url; + return; + } + + position.innerText = queuePos - request.responseText; + setTimeout(updatePosition, 1000, url); + } + request.open("POST", "/archive/create/status.php", true); + request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + request.send('url=' + url); +} + +updatePosition('<?= $url ?>'); +</script> diff --git a/views/archive/create/status.php b/views/archive/create/status.php new file mode 100644 index 0000000..d020c4a --- /dev/null +++ b/views/archive/create/status.php @@ -0,0 +1,5 @@ +<?php + +session_start(); + +echo $_SESSION['archive_current']; |
