Passed
Push — develop ( b5c301...121c4e )
by Портнов
04:48
created

WorkerModelsEvents::reloadSSH()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 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\Workers;
21
22
require_once 'Globals.php';
23
24
use MikoPBX\Common\Models\{AsteriskManagerUsers,
25
    CallQueueMembers,
26
    CallQueues,
27
    Codecs,
28
    ConferenceRooms,
29
    CustomFiles,
30
    DialplanApplications,
31
    ExtensionForwardingRights,
32
    Extensions,
33
    ExternalPhones,
34
    Fail2BanRules,
35
    FirewallRules,
36
    Iax,
37
    IncomingRoutingTable,
38
    IvrMenu,
39
    IvrMenuActions,
40
    LanInterfaces,
41
    NetworkFilters,
42
    OutgoingRoutingTable,
43
    OutWorkTimes,
44
    PbxExtensionModules,
45
    PbxSettings,
46
    Sip,
47
    SoundFiles
48
};
49
use MikoPBX\Common\Providers\BeanstalkConnectionModelsProvider;
50
use MikoPBX\Core\Asterisk\Configs\QueueConf;
51
use MikoPBX\Core\System\{BeanstalkClient,
52
    Configs\CronConf,
53
    Configs\Fail2BanConf,
54
    Configs\IptablesConf,
55
    Configs\NatsConf,
56
    Configs\NginxConf,
57
    Configs\NTPConf,
58
    Configs\PHPConf,
59
    Configs\SSHConf,
60
    Configs\SyslogConf,
61
    PBX,
62
    Processes,
63
    System,
64
    Util};
