Passed
Push — develop ( 3c5942...636dd4 )
by Nikolay
04:57
created

PBX::musicOnHoldReload()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
dl 0
loc 10
rs 10
cc 1
nc 1
nop 0
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, 6 2020
7
 */
8
9
namespace MikoPBX\Core\System;
10
11
use MikoPBX\Common\Models\Codecs;
12
use MikoPBX\Core\Asterisk\CdrDb;
13
use MikoPBX\Core\Asterisk\Configs\{ExtensionsConf,
14
    FeaturesConf,
15
    HttpConf,
16
    IAXConf,
17
    IndicationConf,
18
    ManagerConf,
19
    ModulesConf,
20
    MusicOnHoldConf,
21
    SIPConf,
22
    VoiceMailConf
23
};
24
use MikoPBX\Core\Config\RegisterDIServices;
25
use MikoPBX\Core\Workers\WorkerAmiListener;
26
use MikoPBX\Core\Workers\WorkerCallEvents;
27
use Phalcon\Di;
28
29
/**
30
 * Class PBX
31
 *
32
 * @package MikoPBX\Core\System
33
 */
34
class PBX
35
{
36
    /**
37
     * @var bool
38
     */
39
    public $booting;
40
    private $di; // Link to the dependency injector
41
    private $arrObject;
42
    private $arr_gs;
43
    /**
44
     * @var \MikoPBX\Core\System\MikoPBXConfig
45
     */
46
    private $mikoPBXConfig;
47
48
    /**
49
     * PBX constructor.
50
     */
51
    public function __construct()
52
    {
53
        $this->di            = Di::getDefault();
54
        $this->mikoPBXConfig = new MikoPBXConfig();
55
        $this->arr_gs        = $this->mikoPBXConfig->getGeneralSettings();
56
        $this->booting       = $this->di->getRegistry()->booting;
0 ignored issues
show
Bug introduced by
The method getRegistry() does not exist on null. ( Ignorable by Annotation )

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

56
        $this->booting       = $this->di->/** @scrutinizer ignore-call */ getRegistry()->booting;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
57
        $this->arrObject     = $this->di->getShared('pbxConfModules');
58
    }
59
60
    /**
61
     * Перезапуск процесса Asterisk.
62
     */
63
    public static function restart(): void
64
    {
65
        $pbx = new PBX();
66
        $pbx->stop();
67
        $pbx->start();
68
    }
69
70
    /**
71
     * Остановка процесса Asterisk.
72
     */
73
    public function stop(): void
74
    {
75
        Util::killByName('safe_asterisk');
76
        sleep(1);
77
        $asteriskPath = Util::which('asterisk');
78
        Util::mwExec("{$asteriskPath} -rx 'core stop now'");
79
        Util::processWorker('', '', WorkerCallEvents::class, 'stop');
80
        Util::processWorker('', '', WorkerAmiListener::class, 'stop');
81
        Util::killByName('asterisk');
82
    }
83
84
    /**
85
     * Запуск процесса Asterisk.
86
     *
87
     */
88
    public function start(): void
89
    {
90
        Network::startSipDump();
91
        if (Util::isSystemctl()) {
92
            $systemctlPath = Util::which('systemctl');
93
            Util::mwExecBg("{$systemctlPath} restart asterisk");
94
        } else {
95
            $safe_asteriskPath = Util::which('safe_asterisk');
96
            Util::mwExecBg("{$safe_asteriskPath} -fn");
97
        }
98
    }
99
100
    public static function logRotate(): void
101
    {
102
        self::rotatePbxLog('messages');
103
        self::rotatePbxLog('security_log');
104
        self::rotatePbxLog('error');
105
    }
106
107
    public static function rotatePbxLog($f_name): void
108
    {
109
        $di           = Di::getDefault();
110
        $asteriskPath = Util::which('asterisk');
111
        if ($di === null) {
112
            return;
113
        }
114
        $max_size    = 2;
115
        $log_dir     = System::getLogDir() . '/asterisk/';
116
        $text_config = "{$log_dir}{$f_name} {
117
    nocreate
118
    nocopytruncate
119
    delaycompress
120
    nomissingok
121
    start 0
122
    rotate 9
123
    size {$max_size}M
124
    missingok
125
    noolddir
126
    postrotate
127
        {$asteriskPath} -rx 'logger reload' > /dev/null 2> /dev/null
128
    endscript
129
}";
130
        $varEtcPath  = $di->getShared('config')->path('core.varEtcPath');
131
        $path_conf   = $varEtcPath . '/asterisk_logrotate_' . $f_name . '.conf';
132
        file_put_contents($path_conf, $text_config);
133
        $mb10 = $max_size * 1024 * 1024;
134
135
        $options = '';
136
        if (Util::mFileSize("{$log_dir}{$f_name}") > $mb10) {
137
            $options = '-f';
138
        }
139
        $logrotatePath = Util::which('logrotate');
140
        Util::mwExecBg("{$logrotatePath} {$options} '{$path_conf}' > /dev/null 2> /dev/null");
141
    }
