Lines 88.88% 16 / 18
Functions and Methods 75.00% 3 / 4
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
Watch 88.88% 16 / 18 75.00% 3 / 4 8.09 0.00% 0 / 1
 __construct 84.61% 11 / 13 0.00% 0 / 1 4.06
 until 100.00% 1 / 1 100.00% 1 / 1 1
 token 100.00% 1 / 1 100.00% 1 / 1 1
 release 100.00% 3 / 3 100.00% 1 / 1 2
1<?php
2
3declare(strict_types=1);
4
5namespace Lorekeeper\Client;
6
7use Closure;
8use Psl\Async;
9use Psl\Async\Awaitable;
10use Psl\Async\CancellationTokenInterface;
11use Psl\Async\Exception\CancelledException;
12use Psl\Async\SignalCancellationToken;
13use Psl\DateTime\Duration;
14
15final class Watch
16{
17    private readonly SignalCancellationToken $token;
18
19    private readonly SignalCancellationToken $released;
20
21    /** @var Awaitable<void> */
22    private readonly Awaitable $watcher;
23
24    /** @param Closure(): bool $condition */
25    private function __construct(Closure $condition, Duration $every)
26    {
27        $this->token = new SignalCancellationToken();
28        $this->released = new SignalCancellationToken();
29
30        $token = $this->token;
31        $released = $this->released;
32        $this->watcher = Async\run(static function () use ($condition, $every, $token, $released): void {
33            while (!$released->isCancelled()) {
34                try {
35                    Async\sleep($every, $released);
36                } catch (CancelledException) {
37                    return;
38                }
39
40                if ($condition()) {
41                    $token->cancel();
42
43                    return;
44                }
45            }
46        });
47    }
48
49    /** @param Closure(): bool $condition */
50    public static function until(Closure $condition, ?Duration $every = null): self
51    {
52        return new self($condition, $every ?? Duration::seconds(1));
53    }
54
55    public function token(): CancellationTokenInterface
56    {
57        return $this->token;
58    }
59
60    public function release(): void
61    {
62        if (!$this->released->isCancelled()) {
63            $this->released->cancel();
64        }
65
66        $this->watcher->await();
67    }
68}