65
use MikoPBX\PBXCoreREST\Workers\WorkerApiCommands;
66
use Phalcon\Di;
67
use Pheanstalk\Contract\PheanstalkInterface;
68
use Throwable;
69
70
ini_set('error_reporting', E_ALL);
71
ini_set('display_startup_errors', 1);
72
73
class WorkerModelsEvents extends WorkerBase
74
{
75
    private const R_MANAGERS     = 'reloadManager';
76
77
    public const R_NEED_RESTART  = 'needRestart';
78
79
    private const R_QUEUES = 'reloadQueues';
80
81
    private const R_DIALPLAN = 'reloadDialplan';
82
83
    private const R_CUSTOM_F = 'updateCustomFiles';
84
85
    private const R_FIREWALL = 'reloadFirewall';
86
87
    private const R_NETWORK = 'networkReload';
88
89
    private const R_IAX = 'reloadIax';
90
91
    private const R_SIP = 'reloadSip';
92
93
    private const R_FEATURES = 'reloadFeatures';
94
95
    private const R_CRON = 'reloadCron';
96
97
    public const  R_NGINX = 'reloadNginx';
98
99
    public const  R_NGINX_CONF    = 'reloadNginxConf';
100
101
    public const  R_FAIL2BAN_CONF = 'reloadFail2BanConf';
102
103
    private const R_PHP_FPM = 'reloadPHPFPM';
104
105
    private const R_TIMEZONE = 'updateTomeZone';
106
107
    private const R_SYSLOG   = 'restartSyslogD';
108
109
    private const R_SSH = 'reloadSSH';
110
111
    private const R_LICENSE = 'reloadLicense';
112
113
    private const R_NATS = 'reloadNats';
114
115
    private const R_VOICEMAIL = 'reloadVoicemail';
116
117
    private const R_REST_API_WORKER = 'reloadRestAPIWorker';
118
119
    private const R_CALL_EVENTS_WORKER = 'reloadWorkerCallEvents';
120
121
    private const R_PBX_EXTENSION_STATE = 'afterModuleStateChanged';
122
123
    private const R_MOH = 'reloadMoh';
124
125
    private const R_NTP = 'reloadNtp';
126
127
    private int $last_change;
128
    private array $modified_tables;
129
130
    private int $timeout = 2;
131
    private array $arrObject;
132
    private array $PRIORITY_R;
133
134
135
    /**
136
     * Entry point
137
     *
138
     * @param $argv
139
     */
140
    public function start($argv): void
141
    {
142
        $this->last_change = time() - 2;
143
        $this->arrObject = $this->di->getShared('pbxConfModules');
144
145
        $this->PRIORITY_R = [
146
            self::R_TIMEZONE,
147
            self::R_SYSLOG,
148
            self::R_REST_API_WORKER,
149
            self::R_NETWORK,
150
            self::R_FIREWALL,
151
            self::R_FAIL2BAN_CONF,
152
            self::R_SSH,
153
            self::R_LICENSE,
154
            self::R_NATS,
155
            self::R_NTP,
156
            self::R_PHP_FPM,
157
            self::R_NGINX,
158
            self::R_NGINX_CONF,
159
            self::R_CRON,
160
            self::R_FEATURES,
161
            self::R_SIP,
162
            self::R_IAX,
163
            self::R_DIALPLAN,
164
            self::R_QUEUES,
165
            self::R_MANAGERS,
166
            self::R_CUSTOM_F,
167
            self::R_VOICEMAIL,
168
            self::R_MOH,
169
            self::R_CALL_EVENTS_WORKER,
170
            self::R_PBX_EXTENSION_STATE,
171
        ];
172
173
        $this->modified_tables = [];
174
175
        /** @var BeanstalkClient $client */
176
        $client = $this->di->getShared(BeanstalkConnectionModelsProvider::SERVICE_NAME);
177
        $client->subscribe(self::class, [$this, 'processModelChanges']);
178
        $client->subscribe($this->makePingTubeName(self::class), [$this, 'pingCallBack']);
179
        $client->setTimeoutHandler([$this, 'timeoutHandler']);
180
181
        while ($this->needRestart === false) {
182
            $client->wait(1);
183
        }
184
        // Execute all collected changes before exit
185
        $this->timeoutHandler();
186
    }
187
188
    /**
189
     * Parses for received Beanstalk message
190
     *
191
     * @param BeanstalkClient $message
192
     * @throws \JsonException
193
     */
194
    public function processModelChanges(BeanstalkClient $message): void
195
    {
196
        $data = $message->getBody();
197
        $receivedMessage = null;
198
        if($data === self::R_NEED_RESTART){
199
            $this->needRestart();
200
        }
201
        if(in_array($data, $this->PRIORITY_R, true)){
202
            $this->modified_tables[$data] = true;
203
        }else{
204
            $receivedMessage = json_decode($message->getBody(), true, 512, JSON_THROW_ON_ERROR);
205
            $this->fillModifiedTables($receivedMessage);
206
207
        }
208
        $this->startReload();
209
        if(!$receivedMessage){
210
            return;
211
        }
212
        // Send information about models changes to additional modules
213
        foreach ($this->arrObject as $appClass) {
214
            $appClass->modelsEventChangeData($receivedMessage);
215
        }
216
    }
217
218
    /**
219
     * Collects changes to determine which modules must be reloaded or reconfigured
220
     *
221
     * @param array $data
222
     */
223
    private function fillModifiedTables(array $data): void
224
    {
225
226
        $count_changes = count($this->modified_tables);
227
        $called_class  = $data['model'] ?? '';
228
        Util::sysLogMsg(__METHOD__, "New changes ".$called_class, LOG_DEBUG);
229
230
        // Clear all caches on any changed models on backend
231
        PbxSettings::clearCache($called_class, false);
232
233
        // Get new settings gor dependence modules
234
        foreach ($this->arrObject as $appClass) {
235
            $dependencies = $appClass->dependenceModels();
236
            if (in_array($called_class, $dependencies, true)) {
237
                $appClass->getSettings();
238
            }
239
        }
240
241
        switch ($called_class) {
242
            case AsteriskManagerUsers::class:
243
                $this->modified_tables[self::R_MANAGERS] = true;
244
                break;
245
            case CallQueueMembers::class:
246
                $this->modified_tables[self::R_QUEUES] = true;
247
                break;
248
            case CallQueues::class:
249
                $this->modified_tables[self::R_QUEUES]   = true;
250
                $this->modified_tables[self::R_DIALPLAN] = true;
251
                break;
252
            case ExternalPhones::class:
253
            case Extensions::class:
254
            case DialplanApplications::class:
255
            case IncomingRoutingTable::class:
256
            case IvrMenu::class:
257
            case IvrMenuActions::class:
258
            case OutgoingRoutingTable::class:
259
            case OutWorkTimes::class:
260
            case ConferenceRooms::class:
261
                $this->modified_tables[self::R_DIALPLAN] = true;
262
                break;
263
            case CustomFiles::class:
264
                $this->modified_tables[self::R_CUSTOM_F] = true;
265
                break;
266
            case Sip::class:
267
            case ExtensionForwardingRights::class:
268
                $this->modified_tables[self::R_SIP]      = true;
269
                $this->modified_tables[self::R_DIALPLAN] = true;
270
                break;
271
            case FirewallRules::class:
272
            case Fail2BanRules::class:
273
                $this->modified_tables[self::R_FIREWALL] = true;
274
                break;
275
            case Iax::class:
276
                $this->modified_tables[self::R_IAX]      = true;
277
                $this->modified_tables[self::R_DIALPLAN] = true;
278
                break;
279
            case Codecs::class:
280
                $this->modified_tables[self::R_IAX] = true;
281
                $this->modified_tables[self::R_SIP] = true;
282
                break;
283
            case SoundFiles::class:
284
                $this->modified_tables[self::R_MOH]      = true;
285
                $this->modified_tables[self::R_DIALPLAN] = true;
286
                break;
287
            case LanInterfaces::class:
288
                $this->modified_tables[self::R_NETWORK] = true;
289
                $this->modified_tables[self::R_IAX]     = true;
290
                $this->modified_tables[self::R_SIP]     = true;
291
                break;
292
            case NetworkFilters::class:
293
                $this->modified_tables[self::R_FIREWALL] = true;
294
                $this->modified_tables[self::R_SIP]      = true;
295
                $this->modified_tables[self::R_MANAGERS] = true;
296
                break;
297
            case PbxSettings::class:
298
                $pbxSettings = PbxSettings::findFirstByKey($data['recordId']);
299
                if ($pbxSettings === null) {
300
                    return;
301
                }
302
                if ($pbxSettings->itHasFeaturesSettingsChanges()) {
303
                    $this->modified_tables[self::R_FEATURES] = true;
304
                    $this->modified_tables[self::R_DIALPLAN] = true;
305
                }
306
                if ($pbxSettings->itHasAMIParametersChanges()) {
307
                    $this->modified_tables[self::R_MANAGERS] = true;
308
                }
309
                if ($pbxSettings->itHasIaxParametersChanges()) {
310
                    $this->modified_tables[self::R_IAX] = true;
311
                }
312
                if ($pbxSettings->itHasSipParametersChanges()) {
313
                    $this->modified_tables[self::R_SIP] = true;
314
                }
315
                if ($pbxSettings->itHasSSHParametersChanges()) {
316
                    $this->modified_tables[self::R_SSH] = true;
317
                }
318
                if ($pbxSettings->itHasFirewallParametersChanges()) {
319
                    $this->modified_tables[self::R_FIREWALL] = true;
320
                }
321
                if ($pbxSettings->itHasWebParametersChanges()) {
322
                    $this->modified_tables[self::R_NGINX] = true;
323
                }
324
                if ($pbxSettings->itHasCronParametersChanges()) {
325
                    $this->modified_tables[self::R_CRON] = true;
326
                }
327
                if ($pbxSettings->itHasDialplanParametersChanges()) {
328
                    $this->modified_tables[self::R_DIALPLAN] = true;
329
                }
330
                if ($pbxSettings->itHasVoiceMailParametersChanges()) {
331
                    $this->modified_tables[self::R_VOICEMAIL] = true;
332
                }
333
                if ($pbxSettings->itHasVisualLanguageSettings()) {
334
                    $this->modified_tables[self::R_REST_API_WORKER] = true;
335
                }
336
                if ($pbxSettings->itHasLicenseSettings()) {
337
                    $this->modified_tables[self::R_LICENSE] = true;
338
                    $this->modified_tables[self::R_NATS]    = true;
339
                }
340
                if ($pbxSettings->itHasTimeZoneSettings()) {
341
                    $this->modified_tables[self::R_TIMEZONE]        = true;
342
                    $this->modified_tables[self::R_NGINX]           = true;
343
                    $this->modified_tables[self::R_PHP_FPM]         = true;
344
                    $this->modified_tables[self::R_REST_API_WORKER] = true;
345
                    $this->modified_tables[self::R_SYSLOG]        = true;
346
                }
347
                if ($pbxSettings->itHasNTPSettings()) {
348
                    $this->modified_tables[self::R_NTP] = true;
349
                }
350
                if ($pbxSettings->itHasCallRecordSettings()) {
351
                    $this->modified_tables[self::R_CALL_EVENTS_WORKER] = true;
352
                    $this->modified_tables[self::R_DIALPLAN]           = true;
353
                }
354
                break;
355
            case PbxExtensionModules::class:
356
                $moduleSettings                                                   = PbxExtensionModules::findFirstById(
357
                    $data['recordId']
358
                );
359
                $this->modified_tables[self::R_PBX_EXTENSION_STATE]               = true;
360
                $this->modified_tables['parameters'][self::R_PBX_EXTENSION_STATE] = $moduleSettings;
361
                $this->modified_tables[self::R_CRON]                              = true;
362
                break;
363
            default:
364
        }
365
366
        if ($count_changes === 0 && count($this->modified_tables) > 0) {
367
            // Начинаем отсчет времени при получении первой задачи.
368
            $this->last_change = time();
369
        }
370
    }
371
372
    /**
373
     * Apply changes
374
     *
375
     * @return void
376
     */
377
    private function startReload(): void
378
    {
379
        if (count($this->modified_tables) === 0) {
380
            return;
381
        }
382
        $delta = time() - $this->last_change;
383
        if ($delta < $this->timeout) {
384
            return;
385
        }
386
387
        foreach ($this->PRIORITY_R as $method_name) {
388
            $action     = $this->modified_tables[$method_name] ?? null;
389
            $parameters = $this->modified_tables['parameters'][$method_name] ?? null;
390
            if ($action === null) {
391
                continue;
392
            }
393
            if (method_exists($this, $method_name)) {
394
                Util::sysLogMsg(__METHOD__, "Process changes by {$method_name}", LOG_DEBUG);
395
                if ($parameters === null) {
396
                    $this->$method_name();
397
                } else {
398
                    $this->$method_name($parameters);
399
                }
400
            }
401
        }
402
403
        foreach ($this->arrObject as $appClass) {
404
            $appClass->modelsEventNeedReload($this->modified_tables);
405
        }
406
        $this->modified_tables = [];
407
    }
408
409
410
    /**
411
     * Restarts gnats queue server daemon
412
     */
413
    public function reloadNats(): void
414
    {
415
        $natsConf = new NatsConf();
416
        $natsConf->reStart();
417
    }
418
419
420
    /**
421
     * Reloads Asterisk dialplan
422
     */
423
    public function reloadDialplan(): void
424
    {
425
        PBX::dialplanReload();
426
    }
427
428
    /**
429
     * Reloads Asterisk manager interface module
430
     */
431
    public function reloadManager(): void
432
    {
433
        PBX::managerReload();
434
    }
435
436
    /**
437
     * Generates queue.conf and restart asterisk queue module
438
     */
439
    public function reloadQueues(): void
440
    {
441
        QueueConf::queueReload();
442
    }
443
444
    /**
445
     * Updates custom changes in config files
446
     */
447
    public function updateCustomFiles(): void
448
    {
449
        System::updateCustomFiles();
450
    }
451
452
    /**
453
     * Apply iptable settings and restart firewall
454
     */
455
    public function reloadFirewall(): void
456
    {
457
        IptablesConf::reloadFirewall();
458
    }
459
460
    /**
461
     *  Refresh networks configs and restarts network daemon
462
     */
463
    public function networkReload(): void
464
    {
465
        System::networkReload();
466
    }
467
468
    /**
469
     * Refresh IAX configs and reload iax2 module
470
     */
471
    public function reloadIax(): void
472
    {
473
        PBX::iaxReload();
474
    }
475
476
    /**
477
     * Reload MOH file list in Asterisk.
478
     */
479
    public function reloadMoh(): void
480
    {
481
        PBX::mohReload();
482
    }
483
484
    /**
485
     * Refresh SIP configs and reload PJSIP module
486
     */
487
    public function reloadSip(): void
488
    {
489
        PBX::sipReload();
490
    }
491
492
    /**
493
     *  Refresh features configs and reload features module
494
     */
495
    public function reloadFeatures(): void
496
    {
497
        PBX::featuresReload();
498
    }
499
500
    /**
501
     * Restarts CROND daemon
502
     */
503
    public function reloadCron(): void
504
    {
505
        $cron = new CronConf();
506
        $cron->reStart();
507
    }
508
509
    /**
510
     * Restarts NTP daemon
511
     */
512
    public function reloadNtp(): void
513
    {
514
        NTPConf::configure();
515
    }
516
517
    /**
518
     * Restarts Nginx daemon
519
     */
520
    public function reloadNginx(): void
521
    {
522
        $nginxConf = new NginxConf();
523
        $nginxConf->generateConf();
524
        $nginxConf->reStart();
525
    }
526
527
    /**
528
     * Restarts Nginx daemon
529
     */
530
    public function reloadNginxConf(): void
531
    {
532
        // Обновляем конфигурацию Nginx.
533
        $nginxConf = new NginxConf();
534
        $nginxConf->generateModulesConf();
535
        $nginxConf->reStart();
536
    }
537
538
    /**
539
     * Restarts Nginx daemon
540
     */
541
    public function reloadFail2BanConf(): void{
542
        Fail2BanConf::reloadFail2ban();
543
    }
544
545
    /**
546
     * Restarts Nginx daemon
547
     */
548
    public function needRestart(): void{
549
        $this->needRestart = true;
550
    }
551
552
    /**
553
     * Restarts PHP-FPM daemon
554
     */
555
    public function reloadPHPFPM(): void
556
    {
557
        PHPConf::reStart();
558
    }
559
560
    /**
561
     * Configure SSH settings
562
     */
563
    public function reloadSSH(): void
564
    {
565
        $sshConf = new SSHConf();
566
        $sshConf->configure();
567
    }
568
569
    /**
570
     * Reconfigure TomeZone settings
571
     */
572
    public function updateTomeZone(): void
573
    {
574
        System::timezoneConfigure();
575
    }
576
577
    /**
578
     * Перезапуск rsyslog.
579
     */
580
    public function restartSyslogD(): void
581
    {
582
        // Рестарт демона Syslog.
583
        $syslogConf = new SyslogConf();
584
        $syslogConf->reStart();
585
    }
586
587
    /**
588
     *  Reloads Asterisk voicemail module
589
     */
590
    public function reloadVoicemail(): void
591
    {
592
        PBX::voicemailReload();
593
    }
594
595
    /**
596
     *  Reloads WorkerApiCommands worker
597
     */
598
    public function reloadRestAPIWorker(): void
599
    {
600
        Processes::processPHPWorker(WorkerApiCommands::class);
601
    }
602
603
604
    /**
605
     *  Reloads WorkerCallEvents worker
606
     */
607
    public function reloadWorkerCallEvents(): void
608
    {
609
        Processes::processPHPWorker(WorkerCallEvents::class);
610
    }
611
612
613
    /**
614
     * Timeout handles
615
     */
616
    public function timeoutHandler(): void
617
    {
618
        $this->last_change = time() - $this->timeout;
619
        $this->startReload();
620
    }
621
622
623
    /**
624
     *  Process after PBXExtension state changes
625
     *
626
     * @param \MikoPBX\Common\Models\PbxExtensionModules $record
627
     */
628
    public function afterModuleStateChanged(PbxExtensionModules $record): void
629
    {
630
        $className       = str_replace('Module', '', $record->uniqid);
631
        $configClassName = "\\Modules\\{$record->uniqid}\\Lib\\{$className}Conf";
632
        if (class_exists($configClassName)) {
633
            $configClassName = new $configClassName();
634
            if ($record->disabled === '1' && method_exists($configClassName, 'onAfterModuleDisable')) {
635
                $configClassName->onAfterModuleDisable();
636
            } elseif ($record->disabled === '0' && method_exists($configClassName, 'onAfterModuleEnable')) {
637
                $configClassName->onAfterModuleEnable();
638
            }
639
        }
640
    }
641
642
    public static function invokeAction(string $action, $priority=0):void{
643
        $di = Di::getDefault();
644
        /** @var BeanstalkClient $queue */
645
        $queue = $di->getShared(BeanstalkConnectionModelsProvider::SERVICE_NAME);
646
        $queue->publish(
647
            $action,
648
            self::class,
649
            $priority,
650
            PheanstalkInterface::DEFAULT_DELAY,
651
            3600
652
        );
653
    }
654
}
655
656
/**
657
 * Start point
658
 */
659
$workerClassname = WorkerModelsEvents::class;
660
if (isset($argv) && count($argv) > 1 && $argv[1] === 'start') {
661
    cli_set_process_title($workerClassname);
662
    try {
663
        $worker = new $workerClassname();
664
        $worker->start($argv);
665
    } catch (Throwable $e) {
666
        global $errorLogger;
667
        $errorLogger->captureException($e);
668
        sleep(1);
669
    }
670
}