From cde2d39029a036c9626fa55cd9dc1e595516896b Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Tue, 19 May 2015 20:49:30 +0200 Subject: [PATCH] New statistics system --- src/pocketmine/Achievement.php | 12 +- src/pocketmine/CrashDump.php | 2 +- src/pocketmine/Player.php | 3 + src/pocketmine/Server.php | 57 +++----- src/pocketmine/resources/pocketmine.yml | 9 +- src/pocketmine/scheduler/AsyncTask.php | 2 +- src/pocketmine/scheduler/CallbackTask.php | 2 +- .../scheduler/GarbageCollectionTask.php | 2 +- src/pocketmine/scheduler/PluginTask.php | 2 +- src/pocketmine/scheduler/SendUsageTask.php | 124 +++++++++++++++++- src/pocketmine/scheduler/ServerScheduler.php | 2 +- src/pocketmine/scheduler/Task.php | 2 +- src/pocketmine/scheduler/TaskHandler.php | 2 +- src/pocketmine/utils/ReversePriorityQueue.php | 2 +- src/pocketmine/utils/Utils.php | 17 ++- 15 files changed, 175 insertions(+), 65 deletions(-) diff --git a/src/pocketmine/Achievement.php b/src/pocketmine/Achievement.php index a7a11f003..d48ec4b0e 100644 --- a/src/pocketmine/Achievement.php +++ b/src/pocketmine/Achievement.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -14,8 +14,8 @@ * (at your option) any later version. * * @author PocketMine Team - - * + * @link http://www.pocketmine.net/ + * * */ diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index eb58e777b..3c981a4b9 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 34bcca37f..de955ce73 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1711,6 +1711,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->orderChunks(); $this->sendNextChunk(); + + $this->server->onPlayerLogin($this); + break; case ProtocolInfo::MOVE_PLAYER_PACKET: diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 686ef9c52..133d83026 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -226,7 +226,7 @@ class Server{ private $dataPath; private $pluginPath; - private $lastSendUsage = null; + private $uniquePlayers = []; /** @var QueryHandler */ private $queryHandler; @@ -1978,7 +1978,6 @@ class Server{ */ public function shutdown(){ $this->isRunning = false; - gc_collect_cycles(); } public function forceShutdown(){ @@ -1987,6 +1986,10 @@ class Server{ } try{ + if(!$this->isRunning()){ + $this->sendUsage(SendUsageTask::TYPE_CLOSE); + } + $this->hasStopped = true; $this->shutdown(); @@ -2031,6 +2034,8 @@ class Server{ } $this->memoryManager->doObjectCleanup(); + + gc_collect_cycles(); }catch(\Exception $e){ $this->logger->emergency("Crashed while crashing, killing process"); @kill(getmypid()); @@ -2052,7 +2057,7 @@ class Server{ if($this->getProperty("settings.send-usage", true) !== false){ $this->sendUsageTicker = 6000; - $this->sendUsage(); + $this->sendUsage(SendUsageTask::TYPE_OPEN); } @@ -2131,7 +2136,7 @@ class Server{ if($this->isRunning === false){ return; } - $this->isRunning = false; + $this->sendUsage(SendUsageTask::TYPE_CLOSE); $this->hasStopped = false; ini_set("error_reporting", 0); @@ -2182,6 +2187,7 @@ class Server{ //$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n"; $this->forceShutdown(); + $this->isRunning = false; @kill(getmypid()); exit(1); } @@ -2205,6 +2211,12 @@ class Server{ } } + public function onPlayerLogin(Player $player){ + if($this->sendUsageTicker > 0){ + $this->uniquePlayers[$player->getUniqueId()] = $player->getUniqueId(); + } + } + public function addPlayer($identifier, Player $player){ $this->players[$identifier] = $player; $this->identifiers[spl_object_hash($player)] = $identifier; @@ -2275,38 +2287,9 @@ class Server{ } } - public function sendUsage(){ - if($this->lastSendUsage instanceof SendUsageTask){ - if(!$this->lastSendUsage->isGarbage()){ //do not call multiple times - return; - } - } - - $plist = ""; - foreach($this->getPluginManager()->getPlugins() as $p){ - $d = $p->getDescription(); - $plist .= str_replace([";", ":"], "", $d->getName()) . ":" . str_replace([";", ":"], "", $d->getVersion()) . ";"; - } - - $version = new VersionString(); - $this->lastSendUsage = new SendUsageTask("https://stats.pocketmine.net/usage.php", [ - "serverid" => Binary::readLong(substr(hex2bin(str_replace("-", "", $this->serverID)), 0, 8)), - "port" => $this->getPort(), - "os" => Utils::getOS(), - "name" => $this->getName(), - "memory_total" => $this->getConfigString("memory-limit"), //TODO - "memory_usage" => Utils::getMemoryUsage(), - "php_version" => PHP_VERSION, - "version" => $version->get(true), - "build" => $version->getBuild(), - "mc_version" => \pocketmine\MINECRAFT_VERSION, - "protocol" => \pocketmine\network\protocol\Info::CURRENT_PROTOCOL, - "online" => count($this->players), - "max" => $this->getMaxPlayers(), - "plugins" => $plist, - ]); - - $this->scheduler->scheduleAsyncTask($this->lastSendUsage); + public function sendUsage($type = SendUsageTask::TYPE_STATUS){ + $this->scheduler->scheduleAsyncTask(new SendUsageTask($this, $type, $this->uniquePlayers)); + $this->uniquePlayers = []; } @@ -2438,7 +2421,7 @@ class Server{ if($this->sendUsageTicker > 0 and --$this->sendUsageTicker === 0){ $this->sendUsageTicker = 6000; - $this->sendUsage(); + $this->sendUsage(SendUsageTask::TYPE_STATUS); } if(($this->tickCounter % 100) === 0){ diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index a7fd73238..67b21a5f3 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -18,8 +18,6 @@ settings: enable-profiling: false #Will only add results when tick measurement is below or equal to given value (default 20) profile-report-trigger: 20 - #Sends anonymous statistics to create usage reports - send-usage: true #Number of AsyncTask workers. #Used for plugin asynchronous tasks, world generation, compression and web communication. #Set this approximately to your number of cores. @@ -125,7 +123,7 @@ chunk-generation: #Max. amount of chunks in the waiting queue to be generated queue-size: 8 #Max. amount of chunks in the waiting queue to be populated - population-queue-size: 2 + population-queue-size: 8 ticks-per: animal-spawns: 400 @@ -147,6 +145,11 @@ auto-report: send-phpinfo: false host: crash.pocketmine.net +anonymous-statistics: + #Sends anonymous statistics for data aggregation, plugin usage tracking + enabled: true + host: stats.pocketmine.net + auto-updater: enabled: true on-update: diff --git a/src/pocketmine/scheduler/AsyncTask.php b/src/pocketmine/scheduler/AsyncTask.php index 16594aeb5..b54d43485 100644 --- a/src/pocketmine/scheduler/AsyncTask.php +++ b/src/pocketmine/scheduler/AsyncTask.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/CallbackTask.php b/src/pocketmine/scheduler/CallbackTask.php index f94144235..4d4969404 100644 --- a/src/pocketmine/scheduler/CallbackTask.php +++ b/src/pocketmine/scheduler/CallbackTask.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/GarbageCollectionTask.php b/src/pocketmine/scheduler/GarbageCollectionTask.php index e7b353d3d..0b99aed78 100644 --- a/src/pocketmine/scheduler/GarbageCollectionTask.php +++ b/src/pocketmine/scheduler/GarbageCollectionTask.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/PluginTask.php b/src/pocketmine/scheduler/PluginTask.php index 124ca27a6..cacb732e3 100644 --- a/src/pocketmine/scheduler/PluginTask.php +++ b/src/pocketmine/scheduler/PluginTask.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/SendUsageTask.php b/src/pocketmine/scheduler/SendUsageTask.php index 4065fed84..2ec40a6d8 100644 --- a/src/pocketmine/scheduler/SendUsageTask.php +++ b/src/pocketmine/scheduler/SendUsageTask.php @@ -14,26 +14,140 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ namespace pocketmine\scheduler; +use pocketmine\network\protocol\Info; +use pocketmine\Server; use pocketmine\utils\Utils; +use pocketmine\utils\VersionString; class SendUsageTask extends AsyncTask{ + const TYPE_OPEN = 1; + const TYPE_STATUS = 2; + const TYPE_CLOSE = 3; + public $endpoint; public $data; - public function __construct($endpoint, array $data){ - $this->endpoint = $endpoint; - $this->data = serialize($data); + public function __construct(Server $server, $type, $playerList = []){ + $endpoint = "http://" . $server->getProperty("anonymous-statistics.host", "stats.pocketmine.net") . "/"; + $path = "post"; + + $data = []; + $data["uniqueServerId"] = Utils::getServerUniqueId(); + $data["uniqueRequestId"] = Utils::dataToUUID(Utils::getServerUniqueId(), microtime(true)); + + switch($type){ + case self::TYPE_OPEN: + $path = "open"; + $data["event"] = "open"; + + $version = new VersionString(); + + $data["server"] = [ + "port" => $server->getPort(), + "software" => $server->getName(), + "fullVersion" => $version->get(true), + "version" => $version->get(), + "build" => $version->getBuild(), + "api" => $server->getApiVersion(), + "minecraftVersion" => $server->getVersion(), + "protocol" => Info::CURRENT_PROTOCOL + ]; + + $data["system"] = [ + "operatingSystem" => Utils::getOS(), + "cores" => Utils::getCoreCount(), + "phpVersion" => PHP_VERSION, + "machine" => php_uname("a"), + "release" => php_uname("r"), + "platform" => php_uname("i") + ]; + + $data["players"] = [ + "count" => 0, + "limit" => $server->getMaxPlayers() + ]; + + $plugins = []; + + foreach($server->getPluginManager()->getPlugins() as $p){ + $d = $p->getDescription(); + + $plugins[$d->getName()] = [ + "name" => $d->getName(), + "version" => $d->getVersion(), + "enabled" => $p->isEnabled() + ]; + } + + $data["plugins"] = $plugins; + + break; + case self::TYPE_STATUS: + $path = "status"; + $data["event"] = "status"; + + $data["server"] = [ + "ticksPerSecond" => $server->getTicksPerSecondAverage(), + "tickUsage" => $server->getTickUsageAverage(), + "ticks" => $server->getTick() + ]; + + + //This anonymizes the user ids so they cannot be reversed to the original + foreach($playerList as $k => $v){ + $playerList[$k] = Utils::dataToUUID($v); + } + + $players = []; + foreach($server->getOnlinePlayers() as $p){ + if($p->isOnline()){ + $players[] = Utils::dataToUUID($p->getUniqueId()); + } + } + + $data["players"] = [ + "count" => count($players), + "limit" => $server->getMaxPlayers(), + "currentList" => $players, + "historyList" => array_values($playerList) + ]; + + $info = Utils::getMemoryUsage(true); + $data["system"] = [ + "mainMemory" => $info[0], + "totalMemory" => $info[1], + "availableMemory" => $info[2], + "threadCount" => Utils::getThreadCount() + ]; + + break; + case self::TYPE_CLOSE: + $path = "close"; + $data["event"] = "close"; + $data["crashing"] = $server->isRunning(); + break; + } + + $this->endpoint = $endpoint . $path; + $this->data = json_encode($data/*, JSON_PRETTY_PRINT*/); } public function onRun(){ - Utils::postURL($this->endpoint, unserialize($this->data)); + try{ + Utils::postURL($this->endpoint, $this->data, 10, [ + "Content-Type: application/json", + "Content-Length: ". strlen($this->data) + ]); + }catch(\Exception $e){ + + } } } diff --git a/src/pocketmine/scheduler/ServerScheduler.php b/src/pocketmine/scheduler/ServerScheduler.php index 0209f9f77..4271f0f72 100644 --- a/src/pocketmine/scheduler/ServerScheduler.php +++ b/src/pocketmine/scheduler/ServerScheduler.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/Task.php b/src/pocketmine/scheduler/Task.php index 0b4d2bded..5793466ae 100644 --- a/src/pocketmine/scheduler/Task.php +++ b/src/pocketmine/scheduler/Task.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/scheduler/TaskHandler.php b/src/pocketmine/scheduler/TaskHandler.php index 70b9f7ba5..5bd8e77d4 100644 --- a/src/pocketmine/scheduler/TaskHandler.php +++ b/src/pocketmine/scheduler/TaskHandler.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/utils/ReversePriorityQueue.php b/src/pocketmine/utils/ReversePriorityQueue.php index c0ab5ec96..740f8ee48 100644 --- a/src/pocketmine/utils/ReversePriorityQueue.php +++ b/src/pocketmine/utils/ReversePriorityQueue.php @@ -14,7 +14,7 @@ * (at your option) any later version. * * @author PocketMine Team - + * @link http://www.pocketmine.net/ * * */ diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 942b80b85..15fd8bf45 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -32,6 +32,7 @@ class Utils{ public static $online = true; public static $ip = false; public static $os; + private static $serverUniqueId = null; /** * Generates an unique identifier to a callable @@ -78,6 +79,10 @@ class Utils{ * @return string */ public static function getServerUniqueId($extra = ""){ + if(self::$serverUniqueId !== null){ + return self::$serverUniqueId; + } + $machine = php_uname("a"); $machine .= file_exists("/proc/cpuinfo") ? implode(preg_grep("/model name/", file("/proc/cpuinfo"))) : ""; $machine .= sys_get_temp_dir(); @@ -114,7 +119,7 @@ class Utils{ $data .= $ext . ":" . phpversion($ext); } - return Utils::dataToUUID($machine, $data); + return self::$serverUniqueId = Utils::dataToUUID($machine, $data); } /** @@ -434,16 +439,17 @@ class Utils{ * * @param $page * @param int $timeout default 10 + * @param array $extraHeaders * * @return bool|mixed */ - public static function getURL($page, $timeout = 10){ + public static function getURL($page, $timeout = 10, array $extraHeaders = []){ if(Utils::$online === false){ return false; } $ch = curl_init($page); - curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"]); + curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"], $extraHeaders)); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); @@ -464,10 +470,11 @@ class Utils{ * @param $page * @param array|string $args * @param int $timeout + * @param array $extraHeaders * * @return bool|mixed */ - public static function postURL($page, $args, $timeout = 10){ + public static function postURL($page, $args, $timeout = 10, array $extraHeaders = []){ if(Utils::$online === false){ return false; } @@ -481,7 +488,7 @@ class Utils{ curl_setopt($ch, CURLOPT_POSTFIELDS, $args); curl_setopt($ch, CURLOPT_AUTOREFERER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, ["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"]); + curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 PocketMine-MP"], $extraHeaders)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout); $ret = curl_exec($ch);