191 lines
6.5 KiB
PHP
191 lines
6.5 KiB
PHP
<?php
|
|
// examples/enable_show_local.php
|
|
// Web-server side handler to toggle "Show" for an MVLog job and send a web-push immediately if appropriate.
|
|
// This runs entirely on the web server and does not call the worker.
|
|
//
|
|
// Usage (POST): job=<job> show=1|0
|
|
// Configure $MVLOG_ROOT and $PUSH_CONFIG below.
|
|
|
|
// Configuration - update to match your server
|
|
$MVLOG_ROOT = '/var/www/html/mvlog';
|
|
$PUSH_CONFIG_CANDIDATES = [
|
|
"$MVLOG_ROOT/push.json",
|
|
getenv('HOME') !== false ? getenv('HOME') . '/.config/mvlog/push.json' : null,
|
|
'/etc/mvlog/push.json',
|
|
];
|
|
|
|
$LOGFILE = '/var/log/mvlog_notify.log';
|
|
|
|
$job = $_POST['job'] ?? '';
|
|
$show = isset($_POST['show']) ? filter_var($_POST['show'], FILTER_VALIDATE_BOOLEAN) : true;
|
|
|
|
// Basic validation for job name; adjust to your naming policy if needed
|
|
if (!preg_match('/^[0-9]{8}[-_][A-Za-z0-9._-]+$/', $job)) {
|
|
http_response_code(400);
|
|
echo 'invalid job';
|
|
exit;
|
|
}
|
|
|
|
$jobdir = "$MVLOG_ROOT/in-dir/$job";
|
|
if (!is_dir($jobdir)) {
|
|
http_response_code(404);
|
|
echo 'job not found';
|
|
exit;
|
|
}
|
|
|
|
$enabled_file = "$jobdir/.movmaker-enabled";
|
|
$hidden_file = "$jobdir/.mvlog-hidden";
|
|
$subs_file = "$MVLOG_ROOT/cache/push_subscriptions.json";
|
|
$cache_file = "$MVLOG_ROOT/cache/push_notifications.json";
|
|
|
|
// Find push config
|
|
$push_config = null;
|
|
foreach ($PUSH_CONFIG_CANDIDATES as $candidate) {
|
|
if (!$candidate) continue;
|
|
if (file_exists($candidate) && is_readable($candidate)) {
|
|
$push_config = $candidate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($show) {
|
|
// Create marker file atomically
|
|
file_put_contents($enabled_file, date(DATE_ATOM) . PHP_EOL, LOCK_EX);
|
|
// Try to send push (non-fatal)
|
|
$sent = try_send_show_notification($job, $jobdir, $MVLOG_ROOT, $subs_file, $cache_file, $push_config, $LOGFILE);
|
|
if ($sent) {
|
|
echo 'enabled';
|
|
} else {
|
|
echo 'enabled (no notification)';
|
|
}
|
|
} else {
|
|
// Remove marker and do not touch notifications
|
|
@unlink($enabled_file);
|
|
echo 'disabled';
|
|
}
|
|
|
|
exit;
|
|
|
|
function try_send_show_notification($job, $jobdir, $root, $subs_file, $cache_file, $push_config, $logfile)
|
|
{
|
|
// Skip if hidden
|
|
if (file_exists($jobdir . '/.mvlog-hidden')) {
|
|
error_log("[mvlog] job $job hidden, skipping push\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// Ensure we have subscriptions
|
|
if (!file_exists($subs_file)) {
|
|
error_log("[mvlog] subscriptions file missing, skipping push for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
$subs_raw = file_get_contents($subs_file);
|
|
if (!trim($subs_raw)) {
|
|
error_log("[mvlog] subscriptions empty, skipping push for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
$subs = json_decode($subs_raw, true);
|
|
if (!is_array($subs) || count($subs) === 0) {
|
|
error_log("[mvlog] subscriptions invalid/empty, skipping push for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// Read cache and check if already shown
|
|
$cache = [];
|
|
if (file_exists($cache_file)) {
|
|
$cache = json_decode(@file_get_contents($cache_file), true) ?: [];
|
|
}
|
|
$shown = isset($cache['shown']) && is_array($cache['shown']) ? $cache['shown'] : [];
|
|
if (isset($shown[$job])) {
|
|
error_log("[mvlog] push already sent for $job, skipping\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// Ensure push config present
|
|
if (!$push_config) {
|
|
error_log("[mvlog] push config not found, skipping push for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// Determine title (prefer output filename from state file)
|
|
$title = preg_replace('/_+/', ' ', $job);
|
|
$title = ucwords($title);
|
|
$state_file = $jobdir . '/.movmaker-state.json';
|
|
if (file_exists($state_file)) {
|
|
$state = json_decode(@file_get_contents($state_file), true) ?: [];
|
|
if (!empty($state['output']) && is_string($state['output'])) {
|
|
$out = pathinfo($state['output'], PATHINFO_FILENAME);
|
|
if ($out) {
|
|
$title = preg_replace('/_+/', ' ', $out);
|
|
$title = ucwords($title);
|
|
}
|
|
}
|
|
}
|
|
|
|
$article_id_file = $jobdir . '/.mvlog-id';
|
|
$article_id = file_exists($article_id_file) ? strtolower(trim((string)@file_get_contents($article_id_file))) : '';
|
|
if (!preg_match('/^[0-9]{14}[a-f0-9]{16}$/', $article_id)) {
|
|
error_log("[mvlog] article id missing, skipping push for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
$payload = json_encode([
|
|
'title' => 'Show enabled',
|
|
'body' => $title,
|
|
'url' => './?id=' . rawurlencode($article_id),
|
|
'tag' => "mvlog-show-$article_id",
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
// Call node send_push.js with subscriptions on stdin
|
|
$send_script = escapeshellarg($root . '/send_push.js');
|
|
$push_config_esc = escapeshellarg($push_config);
|
|
$payload_esc = escapeshellarg($payload);
|
|
$cmd = "node $send_script $push_config_esc $payload_esc";
|
|
|
|
$descriptorspec = [
|
|
0 => ['pipe', 'r'], // stdin
|
|
1 => ['pipe', 'w'], // stdout
|
|
2 => ['pipe', 'w'], // stderr
|
|
];
|
|
|
|
$proc = proc_open($cmd, $descriptorspec, $pipes);
|
|
if (!is_resource($proc)) {
|
|
error_log("[mvlog] failed to start node send_push process for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// Write subscriptions to stdin
|
|
fwrite($pipes[0], $subs_raw);
|
|
fclose($pipes[0]);
|
|
|
|
$stdout = stream_get_contents($pipes[1]); fclose($pipes[1]);
|
|
$stderr = stream_get_contents($pipes[2]); fclose($pipes[2]);
|
|
|
|
$rc = proc_close($proc);
|
|
if ($rc !== 0) {
|
|
error_log("[mvlog] send_push failed for $job rc=$rc stdout=" . trim($stdout) . " stderr=" . trim($stderr) . "\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
// On success, record in cache['shown']
|
|
if (!is_array($cache)) $cache = [];
|
|
if (!isset($cache['shown']) || !is_array($cache['shown'])) $cache['shown'] = [];
|
|
$cache['shown'][$job] = ['sent_at' => date(DATE_ATOM)];
|
|
|
|
// Atomic write: write to tmp then rename
|
|
$tmp = $cache_file . '.tmp.' . bin2hex(random_bytes(6));
|
|
$json = json_encode($cache, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
|
|
if (@file_put_contents($tmp, $json, LOCK_EX) === false) {
|
|
error_log("[mvlog] failed to write cache temp file for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
@chmod($tmp, 0664);
|
|
if (!@rename($tmp, $cache_file)) {
|
|
@unlink($tmp);
|
|
error_log("[mvlog] failed to atomically write cache file for $job\n", 3, $logfile);
|
|
return false;
|
|
}
|
|
|
|
error_log("[mvlog] show-notification sent: $job\n", 3, $logfile);
|
|
return true;
|
|
}
|