feat: add post access usage metrics

This commit is contained in:
David Bailey 2023-12-20 18:52:28 +01:00
parent eb87a78625
commit 94b65aec8c
3 changed files with 161 additions and 74 deletions

View file

@ -26,6 +26,20 @@ CREATE TABLE posts (
INDEX(post_path_depth, post_path)
);
CREATE TABLE path_access_counts (
post_path VARCHAR(255),
agent VARCHAR(255),
path_last_access_time DATETIME NOT NULL
DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
path_access_count INTEGER DEFAULT 0,
path_processing_time DOUBLE PRECISION DEFAULT 0,
PRIMARY KEY(post_path, agent),
INDEX(path_last_access_time)
);
INSERT INTO posts (post_path, post_path_depth, post_metadata, post_content)
VALUES (

View file

@ -103,6 +103,47 @@ class MySQLAdapter {
}
}
function log_post_access($post_path, $agent, $time) {
$qry = "
INSERT INTO path_access_counts
(post_path, agent,
path_access_count,
path_processing_time)
VALUES ( ?, ?, 1, ? ) AS new
ON DUPLICATE KEY
UPDATE path_access_count=path_access_counts.path_access_count+1,
path_processing_time=path_access_counts.path_processing_time+new.path_processing_time;
";
$this->_exec($qry, "ssd", $post_path, $agent, $time);
}
function get_post_access_counters() {
$qry = "
SELECT post_path, agent, path_access_count, path_processing_time
FROM path_access_counts
WHERE path_last_access_time > ( CURRENT_TIMESTAMP - INTERVAL 10 MINUTE );
";
$data = $this->_exec($qry, "")->fetch_all(MYSQLI_ASSOC);
$out_data = [];
foreach($data AS $post_data) {
$path = $post_data['post_path'];
$agent_data = ($out_data[$path] ?? []);
$agent_data[$post_data['agent']] = [
'count' => $post_data['path_access_count'],
'time' => round($post_data['path_processing_time'], 6)
];
$out_data[$path] = $agent_data;
}
return $out_data;
}
function update_or_create_post($post_path, $post_metadata, $post_content) {
$post_path = $this->_sanitize_path($post_path);
$path_depth = substr_count($post_path, "/");

View file

@ -1,5 +1,7 @@
<?php
$data_time_start = microtime(true);
require_once 'vendor/autoload.php';
require_once 'post_adapter.php';
@ -32,9 +34,27 @@ $twig->addRuntimeLoader(new class implements RuntimeLoaderInterface {
}
});
$SURI = $_SERVER['REQUEST_URI'];
function deduce_user_agent() {
$real_agent=$_SERVER['HTTP_USER_AGENT'];
if(preg_match('/^\/api\/admin/', $SURI)) {
if(preg_match('/(?:Mozilla|Chrome|Chromium)/', $real_agent)) {
return "web";
}
elseif(preg_match('/(?:google)/', $real_agent)) {
return "bot/google";
}
else {
return "unidentified";
}
}
$user_agent = deduce_user_agent();
function generate_website($SURI) {
global $twig;
global $adapter;
if(preg_match('/^\/api\/admin/', $SURI)) {
header('Content-Type: application/json');
$user_api_key = '';
@ -60,8 +80,11 @@ if(preg_match('/^\/api\/admin/', $SURI)) {
echo json_encode(["ok" => true]);
}
} elseif(preg_match('/^\/api/', $SURI)) {
if(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
} elseif(preg_match('/^\/api/', $SURI)) {
if($SURI == '/api/post_counters') {
header('Content-Type: application/json');
echo json_encode($adapter->get_post_access_counters());
} elseif(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
header('Content-Type: application/json');
echo json_encode($adapter->get_post_by_path($match[1]));
@ -74,10 +97,10 @@ if(preg_match('/^\/api\/admin/', $SURI)) {
echo $twig->render('upload.html');
}
} elseif(preg_match('/^\s*image/', $_SERVER['HTTP_ACCEPT'])) {
} elseif(preg_match('/^\s*image/', $_SERVER['HTTP_ACCEPT'])) {
header('Location: /raw' . $SURI);
exit(0);
} elseif(true) {
} elseif(true) {
$post = $adapter->get_post_by_path($SURI);
if(!$post['found']) {
@ -89,24 +112,24 @@ if(preg_match('/^\/api\/admin/', $SURI)) {
"post" => $post
]);
exit(0);
die();
}
if($post['post_metadata']['type'] == 'directory') {
if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) {
header('Location: ' . $match[1] . '/' . $match[2]);
exit(0);
return;
}
echo $twig->render('post_types/directory.html', [
"post" => $post,
"subposts" => $post['subposts']
"subposts" => $adapter->get_subposts_by_path($SURI)
]);
}
elseif($post['post_metadata']['type'] == 'text/markdown') {
echo $twig->render('post_types/markdown.html', [
"post" => $post,
"subposts" => $post['subposts']
"post" => $post
]);
}
elseif($post['post_metadata']['type'] == 'image') {
@ -115,13 +138,22 @@ if(preg_match('/^\/api\/admin/', $SURI)) {
]);
}
} else {
} else {
echo $twig->render('rrror.html',[
"error_code" => '404 Hoard not found!',
"error_description" => "Well, we searched
far and wide for `" . $SURI . "` but
somehow it must have gotten lost... Sorry!"
]);
}
}
generate_website($_SERVER['REQUEST_URI']);
$data_time_end = microtime(true);
$adapter->log_post_access($_SERVER['REQUEST_URI'],
$user_agent,
$data_time_end - $data_time_start)
?>