db->selectCollection('service_wopi_files'); $files->updateOne(['_id' => $key], ['$setOnInsert' => [ 'tenant' => $tenant, 'user' => $user, 'resource' => $resource, 'file' => bin2hex(random_bytes(16)), ]], ['upsert' => true]); return $files->findOne(['_id' => $key])['file']; } public function save(string $token, array $session): void { $this->db->selectCollection('service_wopi_sessions')->insertOne([ '_id' => 'token:' . hash('sha256', $token), ...$session, ]); } public function find(string $tenant, string $file, string $token, int $now): ?array { return $this->db->selectCollection('service_wopi_sessions')->findOne([ '_id' => 'token:' . hash('sha256', $token), 'tenant' => $tenant, 'file' => $file, 'expires' => ['$gt' => $now], 'mode' => 'view', ]); } public function cached(string $tenant, string $server, int $now): ?string { $entry = $this->db->selectCollection('service_wopi_discovery')->findOne([ '_id' => $this->cacheKey($tenant, $server), 'expires' => ['$gt' => $now], ]); return $entry['xml'] ?? null; } public function cache(string $tenant, string $server, string $xml, int $expires): void { $this->db->selectCollection('service_wopi_discovery')->updateOne( ['_id' => $this->cacheKey($tenant, $server)], ['$set' => ['tenant' => $tenant, 'xml' => $xml, 'expires' => $expires]], ['upsert' => true], ); } public function cleanup(int $now): void { foreach (['service_wopi_sessions', 'service_wopi_discovery'] as $collection) { $this->db->selectCollection($collection)->deleteMany(['expires' => ['$lte' => $now]]); } } private function cacheKey(string $tenant, string $server): string { return 'discovery:' . hash('sha256', json_encode([$tenant, $server], JSON_THROW_ON_ERROR)); } }