Passed
Push — develop ( 20b00c...f7632d )
by Nikolay
14:31
created

PBX::featuresReload()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2023 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\Core\System;
21
22
use MikoPBX\Common\Models\Codecs;
23
use MikoPBX\Common\Models\PbxSettings;
24
use MikoPBX\Common\Models\PbxSettingsConstants;
25
use MikoPBX\Common\Providers\CDRDatabaseProvider;
26
use MikoPBX\Common\Providers\PBXConfModulesProvider;
27
use MikoPBX\Common\Providers\RegistryProvider;
28
use MikoPBX\Core\Asterisk\CdrDb;
29
use MikoPBX\Core\Asterisk\Configs\{AclConf,
30
    AsteriskConf,
31
    AsteriskConfigClass,
32
    AsteriskConfigInterface,
33
    ConferenceConf,
34
    ExtensionsConf,
35
    FeaturesConf,
36
    HttpConf,
37
    IAXConf,
38
    IndicationConf,
39
    ManagerConf,
40
    ModulesConf,
41
    MusicOnHoldConf,
42
    RtpConf,
43
    SIPConf,
44
    VoiceMailConf};
45
use MikoPBX\Core\Workers\WorkerCallEvents;
46
use MikoPBX\Modules\Config\SystemConfigInterface;
47
use Phalcon\Di;
48
use Phalcon\Di\Injectable;
49
50
/**
51
 * Class PBX
52
 *
53
 * @package MikoPBX\Core\System
54
 */
55
class PBX extends Injectable
56
{
57
    /**
58
     * Restarts the Asterisk process.
59
     */
60
    public static function restart(): void
61
    {
62
        $pbx = new PBX();
63
        $pbx->stop();
64
        $pbx->start();
65
    }
66
67
    /**
68
     * Stops the Asterisk process.
69
     */
70
    public function stop(): void
71
    {
72
        Processes::killByName('safe_asterisk');
73
        sleep(1);
74
        $asteriskPath = Util::which('asterisk');
75
        Processes::mwExec("{$asteriskPath} -rx 'core stop now'");
76
        Processes::processWorker('', '', WorkerCallEvents::class, 'stop');
77
        Processes::killByName('asterisk');
78
    }
79
80
    /**
81
     * Starts the Asterisk process.
82
     */
83
    public function start(): void
84
    {
85
        Network::startSipDump();
86
        $safe_asteriskPath = Util::which('safe_asterisk');
87
        // The "-n" option disables color highlighting in Asterisk CLI.
88
        Processes::mwExecBg("{$safe_asteriskPath} -f");
89
        // Send notifications to modules
90
        PBXConfModulesProvider::hookModulesMethod(SystemConfigInterface::ON_AFTER_PBX_STARTED);
91
    }
92
93
    /**
94
     * Rotates the PBX log files.
95
     */
96
    public static function logRotate(): void
97
    {
98
        self::rotatePbxLog('messages');
99
        self::rotatePbxLog('security_log');
100
        self::rotatePbxLog('error');
101
        self::rotatePbxLog('verbose');
102
    }
103
104
    /**
105
     * Rotates the specified PBX log file.
106
     * @param string $fileName The name of the log file to rotate.
107
     */
108
    public static function rotatePbxLog($fileName): void
109
    {
110
        $di           = Di::getDefault();
111
        $asteriskPath = Util::which('asterisk');
112
        if ($di === null) {
113
            return;
114
        }
115
        $max_size    = 10;
116
        $log_dir     = System::getLogDir() . '/asterisk/';
0 ignored issues
show
Deprecated Code introduced by
The function MikoPBX\Core\System\System::getLogDir() has been deprecated: use Directories::getDir(Directories::CORE_LOGS_DIR); ( Ignorable by Annotation )

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

116
        $log_dir     = /** @scrutinizer ignore-deprecated */ System::getLogDir() . '/asterisk/';

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
117
        $text_config = "{$log_dir}{$fileName} {
118
    nocreate
119
    nocopytruncate
120
    delaycompress
121
    nomissingok
122
    start 0
123
    rotate 9
124
    size {$max_size}M
125
    missingok
126
    noolddir
127
    postrotate
128
        {$asteriskPath} -rx 'logger reload' > /dev/null 2> /dev/null
129
    endscript
130
}";
131
        $varEtcDir  = $di->getShared('config')->path('core.varEtcDir');
132
        $path_conf   = $varEtcDir . '/asterisk_logrotate_' . $fileName . '.conf';
133
        file_put_contents($path_conf, $text_config);
134
        $mb10 = $max_size * 1024 * 1024;
135
136
        $options = '';
137
        if (Util::mFileSize("{$log_dir}{$fileName}") > $mb10) {
138
            $options = '-f';
139
        }
140
        $logrotatePath = Util::which('logrotate');
141
        Processes::mwExecBg("{$logrotatePath} {$options} '{$path_conf}' > /dev/null 2> /dev/null");
142
    }
143
144
    /**
145
     * Refreshes the features configs and reloads the features module.
146
     */
