Passed
Push — develop ( fe499f...dd242c )
by Nikolay
05:43 queued 12s
created

WorkerLongPoolAPI::checkAction()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 25
rs 9.4222
c 0
b 0
f 0
cc 5
nc 8
nop 3
1
<?php
2
/**
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 7 2020
7
 */
8
9
namespace MikoPBX\PBXCoreREST\Workers;
10
require_once 'Globals.php';
11
use MikoPBX\Common\Models\LongPollSubscribe;
12
use MikoPBX\Core\System\BeanstalkClient;
13
use MikoPBX\Core\System\Util;
14
use MikoPBX\Core\Workers\WorkerBase;
15
use MikoPBX\PBXCoreREST\Lib\CdrDBProcessor;
16
use MikoPBX\PBXCoreREST\Lib\IAXStackProcessor;
17
use MikoPBX\PBXCoreREST\Lib\SIPStackProcessor;
18
19
use function clearstatcache;
20
21
22
/*
23
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/getRegistry' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
24
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/getActiveChannels' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
25
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/getActiveCalls' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
26
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/ping' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
27
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/common_channel' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
28
curl -s -v --no-buffer 'http://172.16.156.223/pbxcore/api/long/sub/test' -H 'Cookie: PHPSESSID=aec8c4ae8a26e3f74296ba0acaa3a692'
29
*/
30
31
class WorkerLongPoolAPI extends WorkerBase
32
{
33
    protected int $maxProc=1;
34
35
    public function start($argv): void
36
    {
37
38
        $client_queue = new BeanstalkClient();
39
        $client_queue->subscribe($this->makePingTubeName(self::class), [$this, 'pingCallBack']);
40
41
        $ACTIONS         = [];
42
        $COMMON_CNANNELS = [];
43
44
        while (true) {
45
            $data = $this->getData('http://localhost/pbxcore/api/long/channels-stats?id=ALL');
46
            $this->setChannelsData();
47
            if ($data && isset($data['infos'])) {
48
                foreach ($data['infos'] as $channel_data) {
49
                    $url = 'http://localhost/pbxcore/api/long/pub?id=' . $channel_data['channel'];
50
51
                    $data_for_send = $this->execFunction($channel_data['channel']);
52
                    if ($data_for_send) {
53
                        $ACTIONS[$channel_data['channel']]['last_action'] = time();
54
                        $this->postData($url, "$data_for_send\n");
55
                    }
56
57
                    if ( ! isset($COMMON_CNANNELS[$channel_data['channel']])) {
58
                        continue;
59
                    }
60
61
                    $common_actions = $COMMON_CNANNELS[$channel_data['channel']];
62
                    foreach ($common_actions as $action => $action_data) {
63
                        $data_for_send = $this->execFunction($action, $channel_data['channel']);
64
                        if ($data_for_send !== '') {
65
                            $COMMON_CNANNELS[$channel_data['channel']][$action]['last_action'] = time();
66
                            $this->postData($url, "$data_for_send\n");
67
                        }
68
                    }
69
                }
70
            }
71
            $client_queue->wait(1); // instead of sleep
72
        }
73
    }
74
75
    /**
76
     * Проверяет наличие активных подписок LongPoll и отправляет с периодичностью новые данные.
77
     */
78
79
    /**
80
     * Отправляет GET запрос по http. Возвращает ответ в виде массива.
81
     *
82
     * @param string $url
83
     *
84
     * @return string
85
     */
86
    private function getData($url)
87
    {
88
        $ch = curl_init($url);
89
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

89
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_RETURNTRANSFER, true);
Loading history...
90
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);
91
        $resultrequest = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

91
        $resultrequest = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
92
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

92
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
93
94
        return json_decode($resultrequest, true);
95
    }
96
97
    private function setChannelsData(): void
