Completed
Push — master ( 1b605f...95b7c3 )
by Dan
06:00
created

Yabot::onMessage()   B

Complexity

Conditions 4
Paths 7

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 14
nc 7
nop 1
1
<?php
2
3
namespace Nopolabs\Yabot;
4
5
use DateTime;
6
use Exception;
7
use Nopolabs\Yabot\Helpers\LogTrait;
8
use Nopolabs\Yabot\Helpers\SlackTrait;
9
use Nopolabs\Yabot\Message\MessageFactory;
10
use Nopolabs\Yabot\Plugin\PluginInterface;
11
use Nopolabs\Yabot\Plugin\PluginManager;
12
use Nopolabs\Yabot\Slack\Client;
13
use Psr\Log\LoggerInterface;
14
use React\EventLoop\LoopInterface;
15
use Slack\Payload;
16
use Slack\User;
17
use Throwable;
18
19
class Yabot
20
{
21
    use LogTrait;
22
    use SlackTrait;
23
24
    const AUTHED_USER = 'AUTHED_USER';
25
26
    /** @var LoopInterface */
27
    private $eventLoop;
28
29
    /** @var MessageFactory */
30
    private $messageFactory;
31
32
    /** @var PluginManager */
33
    private $pluginManager;
34
35
    private $messageLog;
36
37
    public function __construct(
38
        LoggerInterface $logger,
39
        LoopInterface $eventLoop,
40
        Client $slackClient,
41
        MessageFactory $messageFactory,
42
        PluginManager $pluginManager
43
    ) {
44
        $this->setLog($logger);
45
        $this->setSlack($slackClient);
46
        $this->eventLoop = $eventLoop;
47
        $this->messageFactory = $messageFactory;
48
        $this->pluginManager = $pluginManager;
49
        $this->messageLog = null;
50
    }
51
52
    public function getMessageLog()
53
    {
54
        return $this->messageLog;
55
    }
56
57
    public function setMessageLog(string $messageLog = null)
58
    {
59
        $this->messageLog = $messageLog;
60
    }
61
62
    public function init(array $plugins)
63
    {
64 View Code Duplication
        foreach ($plugins as $pluginId => $plugin) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
65
            /** @var PluginInterface $plugin */
66
67
            $this->info("loading $pluginId");
68
69
            try {
70
                $this->pluginManager->loadPlugin($pluginId, $plugin);
71
            } catch (Exception $e) {
72
                $this->warning("Unhandled Exception while loading $pluginId: ".$e->getMessage());
73
                $this->warning($e->getTraceAsString());
74
            }
75
        }
76
    }
77
78
    public function run()
79
    {
80
        $slack = $this->getSlack();
81
82
        $slack->init();
83
84
        $slack->connect()->then([$this, 'connected']);
85
86
        $this->addMemoryReporting();
87
88
        $this->eventLoop->run();
89
    }
90
91
    public function connected()
92
    {
93
        $slack = $this->getSlack();
94
95
        $slack->update(function (User $authedUser) {
96
            $this->pluginManager->updatePrefixes($authedUser->getUsername());
97
        });
98
99
        $slack->on('message', [$this, 'onMessage']);
100
    }
101
102
    public function onMessage(Payload $payload)
103
    {
104
        $data = $payload->getData();
105
106
        $this->debug('Received message', $data);
107
108
        try {
109
            if ($this->messageLog) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->messageLog of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
110
                $this->logMessage($data);
111
            }
112
            $message = $this->messageFactory->create($data);
113
        } catch (Throwable $throwable) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
114
            $this->warning($throwable->getMessage());
115
            $this->warning($throwable->getTraceAsString());
116
            return;
117
        }
118
119
        if ($message->isSelf()) {
120
            return;
121
        }
122
123
        $this->pluginManager->dispatchMessage($message);
124
    }
125
126
    public function getHelp() : string
127
    {
128
        return implode("\n", $this->pluginManager->getHelp());
129
    }
130
131
    public function getStatus() : string
132
    {
133
        $statuses = $this->pluginManager->getStatuses();
134
135
        array_unshift($statuses, $this->getFormattedMemoryUsage());
136
137
        return implode("\n", $statuses);
138
    }
139
140
    public function addTimer($interval, callable $callback)
141
    {
142
        $this->eventLoop->addTimer($interval, $callback);
143
    }
144
145
    public function addPeriodicTimer($interval, callable $callback)
146
    {
147
        $this->eventLoop->addPeriodicTimer($interval, $callback);
148
    }
149
150
    protected function addMemoryReporting()
151
    {
152
        $now = new DateTime();
153
        $then = new DateTime('+1 hour');
154
        $then->setTime($then->format('H'), 0, 0);
155
        $delay = $then->getTimestamp() - $now->getTimestamp();
156
157
        $this->addTimer($delay, function() {
158
            $this->info($this->getFormattedMemoryUsage());
159
            $this->addPeriodicTimer(3600, function () {
160
                $this->info($this->getFormattedMemoryUsage());
161
            });
162
        });
163
    }
164
165
    protected function getFormattedMemoryUsage() : string
166
    {
167
        $memory = memory_get_usage() / 1024;
168
        $formatted = number_format($memory, 3).'K';
169
        return "Current memory usage: {$formatted}";
170
    }
171
172
    private function logMessage($data)
173
    {
174
        file_put_contents($this->messageLog, json_encode($data)."\n", FILE_APPEND);
175
    }
176
}
177