1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries;
7
8use App\Models\Wiki\WikiObject;
9use Exception;
10use Symfony\Component\Yaml\Yaml;
11
12class WikiRedirect implements WikiObject
13{
14 const CACHE_DURATION = 1 * 60 * 60;
15 const CACHE_KEY = 'wiki:redirect:v2';
16
17 private $cache;
18
19 public function __construct()
20 {
21 $this->fetchCache();
22 }
23
24 public function fetchCache()
25 {
26 $this->cache = cache()->get(static::CACHE_KEY);
27 }
28
29 public function getCache()
30 {
31 return $this->cache;
32 }
33
34 public function needsSync()
35 {
36 return $this->cache === null
37 || ($this->cache['cached_at'] + static::CACHE_DURATION) < time();
38 }
39
40 public function normalizePath($path)
41 {
42 return str_replace(' ', '_', strtolower($path));
43 }
44
45 public function resolve($path)
46 {
47 return $this->cache['redirect'][$this->normalizePath($path)] ?? null;
48 }
49
50 public function sync($force = false)
51 {
52 if (!$force && !$this->needsSync()) {
53 return $this;
54 }
55
56 $lock = cache()->lock(static::CACHE_KEY.':lock', 300);
57
58 // only one process may sync at once
59 if (!$lock->get()) {
60 return $this;
61 }
62
63 try {
64 $redirect = Yaml::parse(strip_utf8_bom(OsuWiki::fetchContent('wiki/redirect.yaml')));
65 } catch (Exception $e) {
66 log_error($e);
67
68 return $this;
69 } finally {
70 $lock->release();
71 }
72
73 $this->cache = [
74 'redirect' => $redirect ?? [],
75 'cached_at' => time(),
76 ];
77 cache()->put(static::CACHE_KEY, $this->cache);
78
79 return $this;
80 }
81}