PL
apps/caramail-server / src / Chat / RoomStore.php · commit 070afda
<?phpnamespace App\Chat;/** * The permanent rooms (and their last sentences), kept in one JSON file between two runs. The rest of the chat * (who is connected, the rooms people made) only lives while the server runs, as the original reset it at start. */final class RoomStore{    /** The 22 permanent rooms of the Caramail chat ("22 salons permanents"), "Salon" the room one enters first. */    public const DEFAULT_ROOMS = ['Salon', '10 - 15 ans', '15 - 20 ans', '20 - 25 ans', '25 - 30 ans', '30 - 35 ans', '35 - 40 ans',        '40 - 45 ans', '45 - 50 ans', 'plus de 50 ans', 'Belgique', 'Gay', 'Lesbiennes',        'Salon : 2', 'Salon : 3', 'Salon : 4', 'Salon : 5', 'Salon : 6', 'Salon : 7', 'Salon : 8', 'Salon : 9', 'Salon : 10'];    public function __construct(private readonly string $file)    {    }    public function file(): string    {        return $this->file;    }    /** @return list<Room> */    public function load(): array    {        $data = is_file($this->file) ? json_decode((string)file_get_contents($this->file), true) : null;        if (!is_array($data) || !isset($data['rooms']) || !is_array($data['rooms'])) {            return array_map(static fn (string $name) => new Room($name, 0, 'admin', true), self::DEFAULT_ROOMS);        }        $rooms = [];        foreach ($data['rooms'] as $row) {            if (!is_array($row) || !isset($row['name']) || trim((string)$row['name']) === '') {                continue;            }            $room = new Room((string)$row['name'], (int)($row['type'] ?? 0), (string)($row['creator'] ?? 'admin'), true, (int)($row['created'] ?? 0));            foreach ((array)($row['history'] ?? []) as $line) {                if (is_array($line) && isset($line['id'], $line['nickname'], $line['text'])) {                    $room->history[] = ['id' => (string)$line['id'], 'nickname' => (string)$line['nickname'], 'text' => (string)$line['text'], 'at' => (int)($line['at'] ?? 0)];                }            }            $room->history = array_slice($room->history, -Room::HISTORY);            $rooms[] = $room;        }        return $rooms;    }    /** @param iterable<Room> $rooms only the permanent ones are written */    public function save(iterable $rooms): void    {        $rows = [];        foreach ($rooms as $room) {            if ($room->permanent) {                $rows[] = ['name' => $room->name, 'type' => $room->type, 'creator' => $room->creator, 'created' => $room->createdAt, 'history' => $room->history];            }        }        $dir = dirname($this->file);        if (!is_dir($dir)) {            @mkdir($dir, 0775, true);        }        $tmp = $this->file . '.tmp';        file_put_contents($tmp, json_encode(['rooms' => $rows], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n");        rename($tmp, $this->file);    }    /** Adds (or removes) a permanent room in the file: the `rooms` command, while the server is stopped or before a restart. */    public function edit(string $name, bool $add): bool    {        $rooms = $this->load();        $key = Room::keyOf($name, 0);        $found = false;        foreach ($rooms as $i => $room) {            if ($room->key() === $key) {                $found = true;                if (!$add) {                    unset($rooms[$i]);                }            }        }        if ($add && !$found) {            $rooms[] = new Room($name, 0, 'admin', true);        }        $this->save($rooms);        return $add ? !$found : $found;    }}