98
    {
99
        /** @var \MikoPBX\Common\Models\LongPollSubscribe $sub */
100
        $subscribes = LongPollSubscribe::find('enable=1');
101
102
        /** @var \MikoPBX\Common\Models\LongPollSubscribe $sub */
103
        foreach ($subscribes as $sub) {
104
            $last_action                                     = $GLOBALS['ACTIONS'][$sub->action]['last_action'] ?? time(
105
                ) - 1;
106
            $GLOBALS['ACTIONS'][$sub->action]                = $sub->toArray();
107
            $GLOBALS['ACTIONS'][$sub->action]['last_action'] = $last_action;
108
109
110
            $last_action                                                            = $GLOBALS['COMMON_CNANNELS'][$sub->channel][$sub->action]['last_action'] ?? time(
111
                ) - 1;
112
            $GLOBALS['COMMON_CNANNELS'][$sub->channel][$sub->action]                = $sub->toArray();
113
            $GLOBALS['COMMON_CNANNELS'][$sub->channel][$sub->action]['last_action'] = $last_action;
114
        }
115
    }
116
117
    /**
118
     * Выполнение метода API.
119
     *
120
     * @param $channel
121
     * @param $common_chan
122
     *
123
     * @return false|string|null
124
     */
125
    private function execFunction($channel, $common_chan = null)
126
    {
127
        clearstatcache();
128
        if ( ! $this->checkAction($channel, $data, $common_chan)) {
129
            return '';
130
        }
131
        $data          = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
132
        $data_for_send = null;
133
        if ('ping' === $channel) {
134
            $data_for_send = 'PONG';
135
        } elseif ('getActiveChannels' === $channel) {
136
            $data_for_send = CdrDBProcessor::getActiveChannels()->getResult();
137
        } elseif ('getActiveCalls' === $channel) {
138
            $data_for_send = CdrDBProcessor::getActiveCalls()->getResult();
139
        } elseif ('getRegistry' === $channel) {
140
            $result        = [
141
                'SIP' => SIPStackProcessor::getRegistry()->getResult(),
142
                'IAX' => IAXStackProcessor::getRegistry()->getResult(),
143
            ];
144
            $data_for_send = json_encode($result, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
145
        }
146
147
        return $data_for_send;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $data_for_send also could return the type array<string,array|mixed|string> which is incompatible with the documented return type false|null|string.
Loading history...
148
    }
149
150
    /**
151
     * Проверка допустимости выполнения дейсвтия в данный момент времени.
152
     *
153
     * @param $channel
154
     * @param $data
155
     * @param $common_chan
156
     *
157
     * @return bool
158
     */
159
    private function checkAction($channel, &$data, $common_chan = null)
160
    {
161
        if ( ! $common_chan) {
162
            $actions = $GLOBALS['ACTIONS'];
163
        } else {
164
            $actions = $GLOBALS['COMMON_CNANNELS'][$common_chan];
165
        }
166
167
        $enable = false;
168
        if ( ! $actions) {
169
            return $enable;
170
        }
171
        $data = null;
172
        $now  = time();
173
174
        $action_data = $actions[$channel] ?? null;
175
        if ($action_data !== null) {
176
            $timeout = $action_data['timeout'];
177
            $data    = $action_data['data'];
178
            if (($now - $action_data['last_action']) > $timeout) {
179
                $enable = true;
180
            }
181
        }
182
183
        return $enable;
184
    }
185
186
    /**
187
     * Отправляет POST запрос по http. Возвращает ответ в виде массива.
188
     *
189
     * @param string $url
190
     * @param string $data
191
     *
192
     * @return string
193
     */
194
    private function postData($url, $data)
195
    {
196
        $ch = curl_init($url);
197
        curl_setopt($ch, CURLOPT_POST, 1);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

197
        curl_setopt(/** @scrutinizer ignore-type */ $ch, CURLOPT_POST, 1);
Loading history...
198
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
199
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
200
        curl_setopt($ch, CURLOPT_TIMEOUT, 1);
201
        $resultrequest = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

201
        $resultrequest = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
202
        curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

202
        curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
203
204
        return json_decode($resultrequest, true);
205
    }
206
207
}
208
209
// Start worker process
210
$workerClassname = WorkerLongPoolAPI::class;
211
if (isset($argv) && count($argv) > 1) {
212
    cli_set_process_title($workerClassname);
213
    try {
214
        $worker = new $workerClassname();
215
        $worker->start($argv);
216
    } catch (\Exception $e) {
217
        global $errorLogger;
218
        $errorLogger->captureException($e);
219
        Util::sysLogMsg("{$workerClassname}_EXCEPTION", $e->getMessage());
220
    }
221
}