1
0
Fork 1

Restructure static site generation

pull/8/head
gravel 1 year ago
parent 918a94b8b4
commit 8edb363efe
Signed by: gravel
SSH Key Fingerprint: SHA256:p4HP49CCk4YQMkJpWJ09L8peEPQWjERtdCRAFxPfbOY

@ -0,0 +1,19 @@
<?php
$PROJECT_ROOT=__DIR__;
$CACHE_ROOT="$PROJECT_ROOT/cache";
$QR_CODES="$CACHE_ROOT/qr-codes";
$ROOMS_FILE="$CACHE_ROOT/rooms.json";
$DOCUMENT_ROOT="$PROJECT_ROOT/output";
$TEMPLATES_ROOT="$PROJECT_ROOT/sites";
$LANGUAGES_ROOT="$PROJECT_ROOT/languages"
// set timeout for file_get_contents()
ini_set('default_socket_timeout', 6); // in seconds, default is 60
// curl timeout is millisecons
$curl_connecttimeout_ms = 3000; // time for initiation of the connection
$curl_timeout_ms = 6000; // max time for whole connection (incl. transfer)
// do not report warnings (timeouts, SSL/TLS errors)
error_reporting(E_ALL & ~E_WARNING);
?>

@ -1,201 +0,0 @@
<?php
/*
* Build valid HTML5 page from provided (table) html
*/
function create_html_page_from_html_data($html_data, $title, $timestamp) {
$pre =
"<!DOCTYPE html>" . PHP_EOL .
"<html lang=\"en\">" . PHP_EOL .
" <head>" . PHP_EOL .
" <meta charset=\"UTF-8\">" . PHP_EOL .
" <link rel=\"icon\" type=\"image/svg+xml\" href=\"favicon.svg\" sizes=\"any\">" . PHP_EOL .
" <link rel=\"stylesheet\" href=\"styles2.css\">" . PHP_EOL .
" <script src=\"script2.js\" defer></script>" . PHP_EOL .
" <title>" . $title . "</title>" . PHP_EOL .
" </head>" . PHP_EOL .
" <body onload=\"onLoad(" . $timestamp . ")\">" . PHP_EOL;
$post =
" </body>" . PHP_EOL .
"</html>" . PHP_EOL;
$html5 = $pre . $html_data . $post;
return $html5;
}
/*
* Writes HTML table with the following info:
* Token + shortened pubkey | Name | Description | Users | View Links(?) | Join URL
*/
function get_table_html($info_arrays) {
$table_lines = array();
foreach($info_arrays as $id => $content) {
/*
* $id is "room token+shortened_pubkey", e.g. "example+09af"
* Each $content looks like this:
* $info_array = array(
* "name" => "Name of the room",
* "language" => "🇩🇪",
* "description" => "Some text that describes the community",
* "active_users" => 1234,
* "preview_link" => "https://example.com/r/example",
* "join_link" => "https://example.com/example?public_key=[64_hex_chars]"
* );
*/
$exploded = explode("/", $content["join_link"]); // https: + "" + 1.2.3.4:56789 + token?public_key=0123456789abcdef
$server_url = $exploded[0] . "//" . $exploded[2]; // extract server_url
$token = explode("?", $exploded[3])[0]; // extract token
$line =
" <tr id=\"" . $id . "\">" . PHP_EOL .
" <td class=\"td_identifier\">" . $id . "</td>" . PHP_EOL .
" <td>" . $content["language"] . "</td>" . PHP_EOL .
" <td>" . $content["name"] . "</td>" . PHP_EOL .
" <td>" . $content["description"] . "</td>" . PHP_EOL .
" <td class=\"td_users\">" . $content["active_users"] . "</td>" . PHP_EOL .
" <td><a href=\"" . $content["preview_link"] . "\">" . $content["preview_link"] . "</a></td>" . PHP_EOL .
" <td><img class=\"qr-code-icon\" src=\"qrcode-solid.svg\" onclick=\"displayQRModal('" . $id . "')\" alt=\"Pictogram of an QR code\"></td>" . PHP_EOL .
" <td class=\"td_join_url\"><a href=\"" . $content["join_link"] . "\">" . $content["join_link"] . "</a></td>" . PHP_EOL .
" </tr>" . PHP_EOL;
$table_lines[] = $line;
}
// prefix
$prefix =
"<h1 id=\"headline\">Session Communities</h1>" . PHP_EOL .
"<table id=\"tbl_communities\">" . PHP_EOL .
" <tr>" . PHP_EOL .
" <th onclick=\"sortTable(0)\" id=\"th_identifier\">Identifier</th>" . PHP_EOL .
" <th onclick=\"sortTable(1)\" id=\"th_language\">L</th>" . PHP_EOL .
" <th onclick=\"sortTable(2)\" id=\"th_name\">Name</th>" . PHP_EOL .
" <th onclick=\"sortTable(3)\" id=\"th_description\">Description</th>" . PHP_EOL .
" <th onclick=\"sortTable(4)\" id=\"th_users\">Users</th>" . PHP_EOL .
" <th onclick=\"sortTable(5)\" id=\"th_preview\">Preview</th>" . PHP_EOL .
" <th id=\"th_qr\">QR</th>" . PHP_EOL .
" <th onclick=\"sortTable(7)\" id=\"th_join_url\">Join URL</th>" . PHP_EOL .
" </tr>" . PHP_EOL;
// suffix
$suffix =
"</table>" . PHP_EOL .
"<table id=\"tbl_footer\">" . PHP_EOL .
" <tr>" . PHP_EOL .
" <td id=\"td_summary\">" . count($table_lines) . " unique Session Communities on " . count_servers($info_arrays) . " servers have been found.</td>" . PHP_EOL .
" </tr>" . PHP_EOL .
" <tr>" . PHP_EOL .
" <td id=\"td_last_checked\">Last checked X minutes ago.</td>" . PHP_EOL .
" </tr>" . PHP_EOL .
"</table>" . PHP_EOL;
// concatenate html
$html = $prefix;
foreach($table_lines as $line) {
$html = $html . $line;
}
$html = $html . $suffix;
return $html;
}
/*
* Needed until all Community servers reliably generate QR codes again
*/
function get_qr_img_element_from_join_url($join_url) {
$data = get_base64_qr_code_from_join_url($join_url);
$mime = "image/png";
$src = "data:" . $mime . ";base64," . $data;
$result =
"<img src=\"" . $src . "\" " .
"alt=\"Community join link encoded as QR code image\" " .
"class=\"qr-code\">";
// echo($result . PHP_EOL);
return $result;
}
/*
* Use Google API to generate QR codes and encode them as base64
*/
function get_base64_qr_code_from_join_url($join_url) {
// https://developers.google.com/chart/infographics/docs/qr_codes
$data = urlencode($join_url);
$size = "512x512";
$api_url =
"https://chart.googleapis.com/chart?cht=qr" .
"&chs=" . $size .
"&chl=" . $data .
"&chld=L|0"; // error correction level: L = 7%, M = 15%, Q = 25%, H = 30% | margin in number of rows
$img_base64 = base64_encode(file_get_contents($api_url));
// echo($img_base64 . PHP_EOL);
return $img_base64;
}
/*
* TODO: Description
*/
function create_qr_code_modals_html($info_arrays) {
$html = "";
foreach($info_arrays as $id => $content) {
/*
* $id is "room token+shortened_pubkey", e.g. "example+09af"
* Each $content looks like this:
* $info_array = array(
* "name" => "Name of the room",
* "language" => "🇩🇪",
* "description" => "Some text that describes the community",
* "active_users" => 1234,
* "preview_link" => "https://example.com/r/example",
* "join_link" => "https://example.com/example?public_key=[64_hex_chars]"
* );
*/
$img_elem = get_qr_img_element_from_join_url($content["join_link"]); // TODO: incorporate ID to use in js function
$modal_html =
"<div id=\"modal_" . $id . "\" class=\"qr-code-modal\">" . PHP_EOL .
" <div class=\"qr-code-modal-content\">" . PHP_EOL .
" <span class=\"qr-code-modal-close\" onclick=\"hideQRModal('" . $id . "')\">&times;</span>" . PHP_EOL .
" " . $img_elem . PHP_EOL .
" </div>" . PHP_EOL .
"</div>" . PHP_EOL;
$html = $html . $modal_html;
}
return $html;
}
/*
* Generate the HTML for the toast/snackbar when you copy a join link
*/
function get_copy_snackbar() {
$snackbar_html =
"<div id=\"copy-snackbar\">" .
"Copied URL to clipboard. Paste into Session app to join." .
"</div>";
return $snackbar_html;
}
/*
* TODO: Description
*/
function generateHTML($timestamp, $info_arrays) {
$title = "Self-updating list of active Session Communities";
$table_html = get_table_html($info_arrays);
$modal_html = create_qr_code_modals_html($info_arrays);
$snackbar_html = get_copy_snackbar();
$html =
$table_html . PHP_EOL .
$modal_html . PHP_EOL .
$snackbar_html . PHP_EOL;
$final_html = create_html_page_from_html_data($html, $title, $timestamp);
return $final_html;
}
?>