142
143
    /**
144
     * Перезапуск модуля features.
145
     *
146
     * @return array
147
     */
148
    public static function featuresReload(): array
149
    {
150
        $featuresConf = new FeaturesConf();
151
        $featuresConf->generateConfig();
152
        $result       = [
153
            'result' => 'Success',
154
        ];
155
        $arr_out      = [];
156
        $asteriskPath = Util::which('asterisk');
157
        Util::mwExec("{$asteriskPath} -rx 'module reload features'", $arr_out);
158
        $out = implode(' ', $arr_out);
159
        if ( ! "Module 'features' reloaded successfully." === $out) {
160
            $result['result'] = 'ERROR';
161
        }
162
        $result['data'] = $out;
163
164
        return $result;
165
    }
166
167
    /**
168
     * Перезапуск большинства модулей asterisk.
169
     *
170
     * @return array
171
     */
172
    public static function coreReload(): array
173
    {
174
        $featuresConf = new FeaturesConf();
175
        $featuresConf->generateConfig();
176
        $result       = [
177
            'result' => 'Success',
178
        ];
179
        $arr_out      = [];
180
        $asteriskPath = Util::which('asterisk');
181
        Util::mwExec("{$asteriskPath} -rx 'core reload'", $arr_out);
182
        $out = implode(' ', $arr_out);
183
        if ('' !== $out) {
184
            $result['result'] = 'ERROR';
185
        }
186
        $result['data'] = $out;
187
188
        return $result;
189
    }
190
191
    /**
192
     * Перезапуск manager модуля.
193
     *
194
     * @return array
195
     */
196
    public static function managerReload(): array
197
    {
198
        $managerCong = new ManagerConf();
199
        $managerCong->generateConfig();
200
201
        $httpConf = new HttpConf();
202
        $httpConf->generateConfig();
203
204
        $result       = [
205
            'result' => 'Success',
206
            'data'   => '',
207
        ];
208
        $arr_out      = [];
209
        $asteriskPath = Util::which('asterisk');
210
        Util::mwExec("{$asteriskPath} -rx 'module reload manager'", $arr_out);
211
        $out = implode(' ', $arr_out);
212
        if ( ! "Module 'manager' reloaded successfully." === $out) {
213
            $result['result'] = 'ERROR';
214
        }
215
        $result['data'] .= $out;
216
217
        Util::mwExec("{$asteriskPath} -rx 'module reload http'", $arr_out);
218
        $out = implode(' ', $arr_out);
219
        if ( ! "Module 'http' reloaded successfully." === trim($out)) {
220
            $result['result'] = 'ERROR';
221
        }
222
        $result['data'] .= " $out";
223
224
        return $result;
225
    }
226
227
    public static function musicOnHoldReload(): array
