TCP::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 2
eloc 13
c 2
b 0
f 1
nc 2
nop 1
dl 0
loc 24
rs 9.8333
1
<?php
2
/**
3
 * -> TCP
4
 * User: moyo
5
 * Date: 21/11/2017
6
 * Time: 3:58 PM
7
 */
8
9
namespace Carno\Log\Outputter;
10
11
use Carno\Log\Contracts\Closeable;
12
use Carno\Log\Contracts\Outputter;
13
use Carno\Log\Exception\MissingNWSocketException;
14
use Carno\Net\Address;
15
use Carno\Net\Contracts\TCP as Pipe;
16
use Carno\Net\Events;
17
use Carno\Promise\Promise;
18
use Carno\Promise\Promised;
19
use Carno\Socket\Socket;
0 ignored issues
show
Bug introduced by
The type Carno\Socket\Socket 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...
20
use Carno\Timer\Timer;
21
22
class TCP implements Outputter, Closeable
23
{
24
    /**
25
     * reconnect later if error occurred
26
     */
27
    private const RETRY_WAIT = 1500;
28
29
    /**
30
     * max buf size
31
     */
32
    private const BUF_OVERFLOW = 20000;
33
34
    /**
35
     * @var Address
36
     */
37
    private $endpoint = null;
38
39
    /**
40
     * @var Events
41
     */
42
    private $events = null;
43
44
    /**
45
     * @var Pipe
46
     */
47
    private $client = null;
48
49
    /**
50
     * @var bool
51
     */
52
    private $connected = false;
53
54
    /**
55
     * @var bool
56
     */
57
    private $closing = false;
58
59
    /**
60
     * @var Promised
61
     */
62
    private $closed = null;
63
64
    /**
65
     * @var array
66
     */
67
    private $buffer = [];
68
69
    /**
70
     * TCP constructor.
71
     * @param Address $endpoint
72
     */
73
    public function __construct(Address $endpoint)
74
    {
75
        if (!class_exists(Socket::class)) {
76
            trigger_error('NWSocket not loaded, tcp outputter will not working', E_USER_WARNING);
77
            throw new MissingNWSocketException();
78
        }
79
80
        $this->endpoint = $endpoint;
81
82
        $this->events = (new Events())
83
            ->attach(Events\Socket::CONNECTED, function () {
84
                $this->connected();
85
            })
86
            ->attach(Events\Socket::CLOSED, function () {
87
                $this->connecting();
88
            })
89
            ->attach(Events\Socket::ERROR, function () {
90
                Timer::after(self::RETRY_WAIT, function () {
91
                    $this->connecting();
92
                });
93
            })
94
        ;
95
96
        $this->connecting();
97
    }
98
99
    /**
100
     * reconnect to server if conn closed or error
101
     */
102
    private function connecting() : void
103
    {
104
        $this->connected = false;
105
        $this->closing
106
            ? $this->closed()->resolve()
107
            : $this->client = Socket::connect($this->endpoint, $this->events)
108
        ;
109
    }
110
111
    /**
112
     * conn established
113
     */
114
    private function connected() : void
115
    {
116
        $this->connected = true;
117
        while ($this->buffer) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->buffer of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
118
            $this->client->send(array_shift($this->buffer));
119
        }
120
    }
121
122
    /**
123
     * @param string $log
124
     */
125
    public function write(string $log) : void
126
    {
127
        if ($this->connected) {
128
            $this->client->send($log);
129
            return;
130
        }
131
132
        if (count($this->buffer) >= self::BUF_OVERFLOW) {
133
            return;
134
        }
135
136
        $this->buffer[] = $log;
137
    }
138
139
    /**
140
     * @return Promised
141
     */
142
    public function close() : Promised
143
    {
144
        if ($this->connected) {
145
            $this->closing = true;
146
            $this->client->close();
147
            return $this->closed();
148
        } else {
149
            return Promise::resolved();
150
        }
151
    }
152
153
    /**
154
     * @return Promised
155
     */
156
    public function closed() : Promised
157
    {
158
        return $this->closed ?? $this->closed = Promise::deferred();
159
    }
160
}
161