$locationid, 'act' => $nextexec['action'], 'next' => $nextexec['time'], 'opt' => $json_options, ]); } else { // All times are getting ignored because they are within 5 minutes of each other, delete possible db entries. self::deleteSchedule($locationid); } return true; } public static function deleteSchedule($locationid) { Database::exec("DELETE FROM `reboot_scheduler` WHERE locationid = :lid", ['lid' => $locationid]); } private static function calculateTimestamp($now, $day, $time) { $ts = strtotime("$day $time"); if ($ts < $now) { $ts = strtotime("next $day $time"); } if ($ts < $now) { EventLog::warning("Invalid params to calculateTimestamp(): 'next $day $time'"); $ts = $now + 864000; } return $ts; } private static function calculateNext($options, $openingTimes) { if (!$options['wol'] && !$options['sd']) return false; $openingTimes = json_decode($openingTimes, true); $now = time(); $events = []; foreach ($openingTimes as $row) { foreach ($row['days'] as $day) { if ($options['wol']) { $events[] = ['action' => 'wol', 'time' => self::calculateTimestamp($now, $day, $row['openingtime'])]; } if ($options['sd']) { $events[] = ['action' => 'sd', 'time' => self::calculateTimestamp($now, $day, $row['closingtime'])]; } } } $tmp = ArrayUtil::flattenByKey($events, 'time'); array_multisort($tmp, SORT_NUMERIC | SORT_ASC, $events); // Only apply offsets now, so we can detect nonsensical overlap $wolOffset = $options['wol-offset'] * 60; $sdOffset = $options['sd-offset'] * 60; $prev = PHP_INT_MAX; for ($i = count($events) - 1; $i >= 0; --$i) { $event =& $events[$i]; if ($event['action'] === 'wol') { $event['time'] -= $wolOffset; } elseif ($event['action'] === 'sd') { $event['time'] += $sdOffset; } else { error_log('BUG Unhandled event type ' . $event['action']); } if ($event['time'] >= $prev || $event['time'] < $now) { // Overlap, delete this event unset($events[$i]); } else { $prev = $event['time']; } } unset($event); // Reset array keys $events = array_values($events); // See which is the next suitable event to act upon $lastEvent = count($events) - 1; for ($i = 0; $i <= $lastEvent; $i++) { $event =& $events[$i]; $diff = ($i === $lastEvent ? PHP_INT_MAX : $events[$i + 1]['time'] - $event['time']); if ($diff < 300 && $event['action'] !== $events[$i + 1]['action']) { // If difference to next event is < 5 min, ignore. continue; } if ($diff < 900 && $event['action'] === 'sd' && $events[$i + 1]['action'] === 'wol') { // If difference to next WOL is < 15 min and this is a shutdown, reboot instead. $res['action'] = 'rb'; $res['time'] = $event['time']; } else { // Use first event. $res = $event; } return $res; } unset($event); return false; } }