1<?php
2// Icinga Web 2 X.509 Module | (c) 2018 Icinga GmbH | GPLv2
3
4namespace Icinga\Module\X509;
5
6use Cron\CronExpression;
7use Icinga\Application\Logger;
8use React\EventLoop\Factory as Loop;
9
10class Scheduler
11{
12    protected $loop;
13
14    public function __construct()
15    {
16        $this->loop = Loop::create();
17    }
18
19    public function add($name, $cronSchedule, callable $callback)
20    {
21        if (! CronExpression::isValidExpression($cronSchedule)) {
22            throw new \RuntimeException('Invalid cron expression');
23        }
24
25        $now = new \DateTime();
26
27        $expression = CronExpression::factory($cronSchedule);
28
29        if ($expression->isDue($now)) {
30            $this->loop->futureTick($callback);
31        }
32
33        $nextRuns = $expression->getMultipleRunDates(2, $now);
34
35        $interval = $nextRuns[0]->getTimestamp() - $now->getTimestamp();
36
37        $period = $nextRuns[1]->getTimestamp() - $nextRuns[0]->getTimestamp();
38
39        Logger::info('Scheduling job %s to run at %s.', $name, $nextRuns[0]->format('Y-m-d H:i:s'));
40
41        $loop = function () use (&$loop, $name, $callback, $period) {
42            $callback();
43
44            $nextRun = (new \DateTime())
45                ->add(new \DateInterval("PT{$period}S"));
46
47            Logger::info('Scheduling job %s to run at %s.', $name, $nextRun->format('Y-m-d H:i:s'));
48
49            $this->loop->addTimer($period, $loop);
50        };
51
52        $this->loop->addTimer($interval, $loop);
53    }
54
55    public function run()
56    {
57        $this->loop->run();
58    }
59}
60