147
    public static function featuresReload(): void
148
    {
149
        $featuresConf = new FeaturesConf();
150
        $featuresConf->generateConfig();
151
        $arr_out      = [];
152
        $asteriskPath = Util::which('asterisk');
153
        Processes::mwExec("{$asteriskPath} -rx 'module reload features'", $arr_out);
154
    }
155
156
    /**
157
     * Reloads the Asterisk core.
158
     */
159
    public static function coreReload(): void
160
    {
161
        $featuresConf = new FeaturesConf();
162
        $featuresConf->generateConfig();
163
164
        $asteriskConf = new AsteriskConf();
165
        $asteriskConf->generateConfig();
166
167
        $indicationConf = new IndicationConf();
168
        $indicationConf->generateConfig();
169
170
        $arr_out      = [];
171
        $asteriskPath = Util::which('asterisk');
172
        Processes::mwExec("{$asteriskPath} -rx 'core reload'", $arr_out);
173
    }
174
175
    /**
176
     * Restarts the Asterisk core.
177
     */
178
    public static function coreRestart(): void
179
    {
180
        $asteriskConf = new AsteriskConf();
181
        $asteriskConf->generateConfig();
182
183
        $indicationConf = new IndicationConf();
184
        $indicationConf->generateConfig();
185
186
        $asteriskPath = Util::which('asterisk');
187
        Processes::mwExec("{$asteriskPath} -rx 'core restart now'");
188
    }
189
190
    /**
191
     * Reloads the Asterisk manager interface module.
192
     */
193
    public static function managerReload(): void
194
    {
195
        $managerCong = new ManagerConf();
196
        $managerCong->generateConfig();
197
198
        $httpConf = new HttpConf();
199
        $httpConf->generateConfig();
200
201
        $arr_out      = [];
202
        $asteriskPath = Util::which('asterisk');
203
        Processes::mwExec("{$asteriskPath} -rx 'module reload manager'", $arr_out);
204
        Processes::mwExec("{$asteriskPath} -rx 'module reload http'", $arr_out);
205
    }
206
207
    /**
208
     * Reloads the Asterisk music on hold module.
209
     */
210
    public static function musicOnHoldReload(): void
211
    {
212
        $o = new MusicOnHoldConf();
213
        $o->generateConfig();
214
        $asteriskPath = Util::which('asterisk');
215
        Processes::mwExec("{$asteriskPath} -rx 'moh reload'");
216
    }
217
218
    /**
219
     * Reloads the Asterisk music on hold module.
220
     */
221
    public static function confBridgeReload(): void
222
    {
223
        $o = new ConferenceConf();
224
        $o->generateConfig();
225
        $asteriskPath = Util::which('asterisk');
226
        Processes::mwExec("$asteriskPath -rx 'module reload app_confbridge'");
227
    }
228
229
230
    /**
231
     * Reloads the Asterisk voicemail module.
232
     */
233
    public static function voicemailReload(): void
234
    {
235
        $o = new VoiceMailConf();
236
        $o->generateConfig();
237
        $arr_out      = [];
238
        $asteriskPath = Util::which('asterisk');
239
        Processes::mwExec("{$asteriskPath} -rx 'voicemail reload'", $arr_out);
240
    }
241
242
    /**
243
     * Reloads the Asterisk modules.
244
     * @return array
245
     */
246
    public static function modulesReload(): array
247
    {
248
        $pbx = new ModulesConf();
249
        $pbx->generateConfig();
250
        $arr_out      = [];
251
        $asteriskPath = Util::which('asterisk');
252
        Processes::mwExec("{$asteriskPath} -rx 'core restart now'", $arr_out);
253
254
        return [
255
            'result' => 'Success',
256
            'data'   => '',
257
        ];
258
    }
259
260
261
    /**
262
     * Checks if a codec exists and creates it if not.
263
     * @param string $name The name of the codec.
264
     * @param string $desc The description of the codec.
265
     * @param string $type The type of the codec.
266
     */
267
    public static function checkCodec($name, $desc, $type): void
268
    {
269
        $codec = Codecs::findFirst('name="' . $name . '"');
270
        if ($codec === null) {
271
            /** @var \MikoPBX\Common\Models\Codecs $codec */
272
            $codec              = new Codecs();
273
            $codec->name        = $name;
274
            $codec->type        = $type;
275
            $codec->description = $desc;
276
            $codec->save();
277
        }
278
    }
279
280
    /**
281
     * Refreshes the SIP configurations and reloads the PJSIP module.
282
     */
283
    public static function sipReload():void
284
    {
285
        $di     = Di::getDefault();
286
        if ($di === null) {
287
            return;
288
        }
289
        $sip = new SIPConf();
290
        $needRestart = $sip->needAsteriskRestart();
291
        $sip->generateConfig();
292
293
        $acl = new AclConf();
294
        $acl->generateConfig();
295
296
        $asteriskPath = Util::which('asterisk');
297
        if ($needRestart === false) {
298
            Processes::mwExec("{$asteriskPath} -rx 'module reload acl'");
299
            Processes::mwExec("{$asteriskPath} -rx 'core reload'");
300
        } else {
301
            SystemMessages::sysLogMsg('SIP RELOAD', 'Need reload asterisk',LOG_INFO);
302
            // Terminate channels.
303
            Processes::mwExec("{$asteriskPath} -rx 'channel request hangup all'");
304
            usleep(500000);
305
            Processes::mwExec("{$asteriskPath} -rx 'core restart now'");
306
        }
307
    }
