Source of file EventManager.php
Size: 9,809 Bytes - Last Modified: 2020-10-24T02:46:31+00:00
/home/travis/build/NextDom/nextdom-core/src/Managers/EventManager.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 | <?php /* This file is part of Jeedom. * * Jeedom is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jeedom is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jeedom. If not, see <http://www.gnu.org/licenses/>. */ /* This file is part of NextDom Software. * * NextDom Software is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NextDom Software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NextDom Software. If not, see <http://www.gnu.org/licenses/>. */ namespace NextDom\Managers; use NextDom\Enums\CacheKey; use NextDom\Enums\Common; use NextDom\Enums\ConfigKey; use NextDom\Enums\DateFormat; use NextDom\Enums\EventType; use NextDom\Helpers\NextDomHelper; use NextDom\Helpers\Utils; /** * Class EventManager * * @package NextDom\Managers */ class EventManager { /** * @var int Max events processed each time */ private static $MAX_EVENTS_BY_PROCESS = 250; /** * @var mixed Event lock file */ private static $eventLockFile = null; /** * Get event cache file object * * @return bool|null|resource * @throws \Exception */ public static function getFileDescriptorLock() { if (self::$eventLockFile === null) { $lockFilePath = NextDomHelper::getTmpFolder() . '/event_cache_lock'; self::$eventLockFile = fopen($lockFilePath, 'w'); chmod($lockFilePath, 0777); } return self::$eventLockFile; } /** * Add event in cache * * @param string $eventCode * @param array $eventOptions * * @throws \Exception */ public static function add($eventCode, $eventOptions = []) { $waitIfLocked = true; $fd = self::getFileDescriptorLock(); if (flock($fd, LOCK_EX, $waitIfLocked)) { $cache = CacheManager::byKey(CacheKey::EVENT); $value = json_decode($cache->getValue('[]'), true); if (!is_array($value)) { $value = []; } $value[] = [Common::DATETIME => Utils::getMicrotime(), Common::NAME => $eventCode, Common::OPTION => $eventOptions]; CacheManager::set(CacheKey::EVENT, json_encode(self::cleanEvent($value))); flock($fd, LOCK_UN); } } /** * Add multiple events in cache * * @param $eventCode * @param array $eventOptions * @throws \Exception */ public static function adds($eventCode, $eventOptions = []) { $waitIfLocked = true; $fd = self::getFileDescriptorLock(); if (flock($fd, LOCK_EX, $waitIfLocked)) { $cache = CacheManager::byKey(CacheKey::EVENT); $value_src = json_decode($cache->getValue('[]'), true); if (!is_array($value_src)) { $value_src = array(); } $value = array(); foreach ($eventOptions as $option) { $value[] = array(Common::DATETIME => Utils::getMicrotime(), Common::NAME => $eventCode, Common::OPTION => $option); } CacheManager::set(CacheKey::EVENT, json_encode(self::cleanEvent(array_merge($value_src, $value)))); flock($fd, LOCK_UN); } } /** * Clean events * * @param $_events * @return array */ public static function cleanEvent($_events) { $_events = array_slice(array_values($_events), -self::$MAX_EVENTS_BY_PROCESS, self::$MAX_EVENTS_BY_PROCESS); $find = []; $events = array_values($_events); $now = strtotime(DateFormat::NOW) + 300; foreach ($events as $key => $event) { if ($event[Common::DATETIME] > $now) { unset($events[$key]); continue; } if ($event[Common::NAME] == EventType::EQLOGIC_UPDATE) { $id = EventType::EQLOGIC_UPDATE . '::' . $event[Common::OPTION][Common::EQLOGIC_ID]; } elseif ($event[Common::NAME] == EventType::CMD_UPDATE) { $id = EventType::CMD_UPDATE . '::' . $event[Common::OPTION][Common::CMD_ID]; } elseif ($event[Common::NAME] == EventType::SCENARIO_UPDATE) { $id = EventType::SCENARIO_UPDATE . '::' . $event[Common::OPTION][Common::SCENARIO_ID]; } elseif ($event[Common::NAME] == EventType::SUMMARY_UPDATE) { $id = EventType::SUMMARY_UPDATE . '::' . $event[Common::OPTION][Common::OBJECT_ID]; if (is_array($event[Common::OPTION][Common::KEYS]) && count($event[Common::OPTION][Common::KEYS]) > 0) { foreach ($event[Common::OPTION][Common::KEYS] as $key2 => $value) { $id .= $key2; } } } else { continue; } if (isset($find[$id])) { if ($find[$id][Common::DATETIME] > $event[Common::DATETIME]) { unset($events[$key]); continue; } else { unset($events[$find[$id][Common::KEY]]); } } $find[$id] = [Common::DATETIME => $event[Common::DATETIME], Common::KEY => $key]; } return array_values($events); } /** * Method used for sorting event by datetime * * @param mixed $eventA First event to compare * @param mixed $eventB Second event to compare * * @return int Result at usort PHP function format */ public static function orderEvent($eventA, $eventB) { return ($eventA[Common::DATETIME] - $eventB[Common::DATETIME]); } /** * Get new events since a datetime * * @param mixed $_datetime Event time * @param null $_longPolling Wait for new events * @param null $_filter Event filter * @return array * @throws \Exception */ public static function changes($_datetime, $_longPolling = null, $_filter = null) { $result = self::filterEvent(self::changesSince($_datetime), $_filter); if ($_longPolling === null || count($result[Common::RESULT]) > 0) { return $result; } $waitTime = ConfigManager::byKey(ConfigKey::EVENT_WAIT_POLLING); $i = 0; $maxCycle = $_longPolling / $waitTime; while (count($result[Common::RESULT]) == 0 && $i < $maxCycle) { if ($waitTime < 1) { usleep(1000000 * $waitTime); } else { sleep(round($waitTime)); } sleep(1); $result = self::filterEvent(self::changesSince($_datetime), $_filter); $i++; } $result[Common::RESULT] = self::cleanEvent($result[Common::RESULT]); return $result; } /** * Get events filtered by name * * @param array $_data * @param null $_filter * @return array Filtered events * @throws \Exception */ private static function filterEvent($_data = [], $_filter = null) { if ($_filter == null) { return $_data; } $filters = ($_filter !== null) ? CacheManager::byKey($_filter . '::event')->getValue([]) : []; $result = [Common::DATETIME => $_data[Common::DATETIME], Common::RESULT => []]; foreach ($_data[Common::RESULT] as $value) { if ($_filter !== null && isset($_filter::$_listenEvents) && !in_array($value[Common::NAME], $_filter::$_listenEvents)) { continue; } if (count($filters) != 0 && $value[Common::NAME] == EventType::CMD_UPDATE && !in_array($value[Common::OPTION][Common::CMD_ID], $filters)) { continue; } $result[Common::RESULT][] = $value; } return $result; } /** * Get events whose state has changed since a datetime * * @param mixed $_datetime Limit datetime * * @return array Associative array with all events * @throws \Exception */ private static function changesSince($_datetime) { $now = Utils::getMicrotime(); if ($_datetime > $now) { $_datetime = $now; } $result = [Common::DATETIME => $_datetime, Common::RESULT => []]; $cache = CacheManager::byKey(CacheKey::EVENT); $events = json_decode($cache->getValue('[]'), true); if (!is_array($events)) { $events = []; } $values = array_reverse($events); if (count($values) > 0) { $result[Common::DATETIME] = $values[0][Common::DATETIME]; foreach ($values as $value) { if ($value[Common::DATETIME] <= $_datetime) { break; } $result[Common::RESULT][] = $value; } } $result[Common::RESULT] = array_reverse($result[Common::RESULT]); return $result; } } |