@ -2,21 +2,9 @@
// requires php-curl
// require other php files
require "helper_functions.php";
require "html_generator.php";
include "languages/language_flags.php"; // actually runs fine without it
// some global stuff
// set timeout for file_get_contents()
ini_set('default_socket_timeout', 6); // in seconds, default is 60
// curl timeout is millisecons
$curl_connecttimeout_ms = 3000; // time for initiation of the connection
$curl_timeout_ms = 6000; // max time for whole connection (incl. transfer)
// do not report warnings (timeouts, SSL/TLS errors)
error_reporting(E_ALL & ~E_WARNING);
require_once "getenv.php"
require_once "utils/server-utils.php";
include_once "$LANGUAGES_ROOT/language_flags.php"; // actually runs fine without it
// room token regex part, must consist of letters, numbers, underscores, or dashes: https://github.com/oxen-io/session-pysogs/blob/dev/administration.md
$room_token_regex_part = "[0-9A-Za-z-_]+";
@ -33,7 +21,6 @@
*/
$room_join_regex = "/https?:\/\/[^\/]+\/" . $room_token_regex_part . "\?public_key=[0-9A-Fa-f]{64}/";
/*
* Some servers don't appear in the wild yet, but can be queried
* Ideally this shouldn't be necessary, but it is for now
@ -50,8 +37,12 @@
);
// path for HTML output
$output = "output/index.html";
// $output = "output/index.html";
// path for room data output
$output = "$ROOMS_FILE";
file_exists($CACHE_ROOT) or mkdir($CACHE_ROOT, 700);
// run main function
main();
@ -75,10 +66,11 @@
$addr_assignments = reduce_addresses_of_pubkeys($addr_assignments);
$room_assignments = assign_rooms_to_address_assignments($addr_assignments, $rooms);
$info_arrays = generate_info_arrays($room_assignments);
// $final_join_links = generate_join_links($room_assignments);
$final_html = generateHTML($timestamp, $info_arrays);
// $final_html = generateHTML($timestamp, $info_arrays);
// print_r($wild_join_links);
// print_r($servers);
@ -91,7 +83,7 @@
// write output to disk
global $output;
file_put_contents($output, $final_html); // overwrites existing file
file_put_contents($output, json_encode($info_arrays)); // overwrites existing file
echo("Done. " . count($info_arrays) . " unique Session Communities on " . count_servers($info_arrays) . " servers have been found." . PHP_EOL);
}
@ -702,24 +694,6 @@
return $info_arrays;
}
/*
* Counts every unique server from given $info_arrays and returns the count
*/
function count_servers($info_arrays) {
$servers = array();
foreach($info_arrays as $i_arr) {
// https://sogs.example.com:1234/token?public_key=...
$join_link = $i_arr["join_link"];
$exploded = explode("/", $join_link); // https: + "" + sogs.example.com:1234 + token?public_key=...
$servers[] = $exploded[0] . "//" . $exploded[2];
}
$servers = array_unique($servers);
sort($servers);
// print_r($servers);
return count($servers);
}
/*
* Debug function to see which communities use pinned messages already
*/

