PollClientsTask::updateClients()   A
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 14
c 2
b 0
f 0
nc 4
nop 1
dl 0
loc 20
rs 9.2222
1
<?php
2
3
namespace BiffBangPow\SSMonitor\Server\Task;
4
5
use BiffBangPow\SSMonitor\Server\Helper\ClientHelper;
6
use BiffBangPow\SSMonitor\Server\Helper\CommsHelper;
7
use BiffBangPow\SSMonitor\Server\Helper\EncryptionHelper;
8
use BiffBangPow\SSMonitor\Server\Model\Client;
9
use Psr\Log\LoggerInterface;
10
use SilverStripe\Core\Config\Configurable;
11
use SilverStripe\Core\Environment;
12
use SilverStripe\Core\Extensible;
13
use SilverStripe\Core\Injector\Injector;
14
use SilverStripe\ORM\FieldType\DBDatetime;
15
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
16
use Symbiote\QueuedJobs\Services\QueuedJobService;
17
18
19
class PollClientsTask extends AbstractQueuedJob
20
{
21
    use Configurable;
22
    use Extensible;
23
24
    /**
25
     * @config
26
     * @var int
27
     */
28
    private static $requeue_delay = 180;
0 ignored issues
show
introduced by
The private property $requeue_delay is not used, and could be removed.
Loading history...
29
30
    public function __construct()
31
    {
32
33
    }
34
35
    public function getTitle()
36
    {
37
        return "BBP Monitoring - Collect data";
38
    }
39
40
    public function process()
41
    {
42
        $helper = new CommsHelper();
43
        $res = $helper->process();
44
45
        if (is_array($res)) {
46
            $this->updateClients($res);
47
        } else {
48
            $this->addMessage($res);
49
        }
50
51
        $this->isComplete = true;
52
        $this->addMessage('Done');
53
    }
54
55
    /**
56
     * @param array $res
57
     * @return string
58
     */
59
    private function updateClients($res)
60
    {
61
        foreach ($res as $clientData) {
62
            $clientID = $clientData['client'];
63
            $httpStatus = $clientData['status'];
64
            $body = $clientData['body'];
65
66
            if ((is_int($httpStatus)) && ($httpStatus < 300)) {
67
                //We have a response
68
                $this->updateClientData($clientID, $body);
69
            } else if ((is_int($httpStatus)) && ($httpStatus < 500)) {
70
                //404 error - log it and fail it
71
                $this->failClient(
72
                    $clientID,
73
                    _t(__CLASS__ . '.40xerror', 'The client failed to respond.  Please ensure the client module is installed and the API keys are set up correctly')
74
                );
75
            } else {
76
                $this->failClient(
77
                    $clientID,
78
                    _t(__CLASS__ . '.50xerror', 'The client failed to respond. Please check it is online and configured properly.')
79
                );
80
            }
81
        }
82
    }
83
84
85
    private function updateClientData($clientID, $data)
86
    {
87
        $client = Client::getByUUID($clientID);
88
        $clientHelper = new ClientHelper($client);
89
        if ($client) {
0 ignored issues
show
introduced by
$client is of type BiffBangPow\SSMonitor\Server\Model\Client, thus it always evaluated to true.
Loading history...
90
            $clientSecret = $clientHelper->getEncryptionSecret();
91
            $clientSalt = $clientHelper->getEncryptionSalt();
92
93
            $encHelper = new EncryptionHelper($clientSecret, $clientSalt);
94
            $clientData = $encHelper->decrypt($data);
95
96
            if (!$clientData) {
97
                $this->failClient($clientID, "Error decrypting response data");
98
                return;
99
            }
100
101
            $clientDataArray = unserialize($clientData);
102
103
            if ((!isset($clientDataArray['clientid'])) || ($clientDataArray['clientid'] !== $clientID)) {
104
                $this->failClient($clientID, "UUID from client either not set, or incorrect");
105
                return;
106
            }
107
108
            $client->update([
109
                'LastFetch' => DBDatetime::now()->format('y-MM-dd HH:mm:ss'),
110
                'ErrorMessage' => '',
111
                'FetchError' => false,
112
                'ClientData' => $data,
113
                'Notified' => false
114
            ]);
115
            $client->write();
116
            $this->extend('OnAfterClientUpdate', $client);
117
            return;
118
119
        } else {
120
            $this->failClient($clientID, 'Unknown UUID');
121
            return;
122
        }
123
        $this->failClient($clientID, 'An unknown error occurred');
0 ignored issues
show
Unused Code introduced by
$this->failClient($clien...nknown error occurred') is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
124
    }
125
126
127
    /**
128
     * @param string $clientID
129
     * @return void
130
     * @throws \SilverStripe\ORM\ValidationException
131
     */
132
    private function failClient(string $clientID, $message)
133
    {
134
        $client = Client::getByUUID($clientID);
135
        if ($client) {
0 ignored issues
show
introduced by
$client is of type BiffBangPow\SSMonitor\Server\Model\Client, thus it always evaluated to true.
Loading history...
136
            $client->FetchError = true;
137
            $client->ErrorMessage = $message;
138
            $client->write();
139
            $clientMessage = 'Client: ' . $clientID . ' (' . $client->Title . ') ' . ' : ' . $message;
140
            $this->addMessage($clientMessage);
141
            $this->notifySlack($client, $clientMessage);
142
            $this->extend('OnAfterClientFail', $clientID);
143
        } else {
144
            $this->addMessage('Cannot find client with ID ' . $clientID);
145
        }
146
    }
147
148
    /**
149
     * @param Client $client
150
     * @param $message
151
     * @return void
152
     * @throws \Psr\Container\NotFoundExceptionInterface
153
     */
154
    private function notifySlack($client, $message = null)
155
    {
156
        $webhook = Environment::getEnv('SLACK_WEBHOOK');
157
        $channel = Environment::getEnv('SLACK_CHANNEL');
158
        if ($channel && $webhook && $client->Notified == 0) {
159
            Injector::inst()->get(LoggerInterface::class . '.SlackLogger')
160
                ->error($message);
161
            $client->update([
162
                'Notified' => true
163
            ]);
164
            $client->write();
165
        }
166
    }
167
168
    public function afterComplete()
169
    {
170
        $requeue_delay = $this->config()->get('requeue_delay');
171
        Injector::inst()->get(LoggerInterface::class)->info("Client job finished.  Requeuing in " . $requeue_delay . " seconds");
172
173
        $newJob = new PollClientsTask();
174
        if ($requeue_delay > 0) {
175
            singleton(QueuedJobService::class)
176
                ->queueJob(
177
                    $newJob,
178
                    date(
179
                        'Y-m-d H:i:s',
180
                        strtotime('+' . $requeue_delay . ' seconds')
181
                    )
182
                );
183
        } else {
184
            singleton(QueuedJobService::class)->queueJob($newJob);
185
        }
186
187
        parent::afterComplete();
188
    }
189
190
}
191