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) { |
|
|
|
|
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) { |
|
|
|
|
110
|
|
|
$this->logMessage($data); |
111
|
|
|
} |
112
|
|
|
$message = $this->messageFactory->create($data); |
113
|
|
|
} catch (Throwable $throwable) { |
|
|
|
|
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
|
|
|
|
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.