@ -0,0 +1,33 @@
<?php
// Perform static site generation.
require_once "getenv.php";
// https://stackoverflow.com/a/17161106
function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge(
[],
...[$files, rglob($dir . "/" . basename($pattern), $flags)]
);
}
return $files;
}
foreach (rglob("$TEMPLATES_ROOT/*.php") as $phppath) {
// Do not render auxilliary PHP files.
if (str_contains("$phppath", "/+") || $phppath[0] == "+")
continue;
$docpath = str_replace($TEMPLATES_ROOT, $DOCUMENT_ROOT, $phppath);
$docpath = str_replace(".php", ".html", $docpath);
// This works? Yes, yes it does.
// We do this to isolate the environment and include-once triggers,
// otherwise we could include the documents in an ob_* wrapper.
$document = `php $phppath`;
file_put_contents($docpath, $document);
}
?>

@ -0,0 +1,13 @@
<?php
$PROJECT_ROOT = dirname(__FILE__);
while (!file_exists("$PROJECT_ROOT/.phpenv")) {
if ($PROJECT_ROOT == "/" || $PROJECT_ROOT == "")
throw new RuntimeException("Could not find .phpenv file.");
$PROJECT_ROOT = dirname($PROJECT_ROOT);
}
require_once "$PROJECT_ROOT/.phpenv";
// set_include_path(get_include_path() . PATH_SEPARATOR . $PROJECT_ROOT);
?>

