Passed
Push — develop ( c405ae...650212 )
by Nikolay
05:16
created

WorkerModelsEvents::cleanupAdvicesCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
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\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
    ModelsBase,
42
    NetworkFilters,
43
    OutgoingRoutingTable,
44
    OutWorkTimes,
45
    PbxExtensionModules,
46
    PbxSettings,
47
    Sip,
48
    SipHosts,
49
    SoundFiles,
50
    Users
51
};
52
use MikoPBX\Common\Providers\BeanstalkConnectionModelsProvider;
53
use MikoPBX\Common\Providers\ModulesDBConnectionsProvider;
54
use MikoPBX\Common\Providers\PBXConfModulesProvider;
55
use MikoPBX\Core\Asterisk\Configs\AsteriskConfigInterface;
56
use MikoPBX\Core\Asterisk\Configs\QueueConf;
57
use MikoPBX\Core\System\{BeanstalkClient,
58
    Configs\CronConf,
59
    Configs\Fail2BanConf,
60
    Configs\IptablesConf,
61
    Configs\NatsConf,
62
    Configs\NginxConf,
63
    Configs\NTPConf,
64
    Configs\PHPConf,
65
    Configs\SSHConf,
66
    Configs\SyslogConf,
67
    PBX,
68
    Processes,
69
    System,
70
    Util
71
};
72
use MikoPBX\Core\Providers\AsteriskConfModulesProvider;
73
use MikoPBX\Modules\Config\SystemConfigInterface;
74
use MikoPBX\PBXCoreREST\Lib\AdvicesProcessor;
75
use MikoPBX\PBXCoreREST\Workers\WorkerApiCommands;
76
use Phalcon\Di;
77
use Pheanstalk\Contract\PheanstalkInterface;
78
use Throwable;
79
80
ini_set('error_reporting', E_ALL);
81
ini_set('display_startup_errors', 1);
82
83
/**
84
 * WorkerModelsEvents.
85
 *
86
 * @package MikoPBX\Core\Workers
87
 */