228
    {
229
        $o = new MusicOnHoldConf();
230
        $o->generateConfig();
231
        $asteriskPath = Util::which('asterisk');
232
        Util::mwExec("{$asteriskPath} -rx 'module reload manager'");
233
234
        return [
235
            'result' => 'Success',
236
            'data'   => '',
237
        ];
238
    }
239
240
    /**
241
     * Перезапуск модуля voicemail
242
     *
243
     * @return array
244
     */
245
    public static function voicemailReload(): array
246
    {
247
        $o = new VoiceMailConf();
248
        $o->generateConfig();
249
        $result       = [
250
            'result' => 'Success',
251
        ];
252
        $arr_out      = [];
253
        $asteriskPath = Util::which('asterisk');
254
        Util::mwExec("{$asteriskPath} -rx 'voicemail reload'", $arr_out);
255
        $out = implode(' ', $arr_out);
256
        if ('Reloading voicemail configuration...' !== $out) {
257
            $result['result'] = 'ERROR';
258
        }
259
        $result['data'] = $out;
260
261
        return $result;
262
    }
263
264
    public static function modulesReload(): array
265
    {
266
        $pbx = new ModulesConf();
267
        $pbx->generateConfig();
268
        $arr_out      = [];
269
        $asteriskPath = Util::which('asterisk');
270
        Util::mwExec("{$asteriskPath} -rx 'core restart now'", $arr_out);
271
272
        return [
273
            'result' => 'Success',
274
            'data'   => '',
275
        ];
276
    }
277
278
279
    public static function checkCodec($name, $desc, $type): void
280
    {
281
        $codec = Codecs::findFirst('name="' . $name . '"');
282
        if ($codec === null) {
283
            /** @var \MikoPBX\Common\Models\Codecs $codec_g722 */
284
            $codec              = new Codecs();
285
            $codec->name        = $name;
286
            $codec->type        = $type;
287
            $codec->description = $desc;
288
            $codec->save();
289
        }
290
    }
291
292
    /**
293
     * Reload SIP
294
     */
295
    public static function sipReload(): array
296
    {
297
        $di     = Di::getDefault();
298
        $result = [
299
            'result'  => 'ERROR',
300
            'message' => '',
301
        ];
302
        if ($di === null) {
303
            return $result;
304
        }
305
        $network = new Network();
306
307
        $topology    = 'public';
308
        $extipaddr   = '';
309
        $exthostname = '';
310
        $networks    = $network->getEnabledLanInterfaces();
311
        foreach ($networks as $if_data) {
312
            $lan_config = $network->getInterface($if_data['interface']);
313
            if (null === $lan_config['ipaddr'] || null === $lan_config['subnet']) {
314
                continue;
315
            }
316
            if (trim($if_data['internet']) === '1') {
317
                $topology    = trim($if_data['topology']);
318
                $extipaddr   = trim($if_data['extipaddr']);
319
                $exthostname = trim($if_data['exthostname']);
320
            }
321
        }
322
        $old_hash   = '';
323
        $varEtcPath = $di->getShared('config')->path('core.varEtcPath');
324
        if (file_exists($varEtcPath . '/topology_hash')) {
325
            $old_hash = file_get_contents($varEtcPath . '/topology_hash');
326
        }
327
        $now_hadh = md5($topology . $exthostname . $extipaddr);
328
329
        $sip = new SIPConf();
330
        $sip->generateConfig();
331
332
333
        $out = [];
334
        if ($old_hash === $now_hadh) {
335
            $asteriskPath = Util::which('asterisk');
336
            Util::mwExec("{$asteriskPath} -rx 'module reload acl'", $out);
337
            Util::mwExec("{$asteriskPath} -rx 'core reload'", $out);
338
            $out_data = trim(implode('', $out));
339
            if ($out_data !== '') {
340
                $result['message'] .= $out_data;
341
            }
342
        } else {
343
            // Завершаем каналы.
344
            $asteriskPath = Util::which('asterisk');
345
            Util::mwExec("{$asteriskPath} -rx 'channel request hangup all'", $out);
346
            usleep(500000);
347
            Util::mwExec("{$asteriskPath} -rx 'core restart now'", $out);
348
            $out_data = trim(implode('', $out));
349
            if ($out_data !== '') {
350
                $result['message'] .= $out_data;
351
            }
352
        }
353
354
        if ($result['message'] === '') {
355
            $result['result'] = 'Success';
356
        }
357
358
        return $result;
359
    }
