timekeeperLocal.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/bin/php
  2. <?PHP
  3. // Local update and invoke command for bash.
  4. // kill $(pidof firefox) || wget -O .timekeeper.php "https://overlord.pfip.au/e107_plugins/timekeeper/localUpdater.php" && chmod +x ~/.timekeeper.php && ~/.timekeeper.php
  5. $version = "3.7";
  6. $TKL = new timekeeperLocal();
  7. if (isset($argv[1]) && $argv[1] == 'debug') {
  8. echo "Debug mode active.";
  9. $TKL->debug = true;
  10. $TKL->message("Timekeeper " . $version, "Timekeeper is running. (In debug mode)");
  11. } else {
  12. $TKL->message("Timekeeper " . $version, "Timekeeper is running.");
  13. }
  14. // mutex here
  15. echo 'Looking for other ' . $argv[0] . ' here.' . PHP_EOL;
  16. $firstCount = false;
  17. $cmdLineReturnArray = [];
  18. exec("ps aux | grep $(whoami) | grep " . $argv[0], $cmdLineReturnArray);
  19. foreach ($cmdLineReturnArray as $cmd) {
  20. if (strpos($cmd, "/php")) {
  21. if ($firstCount) {
  22. die("Found another instance.");
  23. }
  24. $firstCount = true;
  25. }
  26. }
  27. $gamesList = json_decode(file_get_contents('https://overlord.pfip.au/e107_plugins/timekeeper/timekeeperClientServices/games.json'), true);
  28. $TKL->user = exec("whoami");
  29. $TKL->Logging("Timekeeper " . $version . " initialised for " . $TKL->user, false);
  30. while (true) {
  31. set_time_limit(70);
  32. $startupTime = microtime(true);
  33. $TKL->CheckForGames($gamesList);
  34. $TKL->CheckTimeRemaining();
  35. $TKL->burnTime($startupTime, 60);
  36. }
  37. exit;
  38. class timekeeperLocal {
  39. public $lastActiveGame = '';
  40. public $user = '';
  41. public $debug = false;
  42. public function test() {
  43. $this->message('test title', 'test message', '');
  44. }
  45. /**
  46. * Send a message to the user.
  47. *
  48. * <pre><code>Example usage:
  49. * $this->message('Alert','this is an important meassage.',1);
  50. * </code></pre>
  51. *
  52. * @param string $title The title to be displayed for the message.
  53. * @param string $messageText The body text of the message to be displayed.
  54. * @param int $urgency The urgency level for the message to be displayed
  55. * with. <br/>1 = High<br/>2 = Medium<br/>3 = Low
  56. *
  57. * @return void
  58. */
  59. public function message($title, $messageText, $urgency = '') {
  60. switch ($urgency) {
  61. case 1:
  62. $urgencyText = ' --urgency=critical';
  63. break;
  64. case 2:
  65. $urgencyText = ' --urgency=normal';
  66. break;
  67. case 3:
  68. $urgencyText = ' --urgency=low';
  69. break;
  70. default:
  71. $urgencyText = '';
  72. break;
  73. }
  74. exec('notify-send' . $urgencyText . ' "' . $title . '" "' . $messageText . '"');
  75. }
  76. public function burnTime($startupTime, $burnTimeDuration) {
  77. if ($this->lastActiveGame == "") {
  78. sleep(20);
  79. return;
  80. }
  81. //echo 'Burning ' . (int) (60 - (microtime(true) - $startupTime)) . ' seconds' . PHP_EOL;
  82. //echo 'Burning from ' . microtime(true) . PHP_EOL;
  83. while (microtime(true) < ($startupTime + $burnTimeDuration)) {
  84. usleep(300);
  85. }
  86. }
  87. public function CheckForGames($listOfKnownGames) {
  88. foreach ($listOfKnownGames as $gameName) {
  89. $cmdLineReturnArray = [];
  90. exec("ps aux | grep $(whoami) | grep $gameName", $cmdLineReturnArray); //print_r($cmdLineReturnArray);
  91. foreach ($cmdLineReturnArray as $cmdLineReturn) {
  92. if ($this->cmdExceptions($cmdLineReturn)) {
  93. $this->AnounceGameDetected($gameName);
  94. return;
  95. }
  96. }
  97. }
  98. $this->AnounceGameNotDetected();
  99. }
  100. private function cmdExceptions($cmdLineReturn) {
  101. if (strpos($cmdLineReturn, 'grep') != false) {
  102. return false;
  103. } elseif (strpos($cmdLineReturn, 'kiosk') != false) {
  104. return false;
  105. } elseif (strpos($cmdLineReturn, 'contentproc') != false) {
  106. return false;
  107. } elseif (strpos($cmdLineReturn, 'new-window') != false) { //opera helper exception
  108. return false;
  109. } elseif (strpos($cmdLineReturn, 'type=gpu-process') != false) { // opera helper exception
  110. return false;
  111. }
  112. return true;
  113. }
  114. private function AnounceGameDetected($game) {
  115. if ($this->lastActiveGame == "") {
  116. $this->lastActiveGame = $game;
  117. $minutesRemaining = file_get_contents('https://overlord.pfip.au/e107_plugins/timekeeper/timekeeperClientServices/timer.php?user=' . $this->user . '&game=' . $this->lastActiveGame);
  118. $this->message("Timekeeper", ucfirst($game) . " detected running." . PHP_EOL . "You have " . $minutesRemaining . " minutes remaining.");
  119. $this->Logging(ucfirst($game) . " detected running. " . $minutesRemaining . " minutes remaining.");
  120. }
  121. }
  122. private function AnounceGameNotDetected() {
  123. if ($this->lastActiveGame != "") {
  124. $this->lastActiveGame = "";
  125. $this->message("Timekeeper", "No games detected running.");
  126. $this->Logging("No games detected running.");
  127. }
  128. //No games running so just read out the play time avalible
  129. //echo file_get_contents('https://overlord.pfip.tk/e107_plugins/timekeeper/timekeeperClientServices/timer.php?user=' . $this->user . '&game=' . $this->lastActiveGame);
  130. }
  131. public function CheckTimeRemaining() {
  132. if ($this->lastActiveGame != "") {
  133. $serverResponse = file_get_contents('https://overlord.pfip.au/e107_plugins/timekeeper/timekeeperClientServices/timer.php?user=' . $this->user . '&game=' . $this->lastActiveGame);
  134. //echo "==Debug==" . $serverResponse . "====";
  135. $this->TimeLimitWarning($serverResponse);
  136. }
  137. }
  138. private function TimeLimitWarning($reply) {
  139. if (!is_numeric($reply)) {
  140. $this->message("Timekeeper", $reply);
  141. $this->KillGame();
  142. return;
  143. }
  144. switch ($reply) {
  145. case 5:
  146. $this->message("Timekeeper", "You only have 5 minutes remaining.");
  147. break;
  148. case 1:
  149. $this->message("Timekeeper", "You only have 1 minute remaining.");
  150. break;
  151. case 0:
  152. $this->message("Timekeeper", "Your play time has expired.");
  153. $this->KillGame();
  154. break;
  155. default:
  156. break;
  157. }
  158. }
  159. private function KillGame() {
  160. $gamePid = preg_split('/\s+/', exec("ps ax -f| grep $(whoami) | grep $this->lastActiveGame | grep -v grep | grep -v content"))[1];
  161. if ($this->debug) {
  162. $this->message("Timekeeper", "Game PID-" . $gamePid . " should\nhave just been killed.");
  163. } else {
  164. for ($level = 0; $level < 3; $level++) {
  165. $this->Logging('Killing '.$this->lastActiveGame . " with killRoutine($level).");
  166. if($this->killRoutine($level))
  167. {
  168. return;
  169. }
  170. }
  171. }
  172. }
  173. private function killRoutine($level): bool{
  174. $gamePid = preg_split('/\s+/', exec("ps ax -f| grep $(whoami) | grep $this->lastActiveGame | grep -v grep | grep -v content"))[1];
  175. if(count($gamePid)>=2){
  176. $this->Logging('Current pid '. $gamePid . ".");
  177. }else{
  178. $this->Logging('Game is supposedly dead, bailing out now.');
  179. return true;
  180. }
  181. switch ($level) {
  182. case 0:
  183. exec("kill -15 $gamePid");
  184. break;
  185. case 1:
  186. exec("kill -9 $gamePid");
  187. break;
  188. case 2:
  189. exec("pkill -15 $this->lastActiveGame");
  190. break;
  191. case 3:
  192. exec("pkill -9 $this->lastActiveGame");
  193. break;
  194. }
  195. sleep(10);
  196. return false;
  197. }
  198. /**
  199. *
  200. * Logging($message,$append = true);
  201. *
  202. * Write to the common log file.
  203. *
  204. * <pre><code>Example usage:
  205. * $this->Logging('Hello this is a message.');
  206. * </code></pre>
  207. *
  208. * @param string $message The message to be written into the log file.
  209. * @param bool $append Set to false to overwrite the log file.
  210. *
  211. * @return void
  212. */
  213. public function Logging($message, $append = true) {
  214. try {
  215. $filename = "timekeeper.log";
  216. if ($append) {
  217. file_put_contents($filename, $message . PHP_EOL, FILE_APPEND);
  218. } else {
  219. file_put_contents($filename, $message . PHP_EOL);
  220. }
  221. } catch (Exception $ex) {
  222. $this->message("Error", "Logging can not be initialised." . PHP_EOL . $ex, 1);
  223. }
  224. }
  225. }