the browser-facing portion of osu!
at master 107 lines 2.6 kB view raw
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\Models\Wiki; 7 8use App\Exceptions\GitHubNotFoundException; 9use App\Libraries\OsuWiki; 10use Exception; 11use Illuminate\Contracts\Cache\LockTimeoutException; 12 13class Image implements WikiObject 14{ 15 const CACHE_DURATION = 2 * 60 * 60; 16 17 public $path; 18 19 private $cache; 20 21 public function __construct($path) 22 { 23 $this->path = OsuWiki::cleanPath($path); 24 $this->cache = $this->fetchFromCache(); 25 } 26 27 public function cacheKey() 28 { 29 return 'wiki:image:data:v2:'.$this->path; 30 } 31 32 public function get() 33 { 34 return $this->cache['data'] ?? null; 35 } 36 37 public function isVisible() 38 { 39 return $this->get() !== null; 40 } 41 42 public function needsSync() 43 { 44 return $this->cache === null 45 || ($this->cache['cached_at'] + static::CACHE_DURATION) < time(); 46 } 47 48 public function sync($force = false) 49 { 50 if (!$force && !$this->needsSync()) { 51 return $this; 52 } 53 54 $cache = cache(); 55 $cacheKey = $this->cacheKey(); 56 $lock = $cache->lock($cacheKey.':lock', 300); 57 58 if (!$lock->get()) { 59 if ($this->cache !== null) { 60 return $this; 61 } 62 63 try { 64 $lock->block(10); 65 $lock->release(); 66 $this->cache = $this->fetchFromCache(); 67 68 return $this->sync($force); 69 } catch (LockTimeoutException $_e) { 70 // previous attempt is taking too long; try fetching the image anyway 71 } 72 } 73 74 try { 75 $content = OsuWiki::fetchContent('wiki/'.$this->path); 76 $type = image_type_to_mime_type( 77 read_image_properties_from_string($content)[2] ?? null 78 ); 79 80 $data = compact('content', 'type'); 81 } catch (GitHubNotFoundException $e) { 82 // do nothing and cache empty data 83 } catch (Exception $e) { 84 log_error($e); 85 $lock->release(); 86 87 return $this; 88 } 89 90 try { 91 $this->cache = [ 92 'data' => $data ?? null, 93 'cached_at' => time(), 94 ]; 95 $cache->put($cacheKey, $this->cache); 96 } finally { 97 $lock->release(); 98 } 99 100 return $this; 101 } 102 103 private function fetchFromCache(): ?array 104 { 105 return cache()->get($this->cacheKey()); 106 } 107}