docs: document symbols where reasonable

Doxygen is still producing lots of warnings due to bad parsing.

Includes one or two error checks for function constraints.
main
gravel 3 months ago
parent 91818858f5
commit f9aa117e6b
Signed by: gravel
GPG Key ID: C0538F3C906B308F

@ -4,6 +4,13 @@
* Provide language flags for hardcoded Communities.
*/
/**
* @var array<string, string> $server_languages
*
* Dictionary of language flags for hardcoded Communities.
*
* The array key a Community ID (long or legacy short).
*/
$server_languages = [];
// https://reccacon.com/Ukraine

@ -8,10 +8,14 @@
require_once 'utils/getopt.php';
/**
* Recursively match the last segment of the given path pattern.
* @source https://stackoverflow.com/a/17161106
* Return file names matching the glob pattern in all subdirectories.
* @param string $pattern Glob pattern.
* @param int $flags Glob flags.
* @author Tony Chen
* @see https://stackoverflow.com/a/17161106
* @return string[] Array of file names.
*/
function rglob($pattern, $flags = 0) {
function rglob($pattern, $flags = 0): array {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge(
@ -22,7 +26,12 @@
return $files;
}
function serialize_shell_environment(array $env_vars) {
/**
* Produce shell code to set the environment variables given.
*
* @param string[] $env_vars Dictionary of environment variables.
*/
function serialize_shell_environment(array $env_vars): string {
$env_assignments = array_map(function(string $key, string $value) {
return "$key=".escapeshellarg($value);
}, array_keys($env_vars), array_values($env_vars));
@ -30,7 +39,10 @@
}
/**
* Generate files from PHP templates in the templates directory.
* Generate files from PHP templates.
*
* Templates used are in the {@link $TEMPLATES_ROOT} directory.
* Generated files are places in the {@link $DOCUMENT_ROOT} directory.
*/
function generate_files() {
global $LOGGING_VERBOSITY, $TEMPLATES_ROOT, $DOCUMENT_ROOT;

@ -10,6 +10,10 @@
*/
$PROJECT_ROOT = dirname(__FILE__);
/**
* @var string $PHPENV_FILENAME
* File comtaining PHP environment variables. Marks root folder.
*/
$PHPENV_FILENAME = ".phpenv.php";
(function(){

@ -11,25 +11,50 @@
}
/**
* Stored Community servers..
* @var CommunityServer[] $servers
*/
public array $servers;
/**
* Stored Communities.
* @var CommunityRoom[] $rooms
*/
public array $rooms;
/**
* Read a database of Session Open Group servers and Communities.
*
* @param string $rooms_file JSON file containing fetched server data.
* Typically equal to {@link $ROOMS_FILE}.
*
* @return CommunityDatabase
*/
public static function read_from_file(string $rooms_file): CommunityDatabase {
$servers = CommunityServer::read_servers_from_file($rooms_file);
return new CommunityDatabase($servers);
}
/**
* Re-fetch outdated assets for Communities stored by the database.
*
* @return CommunityDatabase self
*/
public function fetch_assets(): CommunityDatabase {
CommunityRoom::fetch_assets($this->rooms);
return $this;
}
/**
* Return the Communities and servers stored by the database.
*
* Usage:
* ```php
* list($rooms, $servers) = communityDatabase->unpack();
* ```
*
* @return array
*/
public function unpack() {
return [$this->rooms, $this->servers];
}

@ -12,6 +12,11 @@
/**
* Construct Community listings from listing configuration and cached Communities.
*
* @param string $listings_ini File containing listing configuration.
* @param CommunityServer[] $servers Array of Community servers used to resolve the listing. Leave empty to fetch from cache.
*
* @return CommunityListingDatabase
*/
public static function resolve_listings_from_ini(string $listings_ini, array $servers = null): CommunityListingDatabase {
global $ROOMS_FILE;
@ -59,7 +64,17 @@
return array_values($this->listings);
}
public function get_listing(string $id): CommunityListing {
/**
* Get the Community listing with the given ID.
*
* @param string $id Configured listing identifier.
*
* @return CommunityListing
*/
public function get_listing(string $id): CommunityListing|null {
if (!isset($this->listings[$id])) {
throw new Error("No such listing: '$id'");
}
return $this->listings[$id];
}
}

@ -173,6 +173,12 @@
/**
* Create incomplete CommunityRoom instance from intermediate data.
*
* Use when room data has been fetched, but the server's public key is still unknown.
*
* @param CommunityServer $server Open Group Server hosting given Community.
* @param array $details Associative data describing given Community.
* @return CommunityRoom Incomplete CommunityRoom instance. Expect errors.
*/
public static function _from_intermediate_data(
CommunityServer $server,
@ -273,7 +279,9 @@
/**
* Create a CommunityRoom instance from associative data.
* @param CommunityServer $server
* @param CommunityServer $server Open Group Server hosting given Community.
* @param array $details Associative data describing Community.
* @return CommunityRoom
*/
public static function from_details($server, array $details) {
return new CommunityRoom($server, $details);
@ -281,7 +289,8 @@
/**
* Create an array of CommunityRoom instances from associative data.
* @param array[] $details
* @param CommunityServer $server Open Group server hosting the given rooms.
* @param array[] $details_array Array of associative arrays holding room data.
* @return CommunityRoom[]
*/
public static function from_details_array($server, array $details_array) {
@ -294,9 +303,11 @@
* Sort Community rooms in-place by the given string property.
* @param CommunityRoom[] $rooms Rooms to sort by given key.
* @param string $key String property of CommunityRoom to sort by.
* @param bool $descending If true, sort in descending order.
* @return void
*/
public static function sort_rooms_str(array &$rooms, string $key, bool $reverse = false) {
usort($rooms, $reverse ? function(CommunityRoom $a, CommunityRoom $b) use ($key) {
public static function sort_rooms_str(array &$rooms, string $key, bool $descending = false) {
usort($rooms, $descending ? function(CommunityRoom $a, CommunityRoom $b) use ($key) {
return strcmp(
$b->$key,
$a->$key
@ -313,9 +324,11 @@
* Sort Community rooms in-place by the given numeric property.
* @param CommunityRoom[] $rooms Rooms to sort by given key.
* @param string $key Numeric property of CommunityRoom to sort by.
* @param bool $descending If true, sort in descending order.
* @return void
*/
public static function sort_rooms_num(array &$rooms, string $key, bool $reverse = false) {
usort($rooms, $reverse ? function(CommunityRoom $a, CommunityRoom $b) use ($key) {
public static function sort_rooms_num(array &$rooms, string $key, bool $descending = false) {
usort($rooms, $descending ? function(CommunityRoom $a, CommunityRoom $b) use ($key) {
return $b->$key - $a->$key;
} : function(CommunityRoom $a, CommunityRoom $b) use ($key) {
return $a->$key - $b->$key;
@ -325,6 +338,8 @@
/**
* Sort Community rooms in-place by their server.
* @param CommunityRoom[] $rooms Rooms to sort by server.
* @param bool $random If true, use random server order to sort rooms.
* @return void
*/
public static function sort_rooms_by_server(array &$rooms, bool $random = false) {
if ($random) {
@ -345,7 +360,9 @@
}
/**
* Re-fetch assets for the given Communities as necessary.
* @param CommunityRoom[] $rooms
* @return void
*/
public static function fetch_assets(array $rooms) {
// Sequential in each server, see note in fetch_room_hints_coroutine()
@ -362,9 +379,12 @@
}
/**
* @param CommunityRoom[] $rooms
* Keep only pinned Communities from the input list.
* @param CommunityRoom[] $rooms Input list of Communities.
* @param CommunityRoom[] $rest (output) Remainder of Communities from the list. (optional)
* @return CommunityRoom[] Pinned Communities.
*/
public static function get_stickied_rooms(array &$rooms, array &$rest = null) {
public static function get_stickied_rooms(array $rooms, array &$rest = null) {
global $STICKIED_ROOMS;
return CommunityRoom::select_rooms($rooms, $STICKIED_ROOMS, unmatched: $rest);
}
@ -538,7 +558,7 @@
* Check whether the given list matches the current Community or its parent server.
* @param string[] $filter
* Array of unique room identifiers, server pubkeys and/or server hostnames.
* @param string $matchee String matching room. Output parameter.
* @param string $matchee (output) String matching current room.
* @return bool True if the array matches the Community, false otherwise.
*/
public function matched_by_list(array $filter, string &$matchee = null): bool {
@ -553,9 +573,11 @@
}
/**
* Select Communities matching the given filter list.
* @param CommunityRoom[] $rooms
* @param string[] $filter
* @param string[] $matchees output parameter
* @param string[] $filter List of room identifiers, server pubkeys and/or hostnames.
* @param string[] $matchees (output) Filter list items used to select at least one Community. (optional)
* @param CommunityRoom[] $unmatched (output) Communities not matched by any filter items. (optional)
* @return CommunityRoom[]
*/
public static function select_rooms(array $rooms, array|string $filter, array &$matchees = null, array &$unmatched = null): array {
@ -615,11 +637,21 @@
return $this->has_nsfw_keywords() || $this->matched_by_list($NSFW_INCLUDE);
}
/**
* Return true if the Community is marked for testing.
*
* @return bool
*/
public function is_testing_room(): bool {
global $TESTING_INCLUDE;
return in_array("test", $this->string_tags) || $this->matched_by_list($TESTING_INCLUDE);
}
/**
* Return true if the Community is manually stickied.
*
* @return bool
*/
public function is_stickied_room(): bool {
global $STICKIED_ROOMS;
return $this->matched_by_list($STICKIED_ROOMS);
@ -642,7 +674,12 @@
return 0;
}
public function get_recommended_staff_count() {
/**
* Compute the recommended threshold for Community staff count.
*
* @return float
*/
public function get_recommended_staff_count(): float {
if ($this->active_users == null || $this->active_users == 0) return INF;
$recommended_staff_count = ceil($this->active_users ** 0.25);
return max(2, $recommended_staff_count);
@ -650,18 +687,30 @@
/**
* Estimate whether the Community has enough staff.
*
* @return bool
*/
public function has_good_staff_rating(): bool {
$staff_count = count($this->get_staff());
return $staff_count >= $this->get_recommended_staff_count();
}
public function get_numeric_staff_rating() {
/**
* Return a rating for the Community's staff count relative to active users.
*
* @return float
*/
public function get_numeric_staff_rating(): float {
if (!$this->write || !$this->read) return 2;
return min(2, count($this->get_staff()) / $this->get_recommended_staff_count());
}
public function get_minimal_staff_count() {
/**
* Compute the lower threshold for Community staff count.
*
* @return float
*/
public function get_minimal_staff_count(): float {
if ($this->active_users == null || $this->active_users == 0) return INF;
$minimal_staff_count = 1 + round((0.38 * log($this->active_users)) ** 1.15);
return max(2, $minimal_staff_count);
@ -858,6 +907,7 @@
/**
* Sort an array of servers in place based on URL.
* @param CommunityServer[] &$servers
* @return void
*/
static function sort_by_url(array &$servers) {
usort($servers, 'CommunityServer::compare_by_url');
@ -878,6 +928,7 @@
/**
* Sorts an array of servers in place by public key.
* @param CommunityServer[] $servers
* @return void
*/
public static function sort_by_pubkey(&$servers) {
foreach ($servers as $server) {
@ -893,6 +944,9 @@
/**
* Return true whether the two servers given share a room.
* @param CommunityServer $a First server to compare.
* @param CommunityServer $b Second server to compare.
* @return bool
*/
public static function rooms_in_common(CommunityServer $a, CommunityServer $b): bool {
// Rely on at least token or creation date differing.
@ -1122,7 +1176,7 @@
/**
* Create Community server instance from array loaded server data.
* @param array $details Decoded JSON associative arrays about server.
* @param array $details_array Array of associative arrays holding server data.
* @return CommunityServer[] Servers represented by given data.
*/
static function from_details_array(array $details_array) {
@ -1139,6 +1193,7 @@
* Add to the given servers additional data extracted from our sources.
* @param CommunityServer[] $servers
* @param CommunitySources $source
* @return void
*/
static function source_additional_info(array $servers, CommunitySources $source): void {
foreach ($servers as $server) {
@ -1214,13 +1269,17 @@
/**
* Returns the hostname for this server.
* @param bool $include_scheme [optional]
* Includes the port. `true` by default.
* @param bool $include_port
* Include port in output, if provided. Default: `true`.
* @return string URL with hostname and port, if applicable.
* Scheme not included.
*/
function get_hostname(bool $include_port = true) {
return url_get_base($this->base_url, include_scheme: false, include_port: $include_port);
return url_get_base(
$this->base_url,
include_scheme: false,
include_port: $include_port
);
}
/**
@ -1232,7 +1291,9 @@
}
/**
* Returns the URL to the endpoint listing this server's rooms.
* Returns the URL to the endpoint describing this server's rooms.
*
* @return string
*/
function get_rooms_api_url(): string {
$base_url = $this->base_url;
@ -1240,7 +1301,11 @@
}
/**
* Returns the URL for the endpoint of the particular room.
* Returns the URL for the endpoint describing a particular room.
*
* @param string $token Token of Community to construct URL.
*
* @return string
*/
function get_room_api_url(string $token): string {
$base_url = $this->base_url;
@ -1318,12 +1383,19 @@
return $pubkey_prefix . $hostname_hash_prefix;
}
/**
* Return string value used to sort Communities by host.
*
* @return string
*/
public function get_server_sort_key(): string {
return $this->get_pubkey() . $this->get_hostname();
}
/**
* Returns the room of the given token, or null if one does not exist.
* @param string $token The string token of a room on the server.
* @return CommunityRoom|null
*/
function get_room_by_token(string $token): CommunityRoom | null {
$candidates = array_filter($this->rooms, function(CommunityRoom $room) use ($token) {
@ -1577,7 +1649,14 @@
return true;
}
/**
* Construct full-fledged Community objects if the public key is available.
* @return void
*/
public function construct_rooms() {
if (!$this->has_pubkey()) {
throw new Error("Cannot construct rooms before pubkey is fetched");
}
$this->rooms = CommunityRoom::from_details_array(
$this,
$this->_intermediate_room_data
@ -1585,7 +1664,9 @@
}
/**
* @return CommunityServer[]
* Deserialize Community servers from the given JSON file.
* @param string $file Path to JSON file containing fetched server data.
* @return CommunityServer[] Array of Session Open Group servers.
*/
public static function read_servers_from_file(string $file): array {
// Read the server data from disk.

@ -22,8 +22,12 @@
}
/**
* Create new instance of SDIRCommunitySource on the given source text.
* Create new instance of SDIRCommunitySource.
* Returns false if processing the source fails.
*
* @param string $contents Text from Session.directory to process.
*
* @return SDIRCommunitySource|false
*/
public static function from_contents(string $contents): SDIRCommunitySource | false {
$source = new SDIRCommunitySource($contents);
@ -142,8 +146,13 @@
private array $tags = [];
/**
* Attempt to create an ASGLCommunitySource instance on the given source text.
* Attempt to create an ASGLCommunitySource instance.
*
* Returns false if processing the source fails.
*
* @param string $contents Text from ASGL to process.
*
* @return ASGLCommunitySource|false
*/
public static function from_contents(string $contents): ASGLCommunitySource | false {
$source = new ASGLCommunitySource($contents);

@ -75,10 +75,16 @@
return html_sanitize($this->get_text());
}
public static $descriptions = [];
/**
* @var string[] $descriptions
* Dictionary of reserved tag descriptions.
*/
public static array $descriptions = [];
/**
* Return tag description.
* Return the tag's description.
*
* @return string
*/
public function get_description_sanitized(): string {
// Feels out-of-place anywhere else.
@ -89,15 +95,34 @@
return html_sanitize(CommunityTag::$descriptions[$this->text] ?? "Tag: $this->text");
}
/**
* Associate the current tag's text with the given description.
*
* @param string $description New description for the current tag text.
*
* @return CommunityTag Return self.
*/
public function set_description_globally(string $description): self {
CommunityTag::$descriptions[$this->text] = $description;
return $this;
}
public static function serializeClassData() {
/**
* Serialize tag data into a string.
*
* @return string JSON data
*/
public static function serializeClassData(): string {
return json_encode(CommunityTag::$descriptions);
}
/**
* Load tag data from the given serialized string.
*
* @param string $data JSON string of tag descriptions.
*
* @return void
*/
public static function loadSerializedClassData(string $data) {
CommunityTag::$descriptions = json_decode($data, associative: true);
}
@ -258,9 +283,18 @@
private const REDUNDANT_TAGS = [];
/**
* @var string[] NSFW_KEYWORDS
* Keywords indicating a not-safe-for-work Community.
*/
public const NSFW_KEYWORDS = ["nsfw", "porn", "erotic", "18+", "sex"];
/**
* Check whether the given user tag is reserved by our aggregator.
*
* @param string $tag String tag to check.
*
* @return bool
*/
public static function is_reserved_tag(string $tag): bool {
return in_array(strtolower($tag), CommunityTag::RESERVED_TAGS);
@ -268,6 +302,10 @@
/**
* Return true if the tag should be given a chance to appear in more crowded views.
*
* @param string $tag String tag to check.
*
* @return bool
*/
public static function is_showcased_tag(string $tag): bool {
return in_array(strtolower($tag), CommunityTag::SHOWCASED_TAGS);
@ -275,6 +313,10 @@
/**
* Return true if the tag should be given visibility in more crowded views.
*
* @param string $tag String tag to check.
*
* @return bool
*/
public static function is_highlighted_tag(string $tag): bool {
return in_array(strtolower($tag), CommunityTag::HIGHLIGHTED_TAGS);
@ -285,7 +327,12 @@
* Constructs Community tags reserved by the aggregator.
*/
class ReservedTags {
public static function official() {
/**
* Return "official" reserved Community tag.
*
* @return CommunityTag
*/
public static function official(): CommunityTag {
$CHECK_MARK = "✅";
return (new CommunityTag(
@ -294,7 +341,12 @@
))->set_description_globally("This Community is maintained by the Session team. $CHECK_MARK");
}
public static function nsfw() {
/**
* Return "nsfw" reserved Community tag.
*
* @return CommunityTag
*/
public static function nsfw(): CommunityTag {
$WARNING_ICON = "⚠️";
return (new CommunityTag(
@ -303,7 +355,12 @@
))->set_description_globally("This Community may contain adult material. $WARNING_ICON");
}
public static function moderated() {
/**
* Return "moderated" reserved Community tag.
*
* @return CommunityTag
*/
public static function moderated(): CommunityTag {
$CHECK_MARK = "✅";
return (new CommunityTag(
@ -312,7 +369,12 @@
))->set_description_globally("This Community seems to have enough moderators. $CHECK_MARK");
}
public static function not_modded() {
/**
* Return "not_modded" reserved Community tag.
*
* @return CommunityTag
*/
public static function not_modded(): CommunityTag {
$WARNING_ICON = "⚠️";
return (new CommunityTag(
@ -321,28 +383,48 @@
))->set_description_globally("This Community does not seem to have enough moderators. $WARNING_ICON");
}
public static function read_only() {
/**
* Return "read_only" reserved Community tag.
*
* @return CommunityTag
*/
public static function read_only(): CommunityTag {
return (new CommunityTag(
"read-only",
TagType::RESERVED_TAG,
))->set_description_globally("This Community is read-only.");
}
public static function no_upload_permission() {
/**
* Return "no_upload_permission" reserved Community tag.
*
* @return CommunityTag
*/
public static function no_upload_permission(): CommunityTag {
return (new CommunityTag(
"uploads off",
TagType::RESERVED_TAG,
))->set_description_globally("This Community does not support uploading files or link previews.");
}
public static function recently_created() {
/**
* Return "recently_created" reserved Community tag.
*
* @return CommunityTag
*/
public static function recently_created(): CommunityTag {
return (new CommunityTag(
"new",
TagType::RESERVED_TAG,
))->set_description_globally("This Community was created recently.");
}
public static function used_by_project() {
/**
* Return "used_by_project" reserved Community tag.
*
* @return CommunityTag
*/
public static function used_by_project(): CommunityTag {
return (new CommunityTag(
"we're here",
TagType::RESERVED_TAG,
@ -350,14 +432,24 @@
. "or respond to feedback in this Community.");
}
public static function testing() {
/**
* Return "testing" reserved Community tag.
*
* @return CommunityTag
*/
public static function testing(): CommunityTag {
return (new CommunityTag(
"test",
TagType::RESERVED_TAG,
))->set_description_globally("This Community is intended for testing only.");
}
public static function stickied() {
/**
* Return "stickied" reserved Community tag.
*
* @return CommunityTag
*/
public static function stickied(): CommunityTag {
return (new CommunityTag(
"pinned",
TagType::RESERVED_TAG,

@ -42,7 +42,8 @@
* Create a new FetchingCoroutine to fetch the contents of a URL.
* @param string $url URL to fetch.
* @param array $curlopts Addition cURL options.
* @return FetchingCoroutine<CurlHandle|false> Coroutine returning
* @return FetchingCoroutine<CurlHandle|false>
* Coroutine returning 1) fulfilled cURL handle, or 2) false in case of failure.
*/
public static function from_url(string $url, array $curlopts = []): FetchingCoroutine {
/**
@ -234,7 +235,7 @@
/**
* Step coroutine with network result until next yield point.
* Coroutine must not have been consumed by any transformations.
* @param CurlHandle|false $response
* @param CurlHandle|false $response_handle
* cURL handle containing fetch result or false in case of failure.
* @return bool True if response was accepted by coroutine, false otherwise.
*/

@ -6,32 +6,61 @@
include_once 'utils/logging.php';
// Read the -v|--verbose option increasing logging verbosity to debug.
/**
* @var array $options
* List of options parsed from the command-line.
*/
$options = getopt("vn", ["verbose", "fast", "no-color", "dry-run", "archive"]);
if (isset($options["v"]) or isset($options["verbose"])) {
/**
* @var int $LOGGING_VERBOSITY
* Highest verbosity to display in logs.
*/
$LOGGING_VERBOSITY = LoggingVerbosity::Debug;
}
/**
* @var bool $FAST_FETCH_MODE
* If true, be less patient when polling servers.
*/
$FAST_FETCH_MODE = (isset($options["fast"]));
/**
* @var bool $DO_DRY_RUN
* If true, do not overwrite fetched server data.
*/
$DO_DRY_RUN = (isset($options["n"]) || isset($options["dry-run"]));
if (isset($options["no-color"])) {
LoggingVerbosity::$showColor = false;
}
/**
* @var bool $DO_ARCHIVE_FILES
* If true, archive fetched server data.
*/
$DO_ARCHIVE_FILES = isset($options["archive"]);
// set timeout for file_get_contents()
ini_set('default_socket_timeout', 6); // in seconds, default is 60
// curl timeout in milliseconds
// max time for initiation of the connection
/**
* @var int $CURL_CONNECT_TIMEOUT_MS
* Maximum time to initiate connection.
*/
$CURL_CONNECT_TIMEOUT_MS = 2000;
// max time for each connection (incl. transfer)
/**
* @var int $CURL_TIMEOUT_MS
* Maximum time for each connection, including transfer.
*/
$CURL_TIMEOUT_MS = $FAST_FETCH_MODE ? 3000 : 9000;
// delay between retries in milliseconds
/**
* @var int $CURL_RETRY_SLEEP
* Delay between fetch retries in milliseconds.
*/
$CURL_RETRY_SLEEP = 2000;
?>

@ -23,9 +23,21 @@
// Prevent class instantiation
private function __construct() {}
/**
* Error log verbosity constant.
*/
const Error = 10;
/**
* Warning log verbosity constant.
*/
const Warning = 20;
/**
* Info log verbosity constant.
*/
const Info = 30;
/**
* Debug log verbosity constant.
*/
const Debug = 40;
/**
@ -118,6 +130,9 @@
);
}
/**
* @private
*/
function _log_message(?string $msg, int $message_verbosity) {
global $LOGGING_VERBOSITY;
if ($message_verbosity > $LOGGING_VERBOSITY) return;
@ -169,7 +184,8 @@
/**
* Logs the given value in a debug message to stderr.
* Only logs when `$LOGGING_VERBOSITY` is debug and below.
* @param string $msg String message to log.
* @param mixed $value Value to log.
* @param int $message_verbosity Verbosity to use when logging value. Default: Debug.
*/
function log_value(mixed $value, int $message_verbosity = LoggingVerbosity::Debug) {
_log_message(var_export($value, true), $message_verbosity);

@ -4,26 +4,68 @@
* Provides site generation context variables.
*/
class SiteGeneration {
public static function getCanonicalPageURL() {
/**
* Get the absolute web path to the current document, omitting the final 'index.html'.
*
* @return string
*/
public static function getCanonicalPageURL(): string {
global $SITE_CANONICAL_URL;
return dirname($SITE_CANONICAL_URL.getenv('SSG_TARGET')) . '/';
}
public static function getAbsoluteSourceDocumentPath() {
/**
* Get the absolute source path of the current document.
*
* @return string
*/
public static function getAbsoluteSourceDocumentPath(): string {
return $_SERVER['SCRIPT_NAME'];
}
public static function getTargetDocumentPath() {
/**
* Get the relative web path of the current document.
*
* @return string
*/
public static function getTargetDocumentPath(): string {
return getenv('SSG_TARGET');
}
public static function getTargetDocumentRoute() {
/**
* Get the directory above the current document's web location.
*
* Returns the path to the directory in which the current document
* will be served, relative to the webroot.
*
* Usage:
* ```php
* // Generating /index.php
* SiteGeneration::getTargetDocumentRoute() // -> '/'
*
* // Generating /privacy/index.php
* SiteGeneration::getTargetDocumentRoute() // -> '/privacy'
* ```
*
* @return string Path to the directory serving the current document.
*/
public static function getTargetDocumentRoute(): string {
return dirname(SiteGeneration::getTargetDocumentPath());
}
public static function getOwnSubDocumentPath(string $identifier) {
/**
* Return the path of a subdocument of the current document.
*
* When generating "index.php", this function will return
* "+index.head.php" when given a subdocument identifier of "head".;
*
* @param string $subdocument Subdocument identifier.
* @return string Absolute source path of subdocument "+current.subdocument.php"
*/
public static function getOwnSubDocumentPath(string $subdocument) {
$page = SiteGeneration::getAbsoluteSourceDocumentPath();
$sub_document = dirname($page) . '/+' . preg_replace('/[.]php$/', ".$identifier.php", basename($page));
$sub_document = dirname($page) . '/+' . preg_replace('/[.]php$/', ".$subdocument.php", basename($page));
return $sub_document;
}
}

@ -4,6 +4,10 @@
* Implement basic utility functions.
*/
/**
* @var string $REGEX_JOIN_LINK
* Regular expression matching Session Community join links.
*/
$REGEX_JOIN_LINK = (function(){
// See https://github.com/oxen-io/session-pysogs/blob/dev/administration.md
$protocol = 'https?:';
@ -47,7 +51,14 @@
return $truncated;
}
function make_curl_handle(string $url, $curlopts = []) {
/**
* Constructs a cURL handle for performing network requests.
*
* @param string $url Target resource to fetch.
* @param array $curlopts Associative array of cURL options. (optional)
* @return CurlHandle
*/
function make_curl_handle(string $url, $curlopts = []): CurlHandle {
global $CURL_CONNECT_TIMEOUT_MS, $CURL_TIMEOUT_MS;
$curl = curl_init($url);
@ -70,7 +81,8 @@
/**
* Downgrades a HTTPS-facing cURL handle to HTTP.
* @return CurlHandle|null Handle copy if can downgrade, or null if not applicable.
* @param CurlHandle $handle cURL handle.
* @return CurlHandle|null Handle copy, or null if not applicable.
*/
function curl_handle_downgrade(CurlHandle $handle): CurlHandle|null {
$url = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
@ -87,7 +99,7 @@
* @param string $url The URL to slice the path from.
* @param bool $include_scheme [optional]
* Includes the scheme. `true` by default.
* @param bool $include_scheme [optional]
* @param bool $include_port [optional]
* Includes the port. `true` by default.
* @return string A URL composed of the original scheme (unless specified),
* hostname, and port (if present).
@ -142,10 +154,10 @@
/**
* Extracts join links that match $REGEX_JOIN_LINK.
* @param ?string $html Text to find join URLs in.
* @param string $html Text to find join URLs in.
* @return string[] Sorted array of unique server join links.
*/
function parse_join_links(?string $html){
function parse_join_links(?string $html): array {
global $REGEX_JOIN_LINK;
preg_match_all($REGEX_JOIN_LINK, $html, $match_result);
$links = $match_result[0];
@ -159,8 +171,9 @@
* @param string $str String to sanitize
* @param int $flags [optional]
* A bitmask of one or more of the following flags,
* which specify how to handle quotes, invalid code unit sequences
* which specify how to handle quotes, invalid code unit sequences
* and the used document type. The default is ENT_COMPAT | ENT_HTML401.
* @param string $encoding Character encoding used. [optional]
* @param bool $double_encode [optional]
* When double_encode is turned off, PHP will not encode
* existing html entities, the default is to convert everything.
@ -176,6 +189,13 @@
return htmlspecialchars($str, $flags, $encoding, $double_encode);
}
/**
* Return the sign of the given number.
*
* @param float $num Floating-point number.
*
* @return int -1 if negative, 1 if positive, 0 otherwise
*/
function sign(float $num): int {
return ($num > 0) - ($num < 0);
}

@ -11,6 +11,10 @@
* @var CommunityRoom[] $rooms
*/
/**
* @var array $json_ld_data
* Associative data about the site in JSON-LD format.
*/
$json_ld_data = array(
'@context' => 'https://schema.org/',
'@id' => $SITE_CANONICAL_URL,

@ -11,7 +11,17 @@
// Set the last-updated timestamp
// to the time the server data file was last modified.
/**
* @var int $time_modified
* Timestamp of last Community data fetch.
*/
$time_modified = filemtime($ROOMS_FILE);
/**
* @var string $time_modified_str
* Timestamp of last Community data fetch.
*/
$time_modified_str = date("Y-m-d H:i:s", $time_modified);
?>

@ -10,14 +10,23 @@
/**
* Filters Session Communities.
*
* RoomSieve methods return copies when mutating the object.
* The stickied room list is preserved after filtering.
*/
class RoomSieve {
/**
* Communities stored.
*
* @var CommunityRoom[] $rooms;
*/
private array $rooms;
/**
* Pinned Communities, set aside.
*
* Not affected by filters.
*
* @var CommunityRoom[] $stickied
*/
private array $stickies;
@ -31,53 +40,104 @@
$this->stickies = $stickied;
}
/**
* Default limit for number of Communities.
*
* Applies only to certain functions.
*/
public const TOP_DEFAULT = 35;
/**
* Create new RoomSieve from the given Communities.
*
* @param CommunityRoom[] $rooms
*
* @return RoomSieve
*/
public static function takeRooms(array $rooms) {
public static function takeRooms(array $rooms): RoomSieve {
return new RoomSieve($rooms);
}
public function saveStickies() {
/**
* Set aside pinned Communities from the main list.
*
* @return RoomSieve
*/
public function saveStickies(): self {
$stickied = CommunityRoom::get_stickied_rooms($this->rooms, $rest);
$rooms = $rest;
return $this->cloneWith($rooms, $stickied);
}
/**
* Add the given Communities to a new RoomSieve.
*
* @param CommunityRoom[] $rooms
*
* @return RoomSieve
*/
public function addRooms(array $rooms) {
public function addRooms(array $rooms): RoomSieve {
return $this->cloneWith(array_merge($this->rooms, $rooms));
}
public function apply(Closure $filter) {
/**
* Use a custom filter for Communities.
*
* Creates a new RoomSieve with all Communities that passed the filter.
*
* @param Closure $filter Function which takes an array of Communities and returns an array of Communities.
*
* @return RoomSieve
*/
public function apply(Closure $filter): RoomSieve {
return $this->cloneWith($filter($this->rooms));
}
public function getWithStickies() {
/**
* Return all stored Communities, including pinned Communities.
*
* @return CommunityRoom[]
*/
public function getWithStickies(): array {
return [...$this->stickies, ...$this->rooms];
}
public function getWithoutStickies() {
return $this->saveStickies()->getRooms();
}
public function getRooms() {
return $this->rooms;
/**
* Return stored Communities without pinned Communities.
*
* @return CommunityRoom[]
*/
public function getWithoutStickies(): array {
return $this->saveStickies()->rooms;
}
public function onlyTop(int $count = RoomSieve::TOP_DEFAULT) {
/**
* Only keep the top N active Communities.
*
* Does not affect stickied Communities.
*
* @param int $count Number of top Communities to keep. (optional)
*
* @return RoomSieve
*/
public function onlyTop(int $count = RoomSieve::TOP_DEFAULT): RoomSieve {
$rooms = $this->rooms;
CommunityRoom::sort_rooms_num($rooms, 'active_users', reverse: true);
CommunityRoom::sort_rooms_num($rooms, 'active_users', descending: true);
return $this->cloneWith(array_slice($rooms, 0, $count));
}
public function exceptTop(int $count = RoomSieve::TOP_DEFAULT) {
/**
* Remove the top N active Communities.
*
* Does not affect stickied Communities.
*
* @param int $count Number of top Communities to remove. (optional)
*
* @return RoomSieve
*/
public function exceptTop(int $count = RoomSieve::TOP_DEFAULT): RoomSieve {
$rooms = $this->rooms;
CommunityRoom::sort_rooms_num($rooms, 'active_users', reverse: true);
CommunityRoom::sort_rooms_num($rooms, 'active_users', descending: true);
return $this->cloneWith(array_slice($rooms, $count));
}
@ -90,14 +150,26 @@
);
}
public function applyStandardSort() {
/**
* Sort Communities by name and server.
*
* @return RoomSieve
*/
public function applyStandardSort(): RoomSieve {
$rooms = $this->rooms;
CommunityRoom::sort_rooms_str($rooms, 'name');
CommunityRoom::sort_rooms_by_server($rooms);
return new RoomSieve($rooms, $this->stickies);
}
public function applyPreferentialSort() {
/**
* Sort Communities by staff rating.
*
* Communities with a description are also preferred.
*
* @return RoomSieve
*/
public function applyPreferentialSort(): RoomSieve {
$rooms = $this->rooms;
CommunityRoom::sort_rooms_num($rooms,'created');
usort($rooms, function($a, $b) {
@ -109,14 +181,24 @@
return new RoomSieve(array_reverse($rooms), $this->stickies);
}
public function indexApproved() {
/**
* Keep only Communities heuristically deemed to be appropriate.
*
* @return RoomSieve
*/
public function indexApproved(): RoomSieve {
$rooms = array_values(array_filter($this->rooms, function($room) {
return RoomSieve::isIndexApproved($room);
}));
return new RoomSieve($rooms, $this->stickies);
}
public function indexNonApproved() {
/**
* Remove Communities heuristically deemed to be appropriate.
*
* @return RoomSieve
*/
public function indexNonApproved(): RoomSieve {
$rooms = array_values(array_filter($this->rooms, function($room) {
return !RoomSieve::isIndexApproved($room);
}));

@ -9,7 +9,16 @@
require_once 'php/servers/room-database.php';
require_once 'sites/_fragment/+room-sieve.php';
/**
* @var CommunityDatabase $room_database
* Database of fetched servers and Communities.
*/
$room_database = CommunityDatabase::read_from_file($ROOMS_FILE)->fetch_assets();
/**
* @var CommunityRoom[] $rooms
* Communities shown on page by default.
*/
$rooms =
RoomSieve::takeRooms($room_database->rooms)
->saveStickies()

@ -6,18 +6,47 @@
require_once '+getenv.php';
/**
* @var string[] $instruction_files
* List of all files containing localized site instructions.
*/
$instruction_files = glob("+instructions/*.txt");
/**
* Get the language name of the given localized file.
*
* @param string $file File containing site instructions.
*
* @return string
*/
function file_language($file) {
$filename = pathinfo($file)['filename'];
return explode(" ", $filename)[0];
}
/**
* Get the language code of the given localized file.
*
* @param string $file File containing site instructions.
*
* @return string
*/
function file_language_code($file) {
$filename = pathinfo($file)['filename'];
$code_in_brackets = explode(" ", $filename)[1];
return mb_substr($code_in_brackets, 1, mb_strlen($code_in_brackets) - 2);
}
/**
* @var string $languages
* List of languages in which instructions are available.
*/
$languages = array_map('file_language', array_slice($instruction_files, 0, 10));
/**
* @var string $language_enumeration
* Enumerated list of languages with available instructions.
*/
$language_enumeration = join(", ", $languages);
?>
<!DOCTYPE html>
@ -71,6 +100,10 @@
// Sanitization as second layer of protection
// for user-submitted instruction files.
// Should not ever have to be used.
/**
* @var string $content
* Instructions file contents.
*/
$content = trim(file_get_contents($file));
$content = htmlentities($content);
// Minimal formatting so that contributions are easier

@ -8,6 +8,10 @@
require_once '+getenv.php';
/**
* @var string[] $HIGHLIGHTED_FIELDS
* List of interactive server log entries.
*/
$HIGHLIGHTED_FIELDS = ["ip", "datetime", "resource", "status", "bytes", "referer", "user-agent"];
?>
<!DOCTYPE html>

@ -6,8 +6,20 @@
*/
require_once '+getenv.php';
/**
* Generate sitemap fragment containing page location and last modified time.
*
* Only works for pages named "index.php".
*
* @param string $rel_loc Canonical webpage location relative to webroot.
* @param string $changes_under_root The directory to check (source or output) to infer file modification time.
* Typically {@link $DOCUMENT_ROOT} to detect new versions of files with updating content
* and {@link $TEMPLATES_ROOT} for articles which only substantially change on source change.
*
* @return void
*/
function loc_lastmod(string $rel_loc, ?string $changes_under_root = null) {
global $SITE_CANONICAL_URL, $DOCUMENT_ROOT, $TEMPLATES_ROOT;
global $SITE_CANONICAL_URL, $TEMPLATES_ROOT;
$root = $changes_under_root ?? $TEMPLATES_ROOT;
$ext = ($root == $TEMPLATES_ROOT) ? "php" : "html";
?>

@ -6,11 +6,31 @@
require_once '+getenv.php';
/**
* Number of background particles.
* @var int $NUM_PARTICLES
*/
$NUM_PARTICLES = 20;
/**
* @var int[] $DELAYS
* Time delays for background particles to appear.
*/
$DELAYS = range(0, 240 - 1, 240 / $NUM_PARTICLES);
shuffle($DELAYS);
/**
* @var string[] $PARTICLES
* Array of available background particles.
*/
$PARTICLES = explode(" ", "$ 💵 💰 💸 💯");
function random_particle() {
/**
* Pick random particle.
*
* @return string
*/
function random_particle(): string {
global $PARTICLES;
$r = rand(0, count($PARTICLES) - 1);
return $PARTICLES[$r];

Loading…
Cancel
Save