• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

azjezz / psl / 5603006711

pending completion
5603006711

push

github

azjezz
chore: update dependencies

Signed-off-by: azjezz <azjezz@protonmail.com>

4152 of 4194 relevant lines covered (99.0%)

49.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.49
/src/Psl/Network/Internal/AbstractStreamServer.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Psl\Network\Internal;
6

7
use Generator;
8
use Psl\Channel;
9
use Psl\Network;
10
use Psl\Network\StreamServerInterface;
11
use Revolt\EventLoop;
12

13
use function error_get_last;
14
use function fclose;
15
use function is_resource;
16
use function stream_socket_accept;
17

18
/**
19
 * @psalm-suppress UnnecessaryVarAnnotation
20
 */
21
abstract class AbstractStreamServer implements StreamServerInterface
22
{
23
    private const DEFAULT_IDLE_CONNECTIONS = 256;
24

25
    /**
26
     * @var closed-resource|resource|null $impl
27
     */
28
    private mixed $impl;
29

30
    /**
31
     * @var string
32
     */
33
    private string $watcher;
34

35
    /**
36
     * @var Channel\ReceiverInterface<array{true, Socket}|array{false, Network\Exception\RuntimeException}>
37
     */
38
    private Channel\ReceiverInterface $receiver;
39

40
    /**
41
     * @param resource $impl
42
     * @param int<1, max> $idleConnections
43
     */
44
    protected function __construct(mixed $impl, int $idleConnections = self::DEFAULT_IDLE_CONNECTIONS)
45
    {
46
        $this->impl = $impl;
11✔
47
        /**
48
         * @var Channel\SenderInterface<array{true, Socket}|array{false, Network\Exception\RuntimeException}> $sender
49
         */
50
        [$this->receiver, $sender] = Channel\bounded($idleConnections);
11✔
51
        $this->watcher = EventLoop::onReadable($impl, static function ($watcher, $resource) use ($sender): void {
11✔
52
            try {
53
                $sock = @stream_socket_accept($resource, timeout: 0.0);
7✔
54
                if ($sock !== false) {
7✔
55
                    $sender->send([true, new Socket($sock)]);
7✔
56

57
                    return;
7✔
58
                }
59

60
                // @codeCoverageIgnoreStart
61
                /** @var array{file: string, line: int, message: string, type: int} $err */
62
                $err = error_get_last();
63
                $sender->send([false, new Network\Exception\RuntimeException('Failed to accept incoming connection: ' . $err['message'], $err['type'])]);
64
                // @codeCoverageIgnoreEnd
65
            } catch (Channel\Exception\ClosedChannelException) {
×
66
                EventLoop::cancel($watcher);
×
67

68
                return;
×
69
            }
70
        });
11✔
71
    }
72

73
    /**
74
     * {@inheritDoc}
75
     */
76
    public function nextConnection(): Network\StreamSocketInterface
77
    {
78
        try {
79
            [$success, $result] = $this->receiver->receive();
8✔
80
        } catch (Channel\Exception\ClosedChannelException) {
2✔
81
            throw new Network\Exception\AlreadyStoppedException('Server socket has already been stopped.');
2✔
82
        }
83

84
        if ($success) {
6✔
85
            /** @var Socket $result */
86
            return $result;
6✔
87
        }
88

89
        /** @var Network\Exception\RuntimeException $result  */
90
        throw $result;
×
91
    }
92

93
    /**
94
     * {@inheritDoc}
95
     */
96
    public function incoming(): Generator
97
    {
98
        try {
99
            while (true) {
1✔
100
                [$success, $result] = $this->receiver->receive();
1✔
101
                if ($success) {
1✔
102
                    /** @var Socket $result */
103
                    yield null => $result;
1✔
104
                } else {
105
                    /** @var Network\Exception\RuntimeException $result  */
106
                    throw $result;
×
107
                }
108
            }
109
        } catch (Channel\Exception\ClosedChannelException) {
1✔
110
            return;
1✔
111
        }
112
    }
113

114
    /**
115
     * {@inheritDoc}
116
     */
117
    public function getLocalAddress(): Network\Address
118
    {
119
        if (!is_resource($this->impl)) {
7✔
120
            throw new Network\Exception\AlreadyStoppedException('Server socket has already been stopped.');
2✔
121
        }
122

123
        return Network\Internal\get_sock_name($this->impl);
5✔
124
    }
125

126
    public function __destruct()
127
    {
128
        /** @psalm-suppress MissingThrowsDocblock */
129
        $this->close();
11✔
130
    }
131

132
    /**
133
     * {@inheritDoc}
134
     */
135
    public function close(): void
136
    {
137
        EventLoop::disable($this->watcher);
11✔
138
        if (null === $this->impl) {
11✔
139
            return;
11✔
140
        }
141

142
        $this->receiver->close();
11✔
143
        $resource = $this->impl;
11✔
144
        $this->impl = null;
11✔
145
        if (is_resource($resource)) {
11✔
146
            fclose($resource);
11✔
147
        }
148
    }
149

150
    /**
151
     * {@inheritDoc}
152
     */
153
    public function getStream(): mixed
154
    {
155
        /** @var resource */
156
        return $this->impl;
2✔
157
    }
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc