Passed
Push — develop ( 6f8a0b...fc46da )
by Портнов
04:51
created

PBX::musicOnHoldReload()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 6
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
    ManagerConf,
39
    ModulesConf,
40
    MusicOnHoldConf,
41
    RtpConf,
42
    SIPConf,
43
    VoiceMailConf};
44
use MikoPBX\Core\Workers\WorkerCallEvents;
45
use MikoPBX\Modules\Config\SystemConfigInterface;
46
use Phalcon\Di;
47
use Phalcon\Di\Injectable;
48
49
/**
50
 * Class PBX
51
 *
52
 * @package MikoPBX\Core\System
53
 */
54
class PBX extends Injectable
55
{
56
    /**
57
     * Restarts the Asterisk process.
58
     */
59
    public static function restart(): void
60
    {
61
        $pbx = new PBX();
62
        $pbx->stop();
63
        $pbx->start();
64
    }
65
66
    /**
67
     * Stops the Asterisk process.
68
     */
69
    public function stop(): void
70
    {
71
        Processes::killByName('safe_asterisk');
72
        sleep(1);
73
        $asteriskPath = Util::which('asterisk');
74
        Processes::mwExec("{$asteriskPath} -rx 'core stop now'");
75
        Processes::processWorker('', '', WorkerCallEvents::class, 'stop');
76
        Processes::killByName('asterisk');
77
    }
78
79
    /**
80
     * Starts the Asterisk process.
81
     */
82
    public function start(): void
83
    {
84
        Network::startSipDump();
85
        $safe_asteriskPath = Util::which('safe_asterisk');
86
        // The "-n" option disables color highlighting in Asterisk CLI.
87
        Processes::mwExecBg("{$safe_asteriskPath} -f");
88
        // Send notifications to modules
89
        PBXConfModulesProvider::hookModulesMethod(SystemConfigInterface::ON_AFTER_PBX_STARTED);
90
    }
91
92
    /**
93
     * Rotates the PBX log files.
94
     */
95
    public static function logRotate(): void
96
    {
97
        self::rotatePbxLog('messages');
98
        self::rotatePbxLog('security_log');
99
        self::rotatePbxLog('error');
100
        self::rotatePbxLog('verbose');
101
    }
102
103
    /**
104
     * Rotates the specified PBX log file.
105
     * @param string $fileName The name of the log file to rotate.
106
     */
107
    public static function rotatePbxLog($fileName): void
108
    {
109
        $di           = Di::getDefault();
110
        $asteriskPath = Util::which('asterisk');
111
        if ($di === null) {
112
            return;
113
        }
114
        $max_size    = 10;
115
        $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

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