Passed
Push — master ( 95cf87...c1f122 )
by Shiyu
01:51
created

UDPRelays::initialize()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
nc 3
nop 0
dl 0
loc 6
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * UDP Relays
4
 * User: moyo
5
 * Date: Jul 23, 2019
6
 * Time: 10:41
7
 */
8
9
namespace Carno\Traced\Transport;
10
11
use Carno\Net\Address;
12
use Carno\Promise\Promise;
13
use Carno\Promise\Promised;
14
use Carno\Tracing\Contracts\Transport;
15
use Swoole\Client;
0 ignored issues
show
Bug introduced by
The type Swoole\Client was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Closure;
17
18
class UDPRelays implements Transport
19
{
20
    public const MAGIC = '  ZU';
21
22
    /**
23
     * @var Address
24
     */
25
    private $endpoint = null;
26
27
    /**
28
     * @var string
29
     */
30
    private $identify = 'unknown';
31
32
    /**
33
     * @var bool
34
     */
35
    private $uxdomain = false;
36
37
    /**
38
     * @var Closure
39
     */
40
    private $sender = null;
41
42
    /**
43
     * @var resource
44
     */
45
    private $socket = null;
46
47
    /**
48
     * @var Client
49
     */
50
    private $client = null;
51
52
    /**
53
     */
54
    private function mkSwoole() : void
55
    {
56
        $this->client = new Client(
57
            $this->uxdomain ? SWOOLE_SOCK_UNIX_DGRAM : SWOOLE_SOCK_UDP,
0 ignored issues
show
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_UNIX_DGRAM was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_UDP was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
58
            PHP_SAPI === 'cli' ? SWOOLE_SOCK_ASYNC : SWOOLE_SOCK_SYNC
0 ignored issues
show
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_ASYNC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant Carno\Traced\Transport\SWOOLE_SOCK_SYNC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
59
        );
60
        $this->client->connect($this->endpoint->host(), $this->endpoint->port());
61
        $this->sender = function (string $data) {
62
            @$this->client->send($data);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for send(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

62
            /** @scrutinizer ignore-unhandled */ @$this->client->send($data);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
63
        };
64
    }
65
66
    /**
67
     */
68
    private function mkSockets() : void
69
    {
70
        $this->socket = socket_create(
71
            $this->uxdomain ? AF_UNIX : AF_INET,
72
            SOCK_DGRAM,
73
            $this->uxdomain ? IPPROTO_IP : SOL_UDP
74
        );
75
        $this->sender = function (string $data) {
76
            @socket_sendto(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for socket_sendto(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

76
            /** @scrutinizer ignore-unhandled */ @socket_sendto(

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
77
                $this->socket,
78
                $data,
79
                strlen($data),
80
                MSG_EOF,
81
                $this->endpoint->host(),
82
                $this->endpoint->port()
83
            );
84
        };
85
    }
86
87
    /**
88
     */
89
    private function initialize() : void
90
    {
91
        if (class_exists('\\Swoole\\Client')) {
92
            $this->mkSwoole();
93
        } elseif (function_exists('socket_create')) {
94
            $this->mkSockets();
95
        }
96
    }
97
98
    /**
99
     * @param Address $endpoint
100
     * @param string $identify
101
     */
102
    public function connect(Address $endpoint, string $identify = null) : void
103
    {
104
        $trim = " /\t\n";
105
106
        if ($endpoint->host() === '~') {
107
            $identify = rtrim($identify, $trim);
108
            $this->uxdomain = true;
109
            $this->identify = substr($identify, ($ips = strrpos($identify, '/')) + 1);
110
            $this->endpoint = new Address(substr($identify, 0, $ips));
111
        } else {
112
            $identify = trim($identify, $trim);
113
            $this->identify = $identify;
114
            $this->endpoint = $endpoint;
115
        }
116
117
        $this->initialize();
118
    }
119
120
    /**
121
     * @return Promised
122
     */
123
    public function disconnect() : Promised
124
    {
125
        $this->socket && socket_close($this->socket);
126
        $this->client && $this->client = null;
127
        return Promise::resolved();
128
    }
129
130
    /**
131
     * @param string $data
132
     */
133
    public function loading(string $data) : void
134
    {
135
        $this->sender && ($this->sender)($this->packing($data));
136
    }
137
138
    /**
139
     * @param string $payload
140
     * @return string
141
     */
142
    private function packing(string $payload) : string
143
    {
144
        return
145
            self::MAGIC .
146
            pack('N', strlen($this->identify)) .
147
            $this->identify .
148
            pack('N', strlen($payload)) .
149
            $payload
150
        ;
151
    }
152
153
    /**
154
     */
155
    public function flushing() : void
156
    {
157
    }
158
}
159