api.stardust.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. /**
  3. * Uncomplicated process manager
  4. */
  5. class StarDust {
  6. /**
  7. * Contains current process name/identifier
  8. *
  9. * @var string
  10. */
  11. protected $processName = '';
  12. /**
  13. * System caching object placeholder
  14. *
  15. * @var object
  16. */
  17. protected $cache = '';
  18. /**
  19. * Contains current process states as processName=>processStats
  20. *
  21. * @var array
  22. */
  23. protected $allProcessStates = array();
  24. /**
  25. * Store each process state in separate STARDUST_PID cache keys
  26. *
  27. * @var bool
  28. */
  29. protected $separateKeys = false;
  30. /**
  31. * Some predefined stuff
  32. */
  33. const LOCK_NAME = 'stardustLockfree';
  34. const LOCK_PREFIX = 'stardustPID_';
  35. const CACHE_TIMEOUT = 2592000;
  36. const CACHE_KEY = 'STARDUST';
  37. const REALTIME_PRECISSION = 5;
  38. public function __construct($processName = '', $separateKeys = false) {
  39. $this->setProcess($processName);
  40. $this->setZaWarudo($separateKeys);
  41. $this->initCache();
  42. $this->loadCache();
  43. }
  44. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⢿⢻⣉⣳⣄⣀⣹⠾⠿⠶⠶⠶⠾⠿⣯⣿⣿⣿⣏⣿⣠⣿⣿⣿⣿⡿⠄⠀⠑⢒⡲⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  45. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⢾⠼⣿⣧⠦⠴⢒⣒⣒⣒⣒⣒⣒⣒⣒⣀⣤⠶⢶⣤⡏⣻⣿⣿⠿⢧⣤⠤⡤⢼⡯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  46. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣴⣞⠿⠛⠉⠉⠉⠉⠉⡭⠭⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⡿⣼⠃⠀⡨⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  47. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠴⠋⠁⠀⠀⠀⠀⠀⠐⠀⢉⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⣟⣫⣤⡴⢷⡟⣦⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  48. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠋⠉⠁⠒⠒⠀⠀⠀⠠⠤⠤⠶⠾⠿⠿⢿⡿⡟⠛⠟⠏⢉⣁⣤⠬⠒⢛⣫⣿⣿⣾⣟⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  49. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠙⢒⣶⢶⡖⣶⣶⡶⢦⣤⣴⢶⣶⣶⣾⣟⣿⣻⣇⢤⣴⣾⠿⣿⢿⢹⣿⡿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  50. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⢴⣶⣒⡾⣿⣟⢧⠈⢿⡿⠺⠟⠓⣊⡴⢙⡏⠉⣏⢻⣉⠺⠿⣿⠾⠋⠘⡼⣿⡟⠁⠀⠀⠀⢀⡠⠤⠤⠤⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  51. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⢯⣿⣞⣷⣿⣿⢆⠁⢿⠡⠔⠚⢛⣿⣿⠟⡇⠀⡟⢿⣯⠿⠗⠂⢤⢀⢧⣿⣟⡁⠀⠀⡠⠚⢁⣤⢔⣒⣒⠒⠚⢦⠀⠀⠀⠀⠀⠀⠀⠀
  52. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⣿⣿⣿⣿⣟⣿⡇⠘⡇⠀⠀⠩⠻⡁⠀⣇⠀⠃⠀⠀⠈⠀⠀⠈⡟⣸⣿⣿⣯⣿⡿⠁⣴⣿⠋⠁⠀⠀⠙⣦⢰⡇⠀⠀⠀⠀⠀⠀⠀
  53. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣤⣤⡈⢳⣿⣿⣿⣷⣧⠀⢃⠀⠀⠀⠀⢱⡀⡅⠀⡀⡄⠀⠀⠀⠀⣸⢡⣿⣿⣿⣿⣿⣇⣾⢻⣿⡻⣖⣦⣄⢠⣇⢀⡇⠀⠀⠀⠀⠀⠀⠀
  54. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡟⣎⢿⡌⢻⣿⣿⣿⣿⡆⠸⡄⠀⠀⠀⠀⠛⢿⣿⠛⠁⠀⠀⠀⢀⡇⣼⣿⣿⣿⣿⣿⣇⢸⣽⣿⣿⣷⣽⠺⣓⢾⣿⠁⣠⣄⡀⠀⠀⠀⠀
  55. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣇⠸⣮⢧⣏⡻⣿⣿⣿⣿⡷⢧⡀⠀⣀⣀⣤⣄⣠⣤⣀⡀⠀⢀⡜⡼⣿⢿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⡮⣿⣮⠑⢌⠻⣋⣩⡙⢢⡀⠀⠀
  56. // ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣋⣮⣆⡾⣸⡿⠹⡞⣿⣿⣿⣇⣸⣳⡀⠉⣅⣀⣉⣉⣀⣉⠉⢀⣮⣾⠇⡌⠓⢝⣿⣿⣿⣿⣿⣿⠁⣉⠁⠀⠈⡝⢦⡀⡷⠈⣯⡻⣦⡈⢆⠀
  57. // ⠀⠀⠀⠀⠀⣀⢤⢚⣉⡓⠚⠉⠲⣿⣿⣿⣿⣯⣿⡄⣽⣿⣿⣿⣿⣿⣷⣵⡀⠈⢻⠉⠙⠛⠋⣠⣿⣿⠏⠀⠰⡄⠀⠙⠻⣿⣿⣿⣿⣾⡇⠀⠀⢀⠇⠦⣣⠃⣼⠻⢿⡎⣿⣄⠱
  58. // ⡀⠀⠴⠒⠉⠀⢿⣾⣾⣿⣷⣄⠀⢾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢈⠻⣿⣄⡟⠀⠀⠀⣰⣿⣿⡟⣰⠸⣆⢹⡄⣄⡀⠈⠛⠉⣻⣿⡇⠀⠀⡼⠈⡦⣿⣶⣿⣿⣾⠵⣶⣛⢧
  59. // ⠀⠀⠀⠀⠀⠀⠈⠹⠽⣿⣿⣻⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⢻⣎⠻⢿⣶⣶⣶⣿⣿⣿⠀⢹⣇⠈⠳⣿⣾⣟⣷⣾⣾⡿⢻⣿⣄⠀⢣⠶⣱⣿⣿⣾⣿⣧⡒⠻⣿⠸
  60. // ⠀⠀⠀⠀⠀⠀⢀⣀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠻⡄⢈⣿⣟⢿⣿⡟⢸⡀⠈⣿⠀⠀⢈⣿⡿⠛⠋⠀⠈⠁⣿⣿⣶⠌⡧⣿⣿⣿⣿⣿⣿⣿⡄⠙⢣
  61. // ⠀⠀⠀⢀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣤⣶⣿⣿⣿⣿⡀⢻⠀⠀⣷⣄⣷⣀⡴⠏⠁⠀⠀⠀⠀⠀⣰⢟⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀
  62. /**
  63. * Inits system caching instance for further usage
  64. *
  65. * @return void
  66. */
  67. protected function initCache() {
  68. $this->cache = new UbillingCache();
  69. }
  70. /**
  71. * Loads current processes data from cache
  72. *
  73. * @return void
  74. */
  75. protected function loadCache() {
  76. $this->allProcessStates = $this->getCachedData();
  77. }
  78. /**
  79. * Sets instance process name/identifier
  80. *
  81. * @param string $processName
  82. *
  83. * @return void
  84. */
  85. public function setProcess($processName = '') {
  86. $this->processName = $processName;
  87. }
  88. /**
  89. * Sets instance process separate keys usage flag
  90. *
  91. * @param string $processName
  92. *
  93. * @return void
  94. */
  95. public function setZaWarudo($state = false) {
  96. $this->separateKeys = $state;
  97. }
  98. /**
  99. * Returns process data from cache
  100. *
  101. * @return array
  102. */
  103. protected function getCachedData() {
  104. $result = array();
  105. if ($this->separateKeys) {
  106. $allCacheKeys = $this->cache->getAllcache();
  107. if (!empty($allCacheKeys)) {
  108. $processKeyMask = UbillingCache::CACHE_PREFIX . self::CACHE_KEY . '_';
  109. foreach ($allCacheKeys as $io => $eachKey) {
  110. if (strpos($eachKey, $processKeyMask) !== false) {
  111. $processNameClean = str_replace($processKeyMask, '', $eachKey);
  112. $processCacheKey = self::CACHE_KEY . '_' . $processNameClean;
  113. $result[$processNameClean] = $this->cache->get($processCacheKey, self::CACHE_TIMEOUT);
  114. }
  115. }
  116. }
  117. } else {
  118. $cachedData = $this->cache->get(self::CACHE_KEY, self::CACHE_TIMEOUT);
  119. if (!empty($cachedData)) {
  120. $result = $cachedData;
  121. }
  122. }
  123. return($result);
  124. }
  125. /**
  126. * Saves current process data into cache
  127. *
  128. * @return void
  129. */
  130. protected function saveCache() {
  131. if ($this->separateKeys) {
  132. $this->cache->set(self::CACHE_KEY . '_' . $this->processName, $this->allProcessStates[$this->processName], self::CACHE_TIMEOUT);
  133. } else {
  134. $this->cache->set(self::CACHE_KEY, $this->allProcessStates, self::CACHE_TIMEOUT);
  135. }
  136. }
  137. /**
  138. * Checks is process name not empty and valid for setting/getting locks?
  139. *
  140. * @return bool
  141. * @throws Exception
  142. */
  143. protected function pidIsOk() {
  144. $result = false;
  145. if (!empty($this->processName)) {
  146. $result = true;
  147. } else {
  148. throw new Exception('EX_EMPTY_PID');
  149. }
  150. return($result);
  151. }
  152. /**
  153. * Starts some process
  154. *
  155. * @return void
  156. */
  157. public function start() {
  158. if ($this->pidIsOk()) {
  159. $this->processStateUpdate(false);
  160. nr_query("SELECT GET_LOCK('" . self::LOCK_PREFIX . $this->processName . "',1)");
  161. }
  162. }
  163. /**
  164. * Stops some process
  165. *
  166. * @return void
  167. */
  168. public function stop() {
  169. if ($this->pidIsOk()) {
  170. $this->processStateUpdate(true);
  171. nr_query("SELECT RELEASE_LOCK('" . self::LOCK_PREFIX . $this->processName . "')");
  172. }
  173. }
  174. /**
  175. * Performs check is database lock available or not?
  176. *
  177. * @return bool
  178. */
  179. protected function isLocked() {
  180. $result = true;
  181. if ($this->pidIsOk()) {
  182. $query = "SELECT IS_FREE_LOCK('" . self::LOCK_PREFIX . $this->processName . "') AS " . self::LOCK_NAME;
  183. $rawReply = simple_query($query);
  184. $result = ($rawReply[self::LOCK_NAME]) ? false : true;
  185. }
  186. return($result);
  187. }
  188. /**
  189. * Performs check for current process is running
  190. *
  191. * @return bool
  192. */
  193. public function isRunning() {
  194. $locked = $this->isLocked();
  195. $result = ($locked) ? true : false;
  196. return($result);
  197. }
  198. /**
  199. * Performs check for current process is not running
  200. *
  201. * @return bool
  202. */
  203. public function notRunning() {
  204. $locked = $this->isLocked();
  205. $result = ($locked) ? false : true;
  206. return($result);
  207. }
  208. /**
  209. * Returns current process execution stats
  210. *
  211. * @return array
  212. */
  213. public function getState() {
  214. $result = array();
  215. if (!empty($this->processName)) {
  216. $processData = $this->getCachedData();
  217. if (isset($processData[$this->processName])) {
  218. $result = $processData[$this->processName];
  219. //process now running?
  220. if (!$result['finished']) {
  221. $result['realtime'] = round((microtime(true) - $result['ms']), self::REALTIME_PRECISSION);
  222. }
  223. }
  224. }
  225. return($result);
  226. }
  227. /**
  228. * Returns all process execution stats
  229. *
  230. * @return array
  231. */
  232. public function getAllStates() {
  233. $result = array();
  234. $processData = $this->getCachedData();
  235. if (!empty($processData)) {
  236. $microTime = microtime(true);
  237. foreach ($processData as $processName => $eachProcessData) {
  238. //updating realtime if process is still running
  239. if (!$eachProcessData['finished']) {
  240. $eachProcessData['realtime'] = round($microTime - $eachProcessData['ms'], self::REALTIME_PRECISSION);
  241. }
  242. //append to results
  243. $result[$processName] = $eachProcessData;
  244. }
  245. }
  246. return($result);
  247. }
  248. /**
  249. * Updates some process execution stats
  250. *
  251. * @param bool $finished process finished or not flag
  252. *
  253. * @return void
  254. */
  255. protected function processStateUpdate($finished = false) {
  256. $startTime = 0;
  257. $endTime = 0;
  258. $realTime = 0;
  259. $ms = 0;
  260. $me = 0;
  261. $nowTime = time();
  262. $microTime = microtime(true);
  263. $finishedData = ($finished) ? 1 : 0;
  264. //process just started?
  265. if (!$finished) {
  266. $startTime = $nowTime;
  267. $ms = $microTime;
  268. }
  269. //process finished?
  270. if ($finished) {
  271. if (isset($this->allProcessStates[$this->processName])) {
  272. $startTime = $this->allProcessStates[$this->processName]['start'];
  273. $ms = $this->allProcessStates[$this->processName]['ms'];
  274. } else {
  275. $startTime = $nowTime;
  276. }
  277. $me = $microTime;
  278. $endTime = $nowTime;
  279. }
  280. //process duration counter
  281. if (isset($this->allProcessStates[$this->processName])) {
  282. if ($finished) {
  283. $realTime = $me - $ms;
  284. } else {
  285. $realTime = 0;
  286. }
  287. }
  288. //getting latest data from cache
  289. $this->loadCache();
  290. //updating current process properties
  291. $this->allProcessStates[$this->processName]['start'] = $startTime;
  292. $this->allProcessStates[$this->processName]['end'] = $endTime;
  293. $this->allProcessStates[$this->processName]['realtime'] = round($realTime, self::REALTIME_PRECISSION);
  294. $this->allProcessStates[$this->processName]['ms'] = $ms;
  295. $this->allProcessStates[$this->processName]['me'] = $me;
  296. $this->allProcessStates[$this->processName]['finished'] = $finishedData;
  297. $this->allProcessStates[$this->processName]['pid'] = getmypid();
  298. //save current process data into cache
  299. $this->saveCache();
  300. }
  301. /**
  302. * Runs execution of some command as background process
  303. *
  304. * @param string $command full executable path to run
  305. * @param int $timeout optional timeout after executing command
  306. *
  307. * @return void
  308. */
  309. public function runBackgroundProcess($command, $timeout = 0) {
  310. if (!empty($command)) {
  311. $pipes = array();
  312. proc_close(proc_open($command . ' > /dev/null 2>/dev/null &', array(), $pipes));
  313. if ($timeout) {
  314. sleep($timeout);
  315. }
  316. }
  317. }
  318. //
  319. // ⠀ (\__/)
  320. // (•ㅅ•) SONO CHI NO SADAME
  321. // _ノヽ ノ\_
  322. // `/ `/ ⌒Y⌒ Y ヽ
  323. // (  (三ヽ人  /  |
  324. // | ノ⌒\  ̄ ̄ヽ ノ
  325. // ヽ___>、__/
  326. // |( 王 ノ〈 (\__/)
  327. // /ミ`ー―彡\ (•ㅅ•)
  328. // / ╰ ╯ \ / \>
  329. }