Passed
Push — develop ( c32ccc...c40cee )
by Nikolay
05:27
created

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