- Full gg.deals-style UI: deal feed with filters, game pages with price history charts, rankings, vouchers, news, prepaids, subscriptions, bundles, franchises, wishlist, API docs - Real data crawlers: * gg:crawl (Steam Store API + GOG Catalog + Epic free games) * gg:catalog (252K game slugs from gg.deals sitemaps) * gg:ggdeals (per-game prices via FlareSolverr session, JSON-LD parsing) * gg:seed / gg:crawl-covers (demo seed + Steam CDN cover art) - 24/7 self-updating scheduler (scripts/scheduler_loop.php, lockfile-protected) - Tailwind v4 dark/light theme, Alpine.js, Chart.js
62 lines
1.4 KiB
PHP
62 lines
1.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Libraries;
|
|
|
|
use MongoDB\Client;
|
|
use MongoDB\Database;
|
|
|
|
/**
|
|
* Shared MongoDB connection wrapper.
|
|
*/
|
|
final class Mongo
|
|
{
|
|
private static ?Database $db = null;
|
|
|
|
public static function db(): Database
|
|
{
|
|
if (self::$db === null) {
|
|
$db = env('MONGO_DB', 'ggdeals');
|
|
|
|
$client = new Client(
|
|
self::uri(),
|
|
[],
|
|
[
|
|
'typeMap' => [
|
|
'root' => 'array',
|
|
'document' => 'array',
|
|
'array' => 'array',
|
|
],
|
|
]
|
|
);
|
|
|
|
self::$db = $client->selectDatabase($db);
|
|
}
|
|
|
|
return self::$db;
|
|
}
|
|
|
|
private static function uri(): string
|
|
{
|
|
$uri = env('MONGO_URI');
|
|
if (is_string($uri) && $uri !== '') {
|
|
return $uri;
|
|
}
|
|
|
|
$host = env('MONGO_HOST', 'harness-mongo');
|
|
$port = env('MONGO_PORT', '27017');
|
|
$user = (string) env('MONGO_USER', '');
|
|
$pass = (string) env('MONGO_PASS', '');
|
|
|
|
$auth = $user !== '' ? urlencode($user) . ':' . urlencode($pass) . '@' : '';
|
|
|
|
return "mongodb://{$auth}{$host}:{$port}/?authSource=admin";
|
|
}
|
|
|
|
public static function collection(string $name): \MongoDB\Collection
|
|
{
|
|
return self::db()->selectCollection($name);
|
|
}
|
|
}
|