@ -0,0 +1,5 @@
<?php
// Perform full update of community list.
require_once "fetch-servers.php";
require_once "generate-html.php";
?>

@ -1,4 +1,23 @@
<?php
/*
* Counts every unique server from given $info_arrays and returns the count
*/
function count_servers($info_arrays) {
$servers = array();
foreach($info_arrays as $i_arr) {
// https://sogs.example.com:1234/token?public_key=...
$join_link = $i_arr["join_link"];
// https: + "" + sogs.example.com:1234 + token?public_key=...
$exploded = explode("/", $join_link);
$servers[] = $exploded[0] . "//" . $exploded[2];
}
$servers = array_unique($servers);
sort($servers);
// print_r($servers);
return count($servers);
}
/*
* Helper function for reduce_servers
*/
@ -92,4 +111,4 @@
return $contents;
}
}
?>
?>

@ -0,0 +1,45 @@
<?php
function room_qr_code_cached($room_id) {
global $QR_CODES;
return "$QR_CODES/$room_id.png";
}
/*
* Use Google API to generate QR codes and encode them as base64
*/
function base64_qr_code($room_id, $join_url, $size = "512x512") {
// Could use http_build_query() instead, but I won't break what works.
// https://developers.google.com/chart/infographics/docs/qr_codes
$png_cached = room_qr_code_cached($room_id);
if (file_exists($png_cached))
return base64_encode(file_get_contents($png_cached));
$data = urlencode($join_url);
$api_url =
"https://chart.googleapis.com/chart?cht=qr" .
"&chs=$size" .
"&chl=$data" .
"&chld=L|0";
// error correction level: L = 7%, M = 15%, Q = 25%, H = 30%
// | margin in number of rows
$png = file_get_contents($api_url);
file_put_contents($png_cached, $png);
return base64_encode($png);
}
file_exists($QR_CODES) or mkdir($QR_CODES, 700);
?>
<?php foreach ($rooms as $id => $room): ?>
<div id="modal_<?=$id?>" class="qr-code-modal">
<div class="qr-code-modal-content">
<span class="qr-code-modal-close" onclick='hideQRModal("<?=$id?>")'>
&times;
</span>
<img
src="data:image/png;base64,<?=base64_qr_code($id, $room->join_link)?>"
alt="Community join link encoded as QR code"
class="qr-code"
>
</div>
</div>
<?php endforeach; ?>