360
361
    /**
362
     * Перезапуск модуля IAX2;
363
     */
364
    public static function iaxReload(): array
365
    {
366
        $result = [
367
            'result' => 'ERROR',
368
        ];
369
        $iax    = new IAXConf();
370
        $iax->generateConfig();
371
        $asteriskPath = Util::which('asterisk');
372
        Util::mwExec("{$asteriskPath} -rx 'iax2 reload'");
373
        $result['result'] = 'Success';
374
375
        return $result;
376
    }
377
378
    /**
379
     * Ожидаем полной загрузки asterisk.
380
     *
381
     * @return bool
382
     */
383
    public static function waitFullyBooted(): bool
384
    {
385
        $time_start = microtime(true);
386
        $result     = false;
387
        $out        = [];
388
        if (Util::isSystemctl()) {
389
            $options = '';
390
        } else {
391
            $options = '-t';
392
        }
393
        $timeoutPath  = Util::which('timeout');
394
        $asteriskPath = Util::which('asterisk');
395
        while (true) {
396
            $execResult = Util::mwExec(
397
                "{$timeoutPath} {$options} 1 {$asteriskPath} -rx'core waitfullybooted'",
398
                $out
399
            );
400
            if ($execResult === 0 && implode('', $out) === 'Asterisk has fully booted.') {
401
                $result = true;
402
                break;
403
            }
404
            $time = microtime(true) - $time_start;
405
            if ($time > 60) {
406
                Util::sysLogMsg(__CLASS__, 'Error: Asterisk has not booted');
407
                break;
408
            }
409
        }
410
411
        return $result;
412
    }
413
414
    /**
415
     * Generates all Asterisk configuration files and (re)starts the Asterisk process
416
     */
417
    public function configure(): array
418
    {
419
        $result = [
420
            'result' => 'ERROR',
421
        ];
422
423
        if ( ! $this->booting) {
424
            $this->stop();
425
        }
426
        /**
427
         * Создание конфигурационных файлов.
428
         */
429
        foreach ($this->arrObject as $appClass) {
430
            $appClass->generateConfig();
431
        }
432
        self::dialplanReload();
433
        if ($this->booting) {
434
            echo "   |- dialplan reload \033[32;1mdone\033[0m \n";
435
        }
436
        // Создание базы данных истории звонков.
437
        /** @var \Phalcon\Db\Adapter\Pdo\Sqlite $connection */
438
        $connection = $this->di->get('dbCDR');
439
        if ( ! $connection->tableExists('cdr')) {
440
            CdrDb::createDb();
441
            Util::CreateLogDB();
442
            RegisterDIServices::recreateDBConnections();
443
        } else {
444
            CdrDb::checkDb();
445
        }
446
447
        $result['result'] = 'Success';
448
449
        return $result;
450
    }
451
452
    /**
453
     * Запуск генератора dialplan.
454
     *
455
     * @return array
456
     */
457
    public static function dialplanReload(): array
458
    {
459
        $di      = Di::getDefault();
460
        $booting = $di->getRegistry()->booting;
461
        $result  = [
462
            'result' => 'ERROR',
463
        ];
464
        if ($di === null) {
465
            return $result;
466
        }
467
468
        $extensions = new ExtensionsConf();
469
        $extensions->generateConfig();
470
        if ($booting !== true) {
471
            $path_asterisk = Util::which('asterisk');
472
            Util::mwExec("{$path_asterisk} -rx 'dialplan reload'");
473
            Util::mwExec("{$path_asterisk} -rx 'module reload pbx_lua.so'");
474
        }
475
476
        $result['result'] = 'Success';
477
478
        return $result;
479
    }
480
481
}
482