diff --git a/app/Events/GetPlayerJson.php b/app/Events/GetPlayerJson.php new file mode 100644 index 00000000..5f6876f3 --- /dev/null +++ b/app/Events/GetPlayerJson.php @@ -0,0 +1,38 @@ +player = $player; + $this->api_type = $api_type; + } + + /** + * Get the channels the event should be broadcast on. + * + * @return array + */ + public function broadcastOn() + { + return []; + } +} diff --git a/app/Events/PlayerProfileUpdated.php b/app/Events/PlayerProfileUpdated.php new file mode 100644 index 00000000..f02f385d --- /dev/null +++ b/app/Events/PlayerProfileUpdated.php @@ -0,0 +1,34 @@ +player = $player; + } + + /** + * Get the channels the event should be broadcast on. + * + * @return array + */ + public function broadcastOn() + { + return []; + } +} diff --git a/app/Http/Controllers/PlayerController.php b/app/Http/Controllers/PlayerController.php index 2c770208..a7e723ee 100644 --- a/app/Http/Controllers/PlayerController.php +++ b/app/Http/Controllers/PlayerController.php @@ -79,7 +79,7 @@ class PlayerController extends BaseController public function show() { - echo json_encode($this->player->model->toArray(), JSON_NUMERIC_CHECK); + return json_encode($this->player->model->toArray(), JSON_NUMERIC_CHECK); } public function rename() @@ -121,9 +121,7 @@ class PlayerController extends BaseController $field_name = "tid_".$texture->type; - $this->player->model->$field_name = $tid; - $this->player->model->last_modified = Utils::getTimeFormatted(); - $this->player->model->save(); + $this->player->setTexture([$field_name => $tid]); View::json('材质已成功应用至角色 '.$this->player->model->player_name.'', 0); } diff --git a/app/Http/Controllers/TextureController.php b/app/Http/Controllers/TextureController.php index 9d60d8f2..e793f48c 100644 --- a/app/Http/Controllers/TextureController.php +++ b/app/Http/Controllers/TextureController.php @@ -20,21 +20,20 @@ class TextureController extends BaseController public function json($player_name, $api = "") { - // FUCKING CHINESE PLAYER NAME - // I DONT WANT TO IMPLEMENT IT AT ALL - $player_name = Option::get('allow_chinese_playername') ? $GLOBALS['player_name'] : $player_name; - $player = new Player(0, $player_name); if ($player->is_banned) Http::abort(404, '该角色拥有者已被本站封禁。'); if ($api == "csl") { - echo $player->getJsonProfile(0); + return response($player->getJsonProfile(Player::CSL_API)) + ->header('Content-type', 'application/json'); } else if ($api == "usm") { - echo $player->getJsonProfile(1); + return response($player->getJsonProfile(Player::USM_API)) + ->header('Content-type', 'application/json'); } else if ($api == "") { - echo $player->getJsonProfile(Option::get('api_type')); + return response($player->getJsonProfile(Option::get('api_type'))) + ->header('Content-type', 'application/json'); } else { Http::abort(404, '不支持的 API_TYPE。'); } @@ -42,7 +41,7 @@ class TextureController extends BaseController public function jsonWithApi($api, $player_name) { - $this->json($player_name, $api); + return $this->json($player_name, $api); } public function texture($hash) { diff --git a/app/Listeners/CachePlayerJson.php b/app/Listeners/CachePlayerJson.php new file mode 100644 index 00000000..18bd79a3 --- /dev/null +++ b/app/Listeners/CachePlayerJson.php @@ -0,0 +1,38 @@ +player; + $api_type = $event->api_type; + + if (!Storage::disk('cache')->has("json/{$player->pid}-{$api_type}")) { + Storage::disk('cache')->put("json/{$player->pid}-{$api_type}", $player->generateJsonProfile($api_type)); + } + + } +} diff --git a/app/Listeners/FreshPlayerJson.php b/app/Listeners/FreshPlayerJson.php new file mode 100644 index 00000000..b11b3c61 --- /dev/null +++ b/app/Listeners/FreshPlayerJson.php @@ -0,0 +1,33 @@ +player; + + $files = [ + "json/{$player->pid}-0", + "json/{$player->pid}-1" + ]; + + foreach ($files as $file) { + if (Storage::disk('cache')->has($file)) { + Storage::disk('cache')->delete($file); + } + } + } +} diff --git a/app/Models/Player.php b/app/Models/Player.php index eea8a6de..c8a5ba68 100644 --- a/app/Models/Player.php +++ b/app/Models/Player.php @@ -2,17 +2,23 @@ namespace App\Models; +use App\Events\PlayerProfileUpdated; +use App\Events\GetPlayerJson; use App\Exceptions\E; +use Event; use Utils; class Player { - public $pid = ""; - public $player_name = ""; + public $pid = ""; + public $player_name = ""; - public $is_banned = false; + public $is_banned = false; - public $model = null; + public $model = null; + + const CSL_API = 0; + const USM_API = 1; /** * Construct player with pid or playername @@ -70,7 +76,10 @@ class Player $this->model->tid_cape = isset($tids['tid_cape']) ? $tids['tid_cape'] : $this->model['tid_cape']; $this->model->last_modified = Utils::getTimeFormatted(); - return $this->model->save(); + + $this->model->save(); + + return Event::fire(new PlayerProfileUpdated($this)); } public function clearTexture() @@ -104,11 +113,12 @@ class Player * @param string $type, 'slim' or 'default' */ public function setPreference($type) { - - return $this->model->update([ + $this->model->update([ 'preference' => $type, 'last_modified' => Utils::getTimeFormatted() ]); + + return Event::fire(new PlayerProfileUpdated($this)); } public function getPreference() { @@ -116,42 +126,55 @@ class Player } public function setOwner($uid) { - return $this->model->update(['uid' => $uid]); + $this->model->update(['uid' => $uid]); + + return Event::fire(new PlayerProfileUpdated($this)); } /** * Get JSON profile - * @param int $api_type, which API to use, 0 for CustomSkinAPI, 1 for UniSkinAPI - * @return string, user profile in json format + * + * @param int $api_type Which API to use, 0 for CustomSkinAPI, 1 for UniSkinAPI + * @return string User profile in json format */ public function getJsonProfile($api_type) { - header('Content-type: application/json'); + Event::fire(new GetPlayerJson($this, $api_type)); // Support both CustomSkinLoader API & UniSkinAPI - if ($api_type == 0 || $api_type == 1) { - $json[($api_type == 0) ? 'username' : 'player_name'] = $this->player_name; - $model = $this->getPreference(); - $sec_model = ($model == 'default') ? 'slim' : 'default'; - if ($api_type == 1) { - $json['last_update'] = $this->getLastModified(); - $json['model_preference'] = [$model, $sec_model]; - } - if ($this->getTexture('steve') || $this->getTexture('alex')) { - // Skins dict order by preference model - $json['skins'][$model] = $this->getTexture($model == "default" ? "steve" : "alex"); - $json['skins'][$sec_model] = $this->getTexture($sec_model == "default" ? "steve" : "alex"); - } - $json['cape'] = $this->getTexture('cape'); + if ($api_type == self::CSL_API || $api_type == self::USM_API) { + return \Storage::disk('cache')->get("json/{$this->pid}-{$api_type}"); } else { throw new E('不支持的 API_TYPE。', -1, true); } + } + + public function generateJsonProfile($api_type) + { + $json[($api_type == self::CSL_API) ? 'username' : 'player_name'] = $this->player_name; + + $model = $this->getPreference(); + $sec_model = ($model == 'default') ? 'slim' : 'default'; + + if ($api_type == self::USM_API) { + $json['last_update'] = $this->getLastModified(); + $json['model_preference'] = [$model, $sec_model]; + } + + if ($this->getTexture('steve') || $this->getTexture('alex')) { + // Skins dict order by preference model + $json['skins'][$model] = $this->getTexture($model == "default" ? "steve" : "alex"); + $json['skins'][$sec_model] = $this->getTexture($sec_model == "default" ? "steve" : "alex"); + } + + $json['cape'] = $this->getTexture('cape'); return json_encode($json, JSON_PRETTY_PRINT); } public function updateLastModified() { // @see http://stackoverflow.com/questions/2215354/php-date-format-when-inserting-into-datetime-in-mysql - return $this->model->update(['last_modified' => Utils::getTimeFormatted()]); + $this->model->update(['last_modified' => Utils::getTimeFormatted()]); + return Event::fire(new PlayerProfileUpdated($this)); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 7b91fda2..07ea4ea6 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -19,6 +19,12 @@ class EventServiceProvider extends ServiceProvider 'App\Events\GetAvatarPreview' => [ 'App\Listeners\CacheAvatarPreview', ], + 'App\Events\GetPlayerJson' => [ + 'App\Listeners\CachePlayerJson', + ], + 'App\Events\PlayerProfileUpdated' => [ + 'App\Listeners\FreshPlayerJson', + ], ]; /** diff --git a/storage/cache/json/.gitignore b/storage/cache/json/.gitignore new file mode 100644 index 00000000..8f4803c0 --- /dev/null +++ b/storage/cache/json/.gitignore @@ -0,0 +1,3 @@ +* +!public/ +!.gitignore