Passed
Pull Request — master (#23)
by Nikolay
09:42 queued 03:08
created

WorkerModelsEvents::clearCachePbxSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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