@ -0,0 +1,67 @@
<?php
// Once handlers are attached in JS, this check ceases to be useful.
function column_sortable($id) {
return $id != "qr";
}
function sort_onclick($colno) {
global $TABLE_COLUMNS;
$column = $TABLE_COLUMNS[$colno];
if (!column_sortable($column['id'])) return "";
return " onclick='sortTable($colno)'";
}
$TABLE_COLUMNS = [
['id' => "identifier", 'name' => "Identifier"],
['id' => "language", 'name' => "L"],
['id' => "name", 'name' => "Name"],
['id' => "description", 'name' => "Description"],
['id' => "users", 'name' => "Users"],
['id' => "preview", 'name' => "Preview"],
['id' => "qr", 'name' => "QR"],
['id' => "join_url", 'name' => "Join URL"],
];
?>
<table id="tbl_communities">
<tr>
<?php foreach ($TABLE_COLUMNS as $colno => $column): ?>
<th<?=sort_onclick($colno)?> id="th_<?=$column['id']?>">
<?=$column['name']?>
</th>
<?php endforeach; ?>
</tr>
<?php foreach ($rooms as $id => $room): ?>
<tr id="<?=$id?>">
<td class="td_identifier"><?=$id?></td>
<td class="td_language"><?=$room->language?></td>
<td class="td_name"><?=$room->name?></td>
<td class="td_description">
<?=$room->description?>
</td>
<td class="td_users"><?=$room->active_users?></td>
<td class="td_preview">
<a href="<?=$room->preview_link?>">
<?=$room->preview_link?>
</a>
</td>
<td class="td_qr_code">
<img
class="qr-code-icon"
src="qrcode-solid.svg"
onclick='displayQRModal("<?=$id?>")'
alt="Pictogram of a QR code"
>
</td>
<td class="td_join_url">
<a href="<?=$room->join_link?>">
<?=$room->join_link?>
</a>
</td>
</tr>
<?php endforeach; ?>
</table>

@ -0,0 +1 @@
../php/getenv.php

@ -0,0 +1,42 @@
<?php
// prerequisite include for sites and components
require_once "+getenv.php";
require_once "$PROJECT_ROOT/php/server-utils.php";
$rooms_raw = file_get_contents($ROOMS_FILE);
$rooms = json_decode($rooms_raw);
$rooms_assoc = json_decode($rooms_raw, true);
$timestamp = filemtime($ROOMS_FILE);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" type="image/svg+xml" href="favicon.svg" sizes="any">
<link rel="stylesheet" href="styles2.css">
<script src="script2.js" defer></script>
<title>Self-updating list of active Session communities</title>
</head>
<body onload="onLoad(<?php echo $timestamp ?>)">
<h1 id="headline">Session Communities</h1>
<?php include "+components/qr_modals.php" ?>
<?php include "+components/tbl_communities.php" ?>
<table id="tbl_footer">
<tr>
<td id="td_summary">
<?=count($rooms_assoc)?> unique Session Communities
on <?=count_servers($rooms_assoc)?> servers have been found.
</td>
</tr>
<tr>
<td id="td_last_checked">Last checked X minutes ago.</td>
</tr>
</table>
<div id="copy-snackbar">
Copied URL to clipboard. Paste into Session app to join
</div>
</body>
</html>

@ -5,4 +5,4 @@ Description=Scrape every known source for Session Communities and put the data t
[Service]
WorkingDirectory=/home/session/sessioncommunities.online
User=session
ExecStart=/usr/bin/php get_online_session_communities.php
ExecStart=/usr/bin/php php/update-listing.php