308
309
    /**
310
     * Updates the RTP config file.
311
     */
312
    public static function rtpReload(): void
313
    {
314
        $rtp = new RtpConf();
315
        $rtp->generateConfig();
316
        $asteriskPath = Util::which('asterisk');
317
        Processes::mwExec("{$asteriskPath} -rx 'module reload res_rtp_asterisk'");
318
    }
319
320
    /**
321
     * Refreshes the IAX configurations and reloads the iax2 module.
322
     */
323
    public static function iaxReload(): void
324
    {
325
        $iax    = new IAXConf();
326
        $iax->generateConfig();
327
        $asteriskPath = Util::which('asterisk');
328
        Processes::mwExec("{$asteriskPath} -rx 'iax2 reload'");
329
    }
330
331
332
    /**
333
     * Waits for Asterisk to fully boot.
334
     * @return bool True if Asterisk has fully booted, false otherwise.
335
     */
336
    public static function waitFullyBooted(): bool
337
    {
338
        $time_start = microtime(true);
339
        $result     = false;
340
        $out        = [];
341
        $options = '';
342
343
        $timeoutPath  = Util::which('timeout');
344
        $asteriskPath = Util::which('asterisk');
345
        while (true) {
346
            $execResult = Processes::mwExec(
347
                "{$timeoutPath} {$options} 1 {$asteriskPath} -rx'core waitfullybooted'",
348
                $out
349
            );
350
            if ($execResult === 0 && implode('', $out) === 'Asterisk has fully booted.') {
351
                $result = true;
352
                break;
353
            }
354
            sleep(1);
355
            $time = microtime(true) - $time_start;
356
            if ($time > 60) {
357
                SystemMessages::sysLogMsg(__CLASS__, 'Error: Asterisk has not booted');
358
                break;
359
            }
360
        }
361
362
        return $result;
363
    }
364
365
    /**
366
     * Configures Asterisk by generating all configuration files and (re)starts the Asterisk process.
367
     * @return array The result of the configuration process.
368
     */
369
    public function configure(): array
370
    {
371
        if ( ! $this->di->getShared(RegistryProvider::SERVICE_NAME)->booting) {
372
            $this->stop();
373
        }
374
        self::updateSavePeriod();
375
        /**
376
         * Create configuration files.
377
         */
378
        $configClassObj = new AsteriskConfigClass();
379
        $configClassObj->hookModulesMethod(AsteriskConfigInterface::GENERATE_CONFIG);
380
381
        self::dialplanReload();
382
        if ($this->di->getShared(RegistryProvider::SERVICE_NAME)->booting) {
383
            $message = '   |- dialplan reload';
384
            SystemMessages::echoToTeletype($message);
385
            SystemMessages::echoWithSyslog($message);
386
            SystemMessages::echoResult($message);
387
            SystemMessages::teletypeEchoResult($message);
388
        }
389
        // Create the call history database.
390
        /** @var \Phalcon\Db\Adapter\Pdo\Sqlite $connection */
391
        $connection = $this->di->get(CDRDatabaseProvider::SERVICE_NAME);
392
        if ( ! $connection->tableExists('cdr')) {
393
            CDRDatabaseProvider::recreateDBConnections();
394
        } else {
395
            CdrDb::checkDb();
396
        }
397
        $result=[];
398
        $result['result'] = 'Success';
399
400
        return $result;
401
    }
402
403
    /**
404
     * Refreshes the extensions.conf file and reloads the Asterisk dialplan.
405
     */
406
    public static function dialplanReload(): void
407
    {
408
        $di = Di::getDefault();
409
        if ($di === null) {
410
            return;
411
        }
412
        if ($di->getShared(RegistryProvider::SERVICE_NAME)->booting !== true) {
413
            $extensions = new ExtensionsConf();
414
            $extensions->generateConfig();
415
            $path_asterisk = Util::which('asterisk');
416
            Processes::mwExec("{$path_asterisk} -rx 'dialplan reload'");
417
            Processes::mwExec("{$path_asterisk} -rx 'module reload pbx_lua.so'");
418
        }
419
    }
420
421
    /**
422
     * Save information on the period of storage of conversation recordings.
423
     * @param string $value
424
     * @return void
425
     */
426
    public static function updateSavePeriod(string $value = ''):void{
427
        if(empty($value)){
428
            $value = PbxSettings::getValueByKey(PbxSettingsConstants::PBX_RECORD_SAVE_PERIOD);
429
        }
430
        $filename   = '/var/etc/record-save-period';
431
        file_put_contents($filename, $value);
432
    }
433
434
}
435