Passed
Push — develop ( 15bc6b...5ea31b )
by Nikolay
05:50 queued 12s
created

WorkerApiCommands::systemCallBack()   F

Complexity

Conditions 35
Paths 35

Size

Total Lines 154
Code Lines 138

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 138
dl 0
loc 154
rs 3.3333
c 1
b 0
f 0
cc 35
nc 35
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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, 2 2020
7
 */
8
9
namespace MikoPBX\PBXCoreREST\Workers;
10
11
use MikoPBX\Core\Asterisk\CdrDb;
12
use MikoPBX\Core\Asterisk\Configs\{IAXConf, SIPConf, VoiceMailConf};
13
use MikoPBX\Core\System\{BeanstalkClient,
14
    TimeManagement,
15
    Firewall,
16
    Notifications,
17
    Storage,
18
    System,
19
    UploadAndConvertFiles,
20
    Util};
21
use MikoPBX\Core\Workers\Cron\WorkerSafeScriptsCore;
22
use MikoPBX\Core\Workers\WorkerBase;
23
use MikoPBX\Core\Workers\WorkerMergeUploadedFile;
24
use MikoPBX\Modules\Setup\PbxExtensionSetupFailure;
25
use MikoPBX\Modules\PbxExtensionState;
26
use Phalcon\Exception;
27
28
use function MikoPBX\Common\Config\appPath;
29
30
require_once 'Globals.php';
31
32
class WorkerApiCommands extends WorkerBase
33
{
34
    /**
35
     * Modules can expose additional REST methods and processors,
36
     * look at src/Modules/Config/RestAPIConfigInterface.php
37
     */
38
    private array $additionalProcessors;
39
40
    /**
41
     * @param $argv
42
     */
43
    public function start($argv): void
44
    {
45
        $client = new BeanstalkClient();
46
        $client->subscribe($this->makePingTubeName(self::class), [$this, 'pingCallBack']);
47
        $client->subscribe(__CLASS__, [$this, 'prepareAnswer']);
48
49
        // Every module config class can process requests under root rights,
50
        // if it described in Config class
51
        $additionalModules = $this->di->getShared('pbxConfModules');
52
        $this->additionalProcessors=[];
53
        foreach ($additionalModules as $moduleConfigObject) {
54
            if ($moduleConfigObject->moduleUniqueId!=='InternalConfigModule'
55
                && method_exists($moduleConfigObject, 'moduleRestAPICallback')
56
            ) {
57
                $this->additionalProcessors[] = [
58
                    $moduleConfigObject->moduleUniqueId,
59
                    $moduleConfigObject,
60
                    'moduleRestAPICallback'
61
                ];
62
            }
63
        }
64
65
        while (true) {
66
            try {
67
                $client->wait();
68
            } catch (Exception $e) {
69
                global $errorLogger;
70
                $errorLogger->captureException($e);
71
                sleep(1);
72
            }
73
        }
74
    }
75
76
77
    /**
78
     * Process request
79
     *
80
     * @param BeanstalkClient $message
81
     */
82
    public function prepareAnswer($message): void
83
    {
84
        try {
85
            $request   = json_decode($message->getBody(), true, 512, JSON_THROW_ON_ERROR);
86
            $processor = $request['processor'];
87
88
            switch ($processor) {
89
                case 'cdr':
90
                    $answer = $this->cdrCallBack($request);
91
                    break;
92
                case 'sip':
93
                    $answer = $this->sipCallBack($request);
94
                    break;
95
                case 'iax':
96
                    $answer = $this->iaxCallBack($request);
97
                    break;
98
                case 'system':
99
                    $answer = $this->systemCallBack($request);
100
                    break;
101
                case 'storage':
102
                    $answer = $this->storageCallBack($request);
103
                    break;
104
                case 'upload':
105
                    $answer = $this->uploadCallBack($request);
106
                    break;
107
                case 'modules':
108
                    $answer = $this->modulesCallBack($request);
109
                    break;
110
                default:
111
                    $answer = "Unknown processor - {$processor}";
112
            }
113
        } catch (\Exception $exception) {
114
            $answer = 'Exception on WorkerApiCommands - ' . $exception->getMessage();
115
        }
116
117
         $message->reply(json_encode($answer));
118
    }
119
120
    /**
121
     * Запросы с CDR таблице
122
     *
123
     * @param array $request
124
     */
125
    private function cdrCallBack($request): array
126
    {
127
        $action = $request['action'];
128
        switch ($action) {
129
            case 'getActiveCalls':
130
                $result['data'] = CdrDb::getActiveCalls();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.
Loading history...
131
                break;
132
            case 'getActiveChannels':
133
                $result['data'] = CdrDb::getActiveChannels();
134
                break;
135
            default:
136
                $result = ["Unknown action - {$action}"];
137
                break;
138
        }
139
140
        return $result;
141
    }
142
143
    /**
144
     * Обработка команд SIP.
145
     *
146
     * @param array $request
147
     */
148
    private function sipCallBack($request): array
149
    {
150
        $action = $request['action'];
151
        $data   = $request['data'];
152
153
        $result = [
154
            'result' => 'ERROR',
155
        ];
156
        if ('getPeersStatuses' === $action) {
157
            $result = SIPConf::getPeersStatuses();
158
        } elseif ('getSipPeer' === $action) {
159
            $result = SIPConf::getPeerStatus($data['peer']);
160
        } elseif ('getRegistry' === $action) {
161
            $result = SIPConf::getRegistry();
162
        } else {
163
            $result['data'] = 'API action not found in sipCallBack;';
164
        }
165
        $result['function'] = $action;
166
167
        return $result;
168
    }
169
170
    /**
171
     * Обработка команду IAX.
172
     *
173
     * @param array $request
174
     */
175
    private function iaxCallBack($request): array
176
    {
177
        $action = $request['action'];
178
        $result = [
179
            'result' => 'ERROR',
180
        ];
181
        if ('getRegistry' === $action) {
182
            $result = IAXConf::getRegistry();
183
        } else {
184
            $result['data'] = 'API action not found in iaxCallBack;';
185
        }
186
        $result['function'] = $action;
187
188
        return $result;
189
    }
190
191
    /**
192
     * Обработка системных команд.
193
     *
194
     * @param array $request
195
     */
196
    private function systemCallBack($request)
197
    {
198
        $action = $request['action'];
199
        $data   = $request['data'];
200
201
        $result = [
202
            'result' => 'ERROR',
203
        ];
204
205
        switch ($action){
206
            case 'reboot':
207
                $result['result'] = 'Success';
208
                System::rebootSync();
209
                break;
210
            case 'shutdown':
211
                $result['result'] = 'Success';
212
                System::shutdown();
213
                break;
214
            case 'mergeUploadedFile':
215
                $result['result'] = 'Success';
216
                $phpPath              = Util::which('php');
217
                $workerDownloaderPath = Util::getFilePathByClassName(WorkerMergeUploadedFile::class);
218
                Util::mwExecBg("{$phpPath} -f {$workerDownloaderPath} '{$data['settings_file']}'");
219
                break;
220
            case 'setDate':
221
                $result = TimeManagement::setDate($data['date']);
222
                break;
223
            case 'getInfo':
224
                $result = System::getInfo();
225
                break;
226
            case 'sendMail':
227
                if (isset($data['email']) && isset($data['subject']) && isset($data['body'])) {
228
                    if (isset($data['encode']) && $data['encode'] === 'base64') {
229
                        $data['subject'] = base64_decode($data['subject']);
230
                        $data['body']    = base64_decode($data['body']);
231
                    }
232
                    $result = Notifications::sendMail($data['email'], $data['subject'], $data['body']);
233
                } else {
234
                    $result['message'] = 'Not all query parameters are populated.';
235
                }
236
                break;
237
            case 'fileReadContent':
238
                $result = Util::fileReadContent($data['filename'], $data['needOriginal']);
239
                break;
240
            case 'getExternalIpInfo':
241
                $result = System::getExternalIpInfo();
242
                break;
243
            case 'reloadMsmtp':
244
                $notifications = new Notifications();
245
                $result        = $notifications->configure();
246
                $OtherConfigs  = new VoiceMailConf();
247
                $OtherConfigs->generateConfig();
248
                $asteriskPath = Util::which('asterisk');
249
                Util::mwExec("{$asteriskPath} -rx 'voicemail reload'");
250
                break;
251
            case 'unBanIp':
252
                $result = Firewall::fail2banUnbanAll($data['ip']);
253
                break;
254
            case 'getBanIp':
255
                $result['result'] = 'Success';
256
                $result['data']   = Firewall::getBanIp();
257
                break;
258
            case 'startLog':
259
                $result['result'] = 'Success';
260
                Util::startLog();
261
                break;
262
            case 'stopLog':
263
                $result['result']   = 'Success';
264
                $result['filename'] = Util::stopLog();
265
                break;
266
            case 'statusUpgrade':
267
                $result = System::statusUpgrade();
268
                break;
269
            case 'upgradeOnline':
270
                $result = System::upgradeOnline($request['data']);
271
                break;
272
            case 'upgrade':
273
                $result = System::upgradeFromImg();
274
                break;
275
            case 'removeAudioFile':
276
                $result = Util::removeAudioFile($data['filename']);
277
                break;
278
            case 'convertAudioFile':
279
                $mvPath = Util::which('mv');
280
                Util::mwExec("{$mvPath} {$data['uploadedBlob']} {$data['filename']}");
281
                $result = Util::convertAudioFile($data['filename']);
282
                break;
283
            case 'uploadNewModule':
284
                $module = $request['data']['uniqid'];
285
                System::moduleStartDownload(
286
                    $module,
287
                    $request['data']['url'],
288
                    $request['data']['md5']
289
                );
290
                $result['uniqid']   = $module;
291
                $result['result']   = 'Success';
292
                break;
293
            case 'statusUploadingNewModule':
294
                $module = $request['data']['uniqid'];
295
                $result             = System::moduleDownloadStatus($module);
296
                $result['function'] = $action;
297
                $result['result']   = 'Success';
298
                break;
299
            case 'enableModule':
300
                $module = $request['data']['uniqid'];
301
                $moduleStateProcessor = new PbxExtensionState($module);
302
                if ($moduleStateProcessor->enableModule() === false) {
303
                    $result['messages'] = $moduleStateProcessor->getMessages();
304
                } else {
305
                    unset($result);
306
                    $result['result'] = 'Success';
307
                }
308
                break;
309
            case 'disableModule':
310
                $module = $request['data']['uniqid'];
311
                $moduleStateProcessor = new PbxExtensionState($module);
312
                if ($moduleStateProcessor->disableModule() === false) {
313
                    $result['messages'] = $moduleStateProcessor->getMessages();
314
                } else {
315
                    unset($result);
316
                    $result['result'] = 'Success';
317
                }
318
                break;
319
            case 'uninstallModule':
320
                $module = $request['data']['uniqid'];
321
                $moduleClass = "\\Modules\\{$module}\\Setup\\PbxExtensionSetup";
322
                if (class_exists($moduleClass)
323
                    && method_exists($moduleClass, 'uninstallModule')) {
324
                    $setup = new $moduleClass($module);
325
                } else {
326
                    // Заглушка которая позволяет удалить модуль из базы данных, которого нет на диске
327
                    $moduleClass = PbxExtensionSetupFailure::class;
328
                    $setup       = new $moduleClass($module);
329
                }
330
                $prams = json_decode($request['input'], true);
331
                if (array_key_exists('keepSettings', $prams)) {
332
                    $keepSettings = $prams['keepSettings'] === 'true';
333
                } else {
334
                    $keepSettings = false;
335
                }
336
                if ($setup->uninstallModule($keepSettings)) {
337
                    $result['result'] = 'Success';
338
                } else {
339
                    $result['result'] = 'Error';
340
                    $result['data']   = implode('<br>', $setup->getMessages());
341
                }
342
                WorkerSafeScriptsCore::restartAllWorkers();
343
                break;
344
            default:
345
                $result['message'] = 'API action not found in systemCallBack;';
346
        }
347
348
        $result['function'] = $action;
349
        return $result;
350
    }
351
352
    /**
353
     * Обработка команд управления дисками.
354
     *
355
     * @param array $request
356
     *
357
     * @return array
358
     */
359
    private function storageCallBack($request): array
360
    {
361
        $action = $request['action'];
362
        $data   = $request['data'];
363
364
        $result = [
365
            'result' => 'ERROR',
366
            'data'   => null,
367
        ];
368
369
        if ('list' === $action) {
370
            $st               = new Storage();
371
            $result['result'] = 'Success';
372
            $result['data']   = $st->getAllHdd();
373
        } elseif ('mount' === $action) {
374
            $res              = Storage::mountDisk($data['dev'], $data['format'], $data['dir']);
375
            $result['result'] = ($res === true) ? 'Success' : 'ERROR';
376
        } elseif ('umount' === $action) {
377
            $res              = Storage::umountDisk($data['dir']);
378
            $result['result'] = ($res === true) ? 'Success' : 'ERROR';
379
        } elseif ('mkfs' === $action) {
380
            $res              = Storage::mkfs_disk($data['dev']);
381
            $result['result'] = ($res === true) ? 'Success' : 'ERROR';
382
            $result['data']   = 'inprogress';
383
        } elseif ('statusMkfs' === $action) {
384
            $result['result'] = 'Success';
385
            $result['data']   = Storage::statusMkfs($data['dev']);
386
        }
387
        $result['function'] = $action;
388
389
        return $result;
390
    }
391
392
    /**
393
     * Обработка команд управления модулями.
394
     *
395
     * @param array $request
396
     *
397
     * @return array
398
     */
399
    private function modulesCallBack($request): array
400
    {
401
        clearstatcache();
402
403
        $action = $request['action'];
404
        $module = $request['module'];
405
406
        $result = [
407
            'result' => 'ERROR',
408
            'data'   => null,
409
        ];
410
411
        // Try process request over additional modules
412
        foreach ($this->additionalProcessors as [$moduleUniqueId, $moduleConfigObject, $callBack]) {
413
            if (stripos($module, $moduleUniqueId) === 0) {
414
                $result = $moduleConfigObject->$callBack($request);
415
                break;
416
            }
417
        }
418
419
        $result['function'] = $action;
420
421
        return $result;
422
    }
423
424
    /**
425
     * Upload files callback
426
     * @param $request
427
     *
428
     * @return array
429
     */
430
    private function uploadCallBack($request) :array
431
    {
432
        $action = $request['action'];
433
        $postData   = $request['data'];
434
        switch ($action) {
435
            case 'uploadResumable':
436
                $result = UploadAndConvertFiles::uploadResumable($postData);
437
                break;
438
            case 'status':
439
                $result = UploadAndConvertFiles::statusUploadFile($postData);
440
              break;
441
            default:
442
                $result = [
443
                    'result' => 'ERROR',
444
                    'message'=>'API action not found in uploadCallBack;'
445
                ];
446
        }
447
448
        $result['function'] = $action;
449
        return $result;
450
    }
451
452
}
453
454
// Start worker process
455
$workerClassname = WorkerApiCommands::class;
456
if (isset($argv) && count($argv) > 1 && $argv[1] === 'start') {
457
    cli_set_process_title($workerClassname);
458
    while (true) {
459
        try {
460
            $worker = new $workerClassname();
461
            $worker->start($argv);
462
        } catch (Exception $e) {
463
            global $errorLogger;
464
            $errorLogger->captureException($e);
465
            Util::sysLogMsg("{$workerClassname}_EXCEPTION", $e->getMessage());
466
        }
467
    }
468
}
469