88
class WorkerModelsEvents extends WorkerBase
89
{
90
    private const R_MANAGERS = 'reloadManager';
91
92
    private const R_QUEUES = 'reloadQueues';
93
94
    private const R_DIALPLAN = 'reloadDialplan';
95
96
    private const R_CUSTOM_F = 'updateCustomFiles';
97
98
    private const R_FIREWALL = 'reloadFirewall';
99
100
    private const R_NETWORK = 'networkReload';
101
102
    private const R_IAX = 'reloadIax';
103
104
    private const R_SIP = 'reloadSip';
105
106
    private const R_RTP = 'rtpReload';
107
108
    private const R_PBX_CORE = 'pbxCoreReload';
109
110
    private const R_FEATURES = 'reloadFeatures';
111
112
    private const R_CRON = 'reloadCron';
113
114
    public const  R_NGINX = 'reloadNginx';
115
116
    public const  R_NGINX_CONF = 'reloadNginxConf';
117
118
    public const  R_FAIL2BAN_CONF = 'reloadFail2BanConf';
119
120
    private const R_PHP_FPM = 'reloadPHPFPM';
121
122
    private const R_TIMEZONE = 'updateTomeZone';
123
124
    private const R_SYSLOG = 'restartSyslogD';
125
126
    private const R_SSH = 'reloadSSH';
127
128
    private const R_LICENSE = 'reloadLicense';
129
130
    private const R_NATS = 'reloadNats';
131
132
    private const R_VOICEMAIL = 'reloadVoicemail';
133
134
    private const R_REST_API_WORKER = 'reloadRestAPIWorker';
135
136
    private const R_CALL_EVENTS_WORKER = 'reloadWorkerCallEvents';
137
138
    private const R_PBX_MODULE_STATE = 'afterModuleStateChanged';
139
140
    private const R_MOH = 'reloadMoh';
141
142
    private const R_NTP = 'reloadNtp';
143
144
    private const R_UPDATE_REC_SAVE_PERIOD = 'updateRecordSavePeriod';
145
146
    private const R_ADVICES = 'cleanupAdvicesCache';
147
148
    private int $last_change;
149
    private array $modified_tables;
150
151
    private int $timeout = 2;
152
153
    // Array of core conf objects
154
    private array $arrAsteriskConfObjects;
155
    private array $PRIORITY_R;
156
    private array $pbxSettingsDependencyTable = [];
157
    private array $modelsDependencyTable = [];
158
159
    /**
160
     * Starts the models events worker.
161
     *
162
     * @param array $params The command-line arguments passed to the worker.
163
     * @return void
164
     */
165
    public function start(array $params): void
166
    {
167
        $this->last_change = time() - 2;
168
169
        $this->arrAsteriskConfObjects = $this->di->getShared(AsteriskConfModulesProvider::SERVICE_NAME);
170
171
        $this->initPbxSettingsDependencyTable();
172
        $this->initModelsDependencyTable();
173
174
        $this->PRIORITY_R = [
175
            self::R_PBX_MODULE_STATE,
176
            self::R_TIMEZONE,
177
            self::R_SYSLOG,
178
            self::R_REST_API_WORKER,
179
            self::R_NETWORK,
180
            self::R_FIREWALL,
181
            self::R_FAIL2BAN_CONF,
182
            self::R_SSH,
183
            self::R_LICENSE,
184
            self::R_NATS,
185
            self::R_NTP,
186
            self::R_PHP_FPM,
187
            self::R_NGINX,
188
            self::R_NGINX_CONF,
189
            self::R_CRON,
190
            self::R_PBX_CORE,
191
            self::R_FEATURES,
192
            self::R_SIP,
193
            self::R_RTP,
194
            self::R_IAX,
195
            self::R_DIALPLAN,
196
            self::R_QUEUES,
197
            self::R_MANAGERS,
198
            self::R_CUSTOM_F,
199
            self::R_VOICEMAIL,
200
            self::R_MOH,
201
            self::R_CALL_EVENTS_WORKER,
202
            self::R_UPDATE_REC_SAVE_PERIOD,
203
            self::R_ADVICES,
204
        ];
205
206
        $this->modified_tables = [];
207
208
        /** @var BeanstalkClient $client */
209
        $client = $this->di->getShared(BeanstalkConnectionModelsProvider::SERVICE_NAME);
210
        $client->subscribe(self::class, [$this, 'processModelChanges']);
211
        $client->subscribe($this->makePingTubeName(self::class), [$this, 'pingCallBack']);
212
        $client->setTimeoutHandler([$this, 'timeoutHandler']);
213
214
        while ($this->needRestart === false) {
215
            $client->wait();
216
        }
217
        // Execute all collected changes before exit
218
        $this->timeoutHandler();
219
    }
220
221
    /**
222
     * Initializes the PBX settings dependency table.
223
     */
224
    private function initPbxSettingsDependencyTable(): void
225
    {
226
        $tables = [];
227
        // FeaturesSettings
228
        $tables[] = [
229
            'settingName' => [
230
                'PBXLanguage',
231
                'PBXInternalExtensionLength',
232
                'PBXCallParkingExt',
233
                'PBXCallParkingStartSlot',
234
                'PBXCallParkingEndSlot',
235
                'PBXFeatureAttendedTransfer',
236
                'PBXFeatureBlindTransfer',
237
                'PBXFeatureDigitTimeout',
238
                'PBXFeatureAtxferNoAnswerTimeout',
239
                'PBXFeatureTransferDigitTimeout',
240
                'PBXFeaturePickupExten',
241
            ],
242
            'functions' => [
243
                self::R_FEATURES,
244
                self::R_DIALPLAN,
245
            ],
246
        ];
247
248
        // CallRecordSettings
249
        $tables[] = [
250
            'settingName' => [
251
                'PBXRecordCalls',
252
                'PBXRecordCallsInner',
253
                'PBXSplitAudioThread',
254
            ],
255
            'functions' => [
256
                self::R_DIALPLAN,
257
            ],
258
        ];
259
260
        // CallRecordSettings / The period of storing conversation records
261
        $tables[] = [
262
            'settingName' => [
263
                'PBXRecordSavePeriod',
264
            ],
265
            'functions' => [
266
                self::R_UPDATE_REC_SAVE_PERIOD,
267
            ],
268
        ];
269
270
        // AMIParameters
271
        $tables[] = [
272
            'settingName' => [
273
                'AMIPort',
274
                'AJAMPort',
275
                'AJAMPortTLS',
276
            ],
277
            'functions' => [
278
                self::R_MANAGERS,
279
            ],
280
        ];
281
282
        // IaxParameters
283
        $tables[] = [
284
            'settingName' => [
285
                'IAXPort',
286
            ],
287
            'functions' => [
288
                self::R_IAX,
289
            ],
290
        ];
291
292
        // Guest calls without authorization
293
        $tables[] = [
294
            'settingName' => [
295
                'PBXAllowGuestCalls',
296
                'UseWebRTC',
297
            ],
298
            'functions' => [
299
                self::R_SIP,
300
                self::R_DIALPLAN,
301
            ],
302
        ];
303
304
        // SipParameters
305
        $tables[] = [
306
            'settingName' => [
307
                'SIPPort',
308
                'TLS_PORT',
309
                'SIPDefaultExpiry',
310
                'SIPMinExpiry',
311
                'SIPMaxExpiry',
312
                'PBXLanguage',
313
            ],
314
            'functions' => [
315
                self::R_SIP,
316
            ],
317
        ];
318
319
        // RTPParameters
320
        $tables[] = [
321
            'settingName' => [
322
                'RTPPortFrom',
323
                'RTPPortTo',
324
                'RTPStunServer',
325
            ],
326
            'functions' => [
327
                self::R_RTP,
328
            ],
329
        ];
330
331
        // SSHParameters
332
        $tables[] = [
333
            'settingName' => [
334
                'SSHPort',
335
                'SSHRsaKey',
336
                'SSHDssKey',
337
                'SSHPassword',
338
                'SSHecdsaKey',
339
                'SSHAuthorizedKeys',
340
                'SSHDisablePasswordLogins',
341
            ],
342
            'functions' => [
343
                self::R_SSH,
344
            ],
345
        ];
346
347
        // FirewallParameters
348
        $tables[] = [
349
            'settingName' => [
350
                'SIPPort',
351
                'TLS_PORT',
352
                'RTPPortFrom',
353
                'RTPPortTo',
354
                'IAXPort',
355
                'AMIPort',
356
                'AJAMPort',
357
                'AJAMPortTLS',
358
                'WEBPort',
359
                'WEBHTTPSPort',
360
                'SSHPort',
361
                'PBXFirewallEnabled',
362
                'PBXFail2BanEnabled',
363
            ],
364
            'functions' => [
365
                self::R_FIREWALL,
366
            ],
367
            'strPosKey' => 'FirewallSettings',
368
        ];
369
370
        // FirewallParameters
371
        $tables[] = [
372
            'settingName' => [
373
                'WEBPort',
374
                'WEBHTTPSPort',
375
                'WEBHTTPSPublicKey',
376
                'WEBHTTPSPrivateKey',
377
                'RedirectToHttps',
378
            ],
379
            'functions' => [
380
                self::R_NGINX,
381
            ],
382
        ];
383
384
        // CronParameters
385
        $tables[] = [
386
            'settingName' => [
387
                'RestartEveryNight',
388
            ],
389
            'functions' => [
390
                self::R_CRON,
391
            ],
392
        ];
393
394
        // DialplanParameters
395
        $tables[] = [
396
            'settingName' => [
397
                'PBXLanguage',
398
                'PBXRecordAnnouncementIn',
399
                'PBXRecordAnnouncementOut',
400
            ],
401
            'functions' => [
402
                self::R_DIALPLAN,
403
            ],
404
        ];
405
        // DialplanParameters
406
        $tables[] = [
407
            'settingName' => [
408
                'PBXLanguage',
409
            ],
410
            'functions' => [
411
                self::R_PBX_CORE,
412
            ],
413
        ];
414
415
        // VoiceMailParameters
416
        $tables[] = [
417
            'settingName' => [
418
                'MailTplVoicemailSubject',
419
                'MailTplVoicemailBody',
420
                'MailTplVoicemailFooter',
421
                'MailSMTPSenderAddress',
422
                'MailSMTPUsername',
423
                'PBXTimezone',
424
                'VoicemailNotificationsEmail',
425
                'SystemNotificationsEmail',
426
                'SystemEmailForMissed',
427
            ],
428
            'functions' => [
429
                self::R_VOICEMAIL,
430
            ],
431
        ];
432
433
        // VisualLanguageSettings
434
        $tables[] = [
435
            'settingName' => [
436
                'SSHLanguage',
437
                'WebAdminLanguage',
438
            ],
439
            'functions' => [
440
                self::R_REST_API_WORKER,
441
            ],
442
        ];
443
444
        // LicenseSettings
445
        $tables[] = [
446
            'settingName' => [
447
                'PBXLicense',
448
            ],
449
            'functions' => [
450
                self::R_LICENSE,
451
                self::R_NATS,
452
            ],
453
        ];
454
455
        // TimeZoneSettings
456
        $tables[] = [
457
            'settingName' => [
458
                'PBXTimezone',
459
            ],
460
            'functions' => [
461
                self::R_TIMEZONE,
462
                self::R_NGINX,
463
                self::R_PHP_FPM,
464
                self::R_REST_API_WORKER,
465
                self::R_CALL_EVENTS_WORKER,
466
                self::R_SYSLOG,
467
            ],
468
        ];
469
470
        // NTPSettings
471
        $tables[] = [
472
            'settingName' => [
473
                'PBXManualTimeSettings',
474
                'NTPServer',
475
                'PBXTimezone',
476
            ],
477
            'functions' => [
478
                self::R_NTP,
479
            ],
480
        ];
481
482
        // Advices
483
        $tables[] = [
484
            'settingName' => [
485
                'WebAdminPassword',
486
                'SSHPassword',
487
                'PBXFirewallEnabled',
488
            ],
489
            'functions' => [
490
                self::R_ADVICES,
491
            ],
492
        ];
493
494
        $this->pbxSettingsDependencyTable = $tables;
495
    }
496
497
    /**
498
     * Initializes the models dependency table.
499
     */
500
    private function initModelsDependencyTable(): void
501
    {
502
        $tables = [];
503
        $tables[] = [
504
            'settingName' => [
505
                AsteriskManagerUsers::class,
506
            ],
507
            'functions' => [
508
                self::R_MANAGERS,
509
                self::R_ADVICES,
510
            ],
511
        ];
512
513
        $tables[] = [
514
            'settingName' => [
515
                CallQueueMembers::class,
516
            ],
517
            'functions' => [
518
                self::R_QUEUES,
519
            ],
520
        ];
521
522
        $tables[] = [
523
            'settingName' => [
524
                CallQueues::class,
525
            ],
526
            'functions' => [
527
                self::R_QUEUES,
528
                self::R_DIALPLAN,
529
            ],
530
        ];
531
        $tables[] = [
532
            'settingName' => [
533
                ExternalPhones::class,
534
                Extensions::class,
535
                DialplanApplications::class,
536
                IncomingRoutingTable::class,
537
                IvrMenu::class,
538
                IvrMenuActions::class,
539
                OutgoingRoutingTable::class,
540
                OutWorkTimes::class,
541
                ConferenceRooms::class,
542
            ],
543
            'functions' => [
544
                self::R_DIALPLAN,
545
            ],
546
        ];
547
548
        $tables[] = [
549
            'settingName' => [
550
                CustomFiles::class,
551
            ],
552
            'functions' => [
553
                self::R_CUSTOM_F,
554
                self::R_ADVICES,
555
            ],
556
        ];
557
558
        $tables[] = [
559
            'settingName' => [
560
                Sip::class,
561
            ],
562
            'functions' => [
563
                self::R_SIP,
564
                self::R_DIALPLAN,
565
                self::R_FIREWALL,
566
                self::R_ADVICES,
567
            ],
568
        ];
569
570
        $tables[] = [
571
            'settingName' => [
572
                Users::class,
573
                ExtensionForwardingRights::class,
574
            ],
575
            'functions' => [
576
                self::R_SIP,
577
                self::R_DIALPLAN,
578
            ],
579
        ];
580
581
        $tables[] = [
582
            'settingName' => [
583
                FirewallRules::class,
584
                Fail2BanRules::class,
585
            ],
586
            'functions' => [
587
                self::R_FIREWALL,
588
            ],
589
        ];
590
591
        $tables[] = [
592
            'settingName' => [
593
                Iax::class,
594
            ],
595
            'functions' => [
596
                self::R_IAX,
597
                self::R_DIALPLAN,
598
            ],
599
        ];
600
601
        $tables[] = [
602
            'settingName' => [
603
                Codecs::class,
604
            ],
605
            'functions' => [
606
                self::R_IAX,
607
                self::R_SIP,
608
            ],
609
        ];
610
611
        $tables[] = [
612
            'settingName' => [
613
                SoundFiles::class,
614
            ],
615
            'functions' => [
616
                self::R_MOH,
617
                self::R_DIALPLAN,
618
            ],
619
        ];
620
621
        $tables[] = [
622
            'settingName' => [
623
                LanInterfaces::class,
624
            ],
625
            'functions' => [
626
                self::R_NETWORK,
627
                self::R_IAX,
628
                self::R_SIP,
629
                self::R_ADVICES,
630
            ],
631
        ];
632
633
        $tables[] = [
634
            'settingName' => [
635
                SipHosts::class,
636
            ],
637
            'functions' => [
638
                self::R_FIREWALL,
639
                self::R_SIP,
640
            ],
641
        ];
642
643
        $tables[] = [
644
            'settingName' => [
645
                NetworkFilters::class,
646
            ],
647
            'functions' => [
648
                self::R_FIREWALL,
649
                self::R_SIP,
650
                self::R_MANAGERS,
651
                self::R_ADVICES,
652
            ],
653
        ];
654
655
        $this->modelsDependencyTable = $tables;
656
    }
657
658
    /**
659
     * Timeout handles
660
     */
661
    public function timeoutHandler(): void
662
    {
663
        $this->last_change = time() - $this->timeout;
664
        $this->startReload();
665
    }
666
667
668
    /**
669
     * Starts the reload process if there are modified tables.
670
     *
671
     * @return void
672
     */
673
    private function startReload(): void
674
    {
675
        // Check if there are any modified tables
676
        if (count($this->modified_tables) === 0) {
677
            return;
678
        }
679
680
        // Check if enough time has passed since the last change
681
        $delta = time() - $this->last_change;
682
        if ($delta < $this->timeout) {
683
            return;
684
        }
685
686
        // Process changes for each method in priority order
687
        foreach ($this->PRIORITY_R as $method_name) {
688
            $action = $this->modified_tables[$method_name] ?? null;
689
            $parameters = $this->modified_tables['parameters'][$method_name] ?? null;
690
691
            // Skip if there is no change for this method
692
            if ($action === null) {
693
                continue;
694
            }
695
696
            // Call the method if it exists
697
            if (method_exists($this, $method_name)) {
698
                Util::sysLogMsg(__METHOD__, "Process changes by {$method_name}", LOG_DEBUG);
699
                if ($parameters === null) {
700
                    $this->$method_name();
701
                } else {
702
                    $this->$method_name($parameters);
703
                }
704
            }
705
        }
706
707
        // Send information about models changes to additional modules bulky without any details
708
        PBXConfModulesProvider::hookModulesMethod(SystemConfigInterface::MODELS_EVENT_NEED_RELOAD, [$this->modified_tables]);
709
710
        // Reset the modified tables array
711
        $this->modified_tables = [];
712
    }
713
714
    /**
715
     * Processes model changes received from the Beanstalk queue.
716
     *
717
     * @param BeanstalkClient $message The message received from the Beanstalk queue.
718
     * @return void
719
     */
720
    public function processModelChanges(BeanstalkClient $message): void
721
    {
722
        // Decode the received message
723
        $receivedMessage = json_decode($message->getBody(), true, 512, JSON_THROW_ON_ERROR);
724
725
        // Check the source of the message and perform actions accordingly
726
        if ($receivedMessage['source'] === BeanstalkConnectionModelsProvider::SOURCE_INVOKE_ACTION
727
            && in_array($receivedMessage['action'], $this->PRIORITY_R, true)) {
728
            // Store the modified table and its parameters
729
            $this->modified_tables[$receivedMessage['action']] = true;
730
            $this->modified_tables['parameters'][$receivedMessage['action']] = $receivedMessage['parameters'];
731
        } elseif ($receivedMessage['source'] === BeanstalkConnectionModelsProvider::SOURCE_MODELS_CHANGED) {
732
733
            // Fill the modified tables array with the changes from the received message
734
            $this->fillModifiedTables($receivedMessage);
735
        }
736
737
        // Start the reload process if there are modified tables
738
        $this->startReload();
739
740
        if (!$receivedMessage) {
741
            return;
742
        }
743
744
        // Send information about model changes to additional modules with changed data details
745
        PBXConfModulesProvider::hookModulesMethod(SystemConfigInterface::MODELS_EVENT_CHANGE_DATA, [$receivedMessage]);
746
    }
747
748
    /**
749
     * Fills the modified tables array with changes based on the received data.
750
     *
751
     * @param array $data The data containing the changes.
752
     * @return void
753
     */
754
    private function fillModifiedTables(array $data): void
755
    {
756
        $count_changes = count($this->modified_tables);
757
        $called_class = $data['model'] ?? '';
758
        Util::sysLogMsg(__METHOD__, "New changes " . $called_class, LOG_DEBUG);
759
760
        // Clear cache for the called class
761
        ModelsBase::clearCache($called_class);
762
763
        // Get new settings for dependent modules
764
        $this->getNewSettingsForDependentModules($called_class);
765
766
        // Fill modified tables from models
767
        $this->fillModifiedTablesFromModels($called_class);
768
769
        // Fill modified tables from PBX settings data
770
        $this->fillModifiedTablesFromPbxSettingsData($called_class, $data['recordId']);
771
772
        // Fill modified tables from PBX extension modules
773
        $this->fillModifiedTablesFromPbxExtensionModules($called_class, $data['recordId']);
774
775
        // Start counting time when the first task is received
776
        if ($count_changes === 0 && count($this->modified_tables) > 0) {
777
            $this->last_change = time();
778
        }
779
    }
780
781
    /**
782
     * Retrieves new settings for dependent modules based on the called class.
783
     *
784
     * @param string $called_class The called class for which to retrieve settings.
785
     * @return void
786
     */
787
    private function getNewSettingsForDependentModules(string $called_class): void
788
    {
789
        foreach ($this->arrAsteriskConfObjects as $configClassObj) {
790
            try {
791
                $dependencies = call_user_func([$configClassObj, AsteriskConfigInterface::GET_DEPENDENCE_MODELS]);
792
793
                // Check if the called class is a dependency and the config class has the GET_SETTINGS method
794
                if (in_array($called_class, $dependencies, true)
795
                    && method_exists($configClassObj, AsteriskConfigInterface::GET_SETTINGS)
796
                ) {
797
                    // Retrieve the new settings for the config class
798
                    call_user_func([$configClassObj, AsteriskConfigInterface::GET_SETTINGS]);
799
                }
800
            } catch (Throwable $e) {
801
                global $errorLogger;
802
                $errorLogger->captureException($e);
803
                Util::sysLogMsg(__METHOD__, $e->getMessage(), LOG_ERR);
804
                continue;
805
            }
806
        }
807
    }
808
809
    /**
810
     * Fills the modified tables array based on the models dependency table and the called class.
811
     *
812
     * @param string $called_class The called class.
813
     * @return void
814
     */
815
    private function fillModifiedTablesFromModels(string $called_class): void
816
    {
817
        foreach ($this->modelsDependencyTable as $dependencyData) {
818
            if (!in_array($called_class, $dependencyData['settingName'], true)) {
819
                continue;
820
            }
821
            foreach ($dependencyData['functions'] as $function) {
822
                $this->modified_tables[$function] = true;
823
            }
824
        }
825
    }
826
827
    /**
828
     * Fills the modified tables array based on the PBX settings data, the called class, and the record ID.
829
     *
830
     * @param string $called_class The called class.
831
     * @param string $recordId The record ID.
832
     * @return void
833
     */
834
    private function fillModifiedTablesFromPbxSettingsData(string $called_class, string $recordId): void
835
    {
836
        // Check if the called class is not PbxSettings
837
        if (PbxSettings::class !== $called_class) {
838
            return;
839
        }
840
841
        // Clear cache for PbxSettings
842
        PbxSettings::clearCache(PbxSettings::class);
843
844
        // Find the PbxSettings record
845
        /** @var PbxSettings $pbxSettings */
846
        $pbxSettings = PbxSettings::findFirstByKey($recordId);
847
        if ($pbxSettings === null) {
848
            return;
849
        }
850
        $settingName = $pbxSettings->key;
851
852
        // Iterate through the PBX settings dependency table and update the modified tables array
853
        foreach ($this->pbxSettingsDependencyTable as $data) {
854
            $additionalConditions = (isset($data['strPosKey']) && strpos($settingName, $data['strPosKey']) !== false);
855
856
            // Check additional conditions and the setting name
857
            if (!$additionalConditions && !in_array($settingName, $data['settingName'], true)) {
858
                continue;
859
            }
860
861
            // Update the modified tables array for each function
862
            foreach ($data['functions'] as $function) {
863
                $this->modified_tables[$function] = true;
864
            }
865
        }
866
    }
867
868
    /**
869
     * Fills the modified tables array based on the PBX extension modules data, the called class, and the record ID.
870
     *
871
     * @param string $called_class The called class.
872
     * @param string $recordId The record ID.
873
     * @return void
874
     */
875
    private function fillModifiedTablesFromPbxExtensionModules(string $called_class, string $recordId): void
876
    {
877
        // Check if the called class is not PbxExtensionModules
878
        if (PbxExtensionModules::class !== $called_class) {
879
            return;
880
        }
881
882
        // Find the module settings record
883
        $moduleSettings = PbxExtensionModules::findFirstById($recordId);
884
        if ($moduleSettings !== null) {
885
886
            // Invoke the action for the PBX module state with the module settings data
887
            self::invokeAction(self::R_PBX_MODULE_STATE, $moduleSettings->toArray(), 50);
888
        }
889
    }
890
891
    /**
892
     * Invokes an action by publishing a job to the Beanstalk queue.
893
     *
894
     * @param string $action The action to invoke.
895
     * @param array $parameters The parameters for the action.
896
     * @param int $priority The priority of the job.
897
     * @return void
898
     */
899
    public static function invokeAction(string $action, array $parameters = [], int $priority = 0): void
900
    {
901
        $di = Di::getDefault();
902
        if (!$di) {
903
            return;
904
        }
905
        /** @var BeanstalkClient $queue */
906
        $queue = $di->getShared(BeanstalkConnectionModelsProvider::SERVICE_NAME);
907
908
        // Prepare the job data
909
        $jobData = json_encode(
910
            [
911
                'source' => BeanstalkConnectionModelsProvider::SOURCE_INVOKE_ACTION,
912
                'action' => $action,
913
                'parameters' => $parameters,
914
                'model' => ''
915
            ]
916
        );
917
918
        // Publish the job to the Beanstalk queue
919
        $queue->publish(
920
            $jobData,
921
            self::class,
922
            $priority,
923
            PheanstalkInterface::DEFAULT_DELAY,
924
            3600
925
        );
926
    }
927
928
    /**
929
     * Restarts gnats queue server daemon
930
     */
931
    public function reloadNats(): void
932
    {
933
        $natsConf = new NatsConf();
934
        $natsConf->reStart();
935
    }
936
937
    /**
938
     * Reloads Asterisk dialplan
939
     */
940
    public function reloadDialplan(): void
941
    {
942
        PBX::dialplanReload();
943
    }
944
945
    /**
946
     * Reloads Asterisk manager interface module
947
     */
948
    public function reloadManager(): void
949
    {
950
        PBX::managerReload();
951
    }
952
953
    /**
954
     * Generates queue.conf and restart asterisk queue module
955
     */
956
    public function reloadQueues(): void
957
    {
958
        QueueConf::queueReload();
959
    }
960
961
    /**
962
     * Updates custom changes in config files
963
     */
964
    public function updateCustomFiles(): void
965
    {
966
        System::updateCustomFiles();
967
    }
968
969
    /**
970
     * Applies iptables settings and restart firewall
971
     */
972
    public function reloadFirewall(): void
973
    {
974
        IptablesConf::updateFirewallRules();
975
        IptablesConf::reloadFirewall();
976
    }
977
978
    public function pbxCoreReload(): void
979
    {
980
        PBX::coreRestart();
981
    }
982
983
    /**
984
     *  Refreshes networks configs and restarts network daemon
985
     */
986
    public function networkReload(): void
987
    {
988
        System::networkReload();
989
    }
990
991
    /**
992
     * Refreshes IAX configs and reload iax2 module
993
     */
994
    public function reloadIax(): void
995
    {
996
        PBX::iaxReload();
997
    }
998
999
    /**
1000
     * Reloads MOH file list in Asterisk.
1001
     */
1002
    public function reloadMoh(): void
1003
    {
1004
        PBX::mohReload();
1005
    }
1006
1007
    /**
1008
     * Refreshes SIP configs and reload PJSIP module
1009
     */
1010
    public function reloadSip(): void
1011
    {
1012
        PBX::sipReload();
1013
    }
1014
1015
    /**
1016
     * Update RTP config file.
1017
     */
1018
    public function rtpReload(): void
1019
    {
1020
        PBX::rtpReload();
1021
    }
1022
1023
    /**
1024
     *  Refreshes features configs and reload features module
1025
     */
1026
    public function reloadFeatures(): void
1027
    {
1028
        PBX::featuresReload();
1029
    }
1030
1031
    /**
1032
     * Restarts CROND daemon
1033
     */
1034
    public function reloadCron(): void
1035
    {
1036
        $cron = new CronConf();
1037
        $cron->reStart();
1038
    }
1039
1040
    /**
1041
     * Restarts NTP daemon
1042
     */
1043
    public function reloadNtp(): void
1044
    {
1045
        NTPConf::configure();
1046
    }
1047
1048
    /**
1049
     * Update record save period
1050
     */
1051
    public function updateRecordSavePeriod(): void
1052
    {
1053
        PBX::updateSavePeriod();
1054
    }
1055
1056
    /**
1057
     * Restarts Nginx daemon
1058
     */
1059
    public function reloadNginx(): void
1060
    {
1061
        $nginxConf = new NginxConf();
1062
        $nginxConf->generateConf();
1063
        $nginxConf->reStart();
1064
    }
1065
1066
    /**
1067
     * Applies modules locations changes and restarts Nginx daemon
1068
     */
1069
    public function reloadNginxConf(): void
1070
    {
1071
        $nginxConf = new NginxConf();
1072
        $nginxConf->generateModulesConfigs();
1073
        $nginxConf->reStart();
1074
    }
1075
1076
    /**
1077
     * Restarts Fail2Ban daemon
1078
     */
1079
    public function reloadFail2BanConf(): void
1080
    {
1081
        Fail2BanConf::reloadFail2ban();
1082
    }
1083
1084
    /**
1085
     * Restarts PHP-FPM daemon
1086
     */
1087
    public function reloadPHPFPM(): void
1088
    {
1089
        PHPConf::reStart();
1090
    }
1091
1092
    /**
1093
     * Configures SSH settings
1094
     */
1095
    public function reloadSSH(): void
1096
    {
1097
        $sshConf = new SSHConf();
1098
        $sshConf->configure();
1099
    }
1100
1101
    /**
1102
     * Reconfigures TomeZone settings
1103
     */
1104
    public function updateTomeZone(): void
1105
    {
1106
        System::timezoneConfigure();
1107
    }
1108
1109
    /**
1110
     * Restarts rsyslog daemon
1111
     */
1112
    public function restartSyslogD(): void
1113
    {
1114
        $syslogConf = new SyslogConf();
1115
        $syslogConf->reStart();
1116
    }
1117
1118
    /**
1119
     *  Reloads Asterisk voicemail module
1120
     */
1121
    public function reloadVoicemail(): void
1122
    {
1123
        PBX::voicemailReload();
1124
    }
1125
1126
    /**
1127
     *  Reloads WorkerApiCommands worker
1128
     */
1129
    public function reloadRestAPIWorker(): void
1130
    {
1131
        Processes::processPHPWorker(WorkerApiCommands::class);
1132
    }
1133
1134
    /**
1135
     *  Reloads WorkerCallEvents worker
1136
     */
1137
    public function reloadWorkerCallEvents(): void
1138
    {
1139
        Processes::processPHPWorker(WorkerCallEvents::class);
1140
    }
1141
1142
    /**
1143
     * Cleanup advices cache
1144
     * @return void
1145
     */
1146
    private function cleanupAdvicesCache(): void
1147
    {
1148
        AdvicesProcessor::cleanupCache();
1149
    }
1150
1151
1152
    /**
1153
     * Process after PBXExtension state changes
1154
     *
1155
     * @param array $pbxModuleRecord
1156
     */
1157
    public function afterModuleStateChanged(array $pbxModuleRecord): void
1158
    {
1159
        // Recreate modules array
1160
        PBXConfModulesProvider::recreateModulesProvider();
1161
1162
        // Recreate database connections
1163
        ModulesDBConnectionsProvider::recreateModulesDBConnections();
1164
1165
        // Hook module methods if they change system configs
1166
        $className = str_replace('Module', '', $pbxModuleRecord['uniqid']);
1167
        $configClassName = "Modules\\{$pbxModuleRecord['uniqid']}\\Lib\\{$className}Conf";
1168
        if (class_exists($configClassName)) {
1169
            $configClassObj = new $configClassName();
1170
1171
            // Reconfigure fail2ban and restart iptables
1172
            if (method_exists($configClassObj, SystemConfigInterface::GENERATE_FAIL2BAN_JAILS)
1173
                && !empty(call_user_func([$configClassObj, SystemConfigInterface::GENERATE_FAIL2BAN_JAILS]))) {
1174
                $this->modified_tables[self::R_FAIL2BAN_CONF] = true;
1175
            }
1176
1177
            // Refresh Nginx conf if module has any locations
1178
            if (method_exists($configClassObj, SystemConfigInterface::CREATE_NGINX_LOCATIONS)
1179
                && !empty(call_user_func([$configClassObj, SystemConfigInterface::CREATE_NGINX_LOCATIONS]))) {
1180
                $this->modified_tables[self::R_NGINX_CONF] = true;
1181
            }
1182
1183
            // Refresh crontab rules if module has any for it
1184
            if (method_exists($configClassObj, SystemConfigInterface::CREATE_CRON_TASKS)) {
1185
                $tasks = [];
1186
                call_user_func_array([$configClassObj, SystemConfigInterface::CREATE_CRON_TASKS], [&$tasks]);
1187
                if (!empty($tasks)) {
1188
                    $this->modified_tables[self::R_CRON] = true;
1189
                }
1190
            }
1191
1192
            // Reconfigure asterisk manager interface
1193
            if (method_exists($configClassObj, AsteriskConfigInterface::GENERATE_MANAGER_CONF)
1194
                && !empty(call_user_func([$configClassObj, AsteriskConfigInterface::GENERATE_MANAGER_CONF]))) {
1195
                $this->modified_tables[self::R_MANAGERS] = true;
1196
            }
1197
1198
            // Hook modules AFTER_ methods
1199
            if ($pbxModuleRecord['disabled'] === '1'
1200
                && method_exists($configClassObj, SystemConfigInterface::ON_AFTER_MODULE_DISABLE)) {
1201
                call_user_func([$configClassObj, SystemConfigInterface::ON_AFTER_MODULE_DISABLE]);
1202
            } elseif ($pbxModuleRecord['disabled'] === '0'
1203
                && method_exists($configClassObj, SystemConfigInterface::ON_AFTER_MODULE_ENABLE)) {
1204
                call_user_func([$configClassObj, SystemConfigInterface::ON_AFTER_MODULE_ENABLE]);
1205
            }
1206
        }
1207
    }
1208
}
1209
1210
/**
1211
 * The start point
1212
 */
1213
WorkerModelsEvents::startWorker($argv ?? []);