|  |  |  | <?php | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * \file | 
					
						
							|  |  |  | 	 * Implement Community listings for the [Listing Provider API](https://codeberg.org/gravel/session-listing-providers). | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require_once "getenv.php"; | 
					
						
							|  |  |  | 	require_once "utils/logging.php"; | 
					
						
							|  |  |  | 	require_once "servers/servers-rooms.php"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Represents a Community listing in the Listing Provider API. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	class CommunityListing implements JsonSerializable { | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @var string $id | 
					
						
							|  |  |  | 		 * Unique listing identifier. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public readonly string $id; | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @var string $name | 
					
						
							|  |  |  | 		 * Human-readable listing name. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public readonly string $name; | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @var string $rating | 
					
						
							|  |  |  | 		 * One-word content rating for Communities listed. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public readonly string $rating; | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @var CommunityRoom[] $rooms | 
					
						
							|  |  |  | 		 * Communities included in the listing. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public readonly array $rooms; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Create a new CommunityListing instance with the given parameters. | 
					
						
							|  |  |  | 		 * @param string $id Unique listing identifier. | 
					
						
							|  |  |  | 		 * @param string $name Human-readable listing name. | 
					
						
							|  |  |  | 		 * @param string $rating One-word content rating for Communities listed. | 
					
						
							|  |  |  | 		 * @param CommunityRoom[] $rooms Communities included in the listing. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public function __construct(string $id, string $name, ?string $rating, array $rooms) { | 
					
						
							|  |  |  | 			$this->id = $id; | 
					
						
							|  |  |  | 			$this->name = $name; | 
					
						
							|  |  |  | 			$this->rating = $rating ?? "unknown"; | 
					
						
							|  |  |  | 			$this->rooms = $rooms; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Produce associative listing data for JSON serialization. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public function jsonSerialize(): mixed { | 
					
						
							|  |  |  | 			// TODO: Careful serialization | 
					
						
							|  |  |  | 			$details = get_object_vars($this); | 
					
						
							|  |  |  | 			$details['rooms'] = array_map(function(CommunityRoom $room){ | 
					
						
							|  |  |  | 				return $room->to_listing_data(); | 
					
						
							|  |  |  | 			}, $this->rooms); | 
					
						
							|  |  |  | 			return $details; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * Produce associative data summarizing this listing. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		public function to_summary(): array { | 
					
						
							|  |  |  | 			return array( | 
					
						
							|  |  |  | 				'id' => $this->id, | 
					
						
							|  |  |  | 				'name' => $this->name, | 
					
						
							|  |  |  | 				'rating' => $this->rating, | 
					
						
							|  |  |  | 				'rooms' => count($this->rooms) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Construct Community listings from listing configuration and cached Communities. | 
					
						
							|  |  |  | 	 * @return CommunityListing[] | 
					
						
							|  |  |  | 	 * \todo Refactor | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	function resolve_listings_config(): array { | 
					
						
							|  |  |  | 		global $LISTINGS_INI, $ROOMS_FILE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		$listings_raw = parse_ini_file($LISTINGS_INI, process_sections: true, scanner_mode: INI_SCANNER_RAW); | 
					
						
							|  |  |  | 		$servers_raw = file_get_contents($ROOMS_FILE); | 
					
						
							|  |  |  | 		$server_data = json_decode($servers_raw, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		$servers = CommunityServer::from_details_array($server_data); | 
					
						
							|  |  |  | 		$rooms_all = CommunityServer::enumerate_rooms($servers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		$listings = []; | 
					
						
							|  |  |  | 		foreach ($listings_raw as $id => $listing_props) { | 
					
						
							|  |  |  | 			$filter = [...($listing_props['rooms'] ?? []), ...($listing_props['sogs'] ?? [])]; | 
					
						
							|  |  |  | 			$matchees = []; | 
					
						
							|  |  |  | 			$rooms = CommunityRoom::select_rooms($rooms_all, $filter, $matchees); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			foreach ($filter as $filter_item) { | 
					
						
							|  |  |  | 				if (!in_array($filter_item, $matchees)) { | 
					
						
							|  |  |  | 					log_warning("Could not find $filter_item from listing $id."); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$rooms = array_filter($rooms, function(CommunityRoom $room) { | 
					
						
							|  |  |  | 				return !$room->is_off_record(); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$listings[] = new CommunityListing( | 
					
						
							|  |  |  | 				$id, | 
					
						
							|  |  |  | 				$listing_props['name'], | 
					
						
							|  |  |  | 				$listing_props['rating'], | 
					
						
							|  |  |  | 				$rooms | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return $listings; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Resolve and write configured Community listings to disk. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	function generate_listings() { | 
					
						
							|  |  |  | 		global $LISTING_PROVIDER_LISTING_SUMMARY, $LISTING_PROVIDER_LISTINGS; | 
					
						
							|  |  |  | 		log_info("Generating listings..."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		$listings_resolved = resolve_listings_config(); | 
					
						
							|  |  |  | 		$summaries = array_map(function(CommunityListing $listing) { | 
					
						
							|  |  |  | 			return $listing->to_summary(); | 
					
						
							|  |  |  | 		}, $listings_resolved); | 
					
						
							|  |  |  | 		file_put_contents($LISTING_PROVIDER_LISTING_SUMMARY, json_encode($summaries)); | 
					
						
							|  |  |  | 		foreach ($listings_resolved as $listing) { | 
					
						
							|  |  |  | 			$id = $listing->id; | 
					
						
							|  |  |  | 			file_put_contents( | 
					
						
							|  |  |  | 				"$LISTING_PROVIDER_LISTINGS/$id", | 
					
						
							|  |  |  | 				json_encode($listing) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		$listings_count = count($listings_resolved); | 
					
						
							|  |  |  | 		log_info("Generated $listings_count listings."); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file_exists($LISTING_PROVIDER_LISTINGS) or mkdir($LISTING_PROVIDER_LISTINGS, 0755, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	$options = getopt("v", ["verbose"]); | 
					
						
							|  |  |  | 	if (isset($options["v"]) or isset($options["verbose"])) { | 
					
						
							|  |  |  | 		$LOGGING_VERBOSITY = LoggingVerbosity::Debug; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	generate_listings(); | 
					
						
							|  |  |  | ?> |