PluginManager   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 5
dl 0
loc 213
rs 9.52
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A loadPlugin() 0 11 2
A getHelp() 0 15 3
A getStatuses() 0 13 2
A setAuthedUser() 0 6 1
A matchesPrefix() 0 10 2
A dispatchMessage() 0 22 3
A dispatchToPrefixes() 0 16 4
A dispatchToPlugins() 0 20 4
A addPlugin() 0 18 3
A getPluginMap() 0 4 1
A getPriorityMap() 0 4 1
A setPriorityMap() 0 4 1
A getAuthedUser() 0 4 1
A updatePrefixes() 0 15 4
A helpPrefix() 0 12 3
1
<?php
2
3
namespace Nopolabs\Yabot\Plugin;
4
5
6
use Exception;
7
use Nopolabs\Yabot\Helpers\LogTrait;
8
use Nopolabs\Yabot\Message\Message;
9
use Nopolabs\Yabot\Yabot;
10
use Psr\Log\LoggerInterface;
11
use Slack\User;
12
use Throwable;
13
14
class PluginManager
15
{
16
    use LogTrait;
17
18
    const NO_PREFIX = '<none>';
19
    const AUTHED_USER_PREFIX = '<authed_user>';
20
    const DEFAULT_PRIORITY = 100;
21
22
    /** @var User */
23
    protected $authedUser;
24
25
    /** @var array */
26
    protected $pluginMap;
27
28
    /** @var array */
29
    protected $priorityMap;
30
31
    public function __construct(LoggerInterface $logger)
32
    {
33
        $this->setLog($logger);
34
35
        $this->priorityMap = [];
36
    }
37
38
    public function loadPlugin($pluginId, PluginInterface $plugin)
39
    {
40
        if (isset($this->pluginMap[$pluginId])) {
41
            $this->warning("$pluginId already loaded, ignoring duplicate.");
42
            return;
43
        }
44
45
        $this->addPlugin($pluginId, $plugin);
46
47
        $this->info('loaded', ['pluginId' => $pluginId, 'prefix' => $plugin->getPrefix()]);
48
    }
49
50
    public function getHelp() : array
51
    {
52
        $help = [];
53
        /** @var PluginInterface $plugin */
54
        foreach ($this->getPluginMap() as $pluginId => $plugin) {
55
            $prefix = $this->helpPrefix($plugin->getPrefix());
56
            $help[] = $pluginId;
57
            $lines = explode("\n", trim($plugin->help()));
58
            foreach ($lines as $line) {
59
                $help[] = '    '.str_replace('<prefix> ', $prefix, $line);
60
            }
61
        }
62
63
        return $help;
64
    }
65
66
    public function getStatuses() : array
67
    {
68
        $count = count($this->getPluginMap());
69
70
        $statuses = [];
71
        $statuses[] = "There are $count plugins loaded.";
72
        foreach ($this->getPluginMap() as $pluginId => $plugin) {
73
            /** @var PluginInterface $plugin */
74
            $statuses[] = "$pluginId ".$plugin->status();
75
        }
76
77
        return $statuses;
78
    }
79
80
    public function setAuthedUser(User $authedUser)
81
    {
82
        $this->authedUser = $authedUser;
83
84
        $this->updatePrefixes($authedUser->getUsername());
85
    }
86
87
    public function matchesPrefix($prefix, $text) : array
88
    {
89
        if ($prefix === self::NO_PREFIX) {
90
            return [$text, $text];
91
        }
92
93
        preg_match("/^$prefix\\s+(.*)/", $text, $matches);
94
95
        return $matches;
96
    }
97
98
    public function dispatchMessage(Message $message)
99
    {
100
        $text = $message->getFormattedText();
101
102
        $this->info('dispatchMessage: ', [
103
            'formattedText' => $text,
104
            'user' => $message->getUsername(),
105
            'channel' => $message->getChannel()->getName(),
0 ignored issues
show
Bug introduced by
Consider using $message->getChannel()->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
106
            'isBot' => $message->isBot(),
107
            'isSelf' => $message->isSelf(),
108
        ]);
109
110
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
111
            $this->debug("Dispatching priority $priority");
112
113
            $this->dispatchToPrefixes($prefixMap, $message, $text);
114
115
            if ($message->isHandled()) {
116
                return;
117
            }
118
        }
119
    }
120
121
    protected function dispatchToPrefixes(array $prefixMap, Message $message, string $text)
122
    {
123
        foreach ($prefixMap as $prefix => $plugins) {
124
            if ($matches = $this->matchesPrefix($prefix, $text)) {
125
                $this->debug("Dispatching prefix '$prefix'");
126
127
                $message->setPluginText(ltrim($matches[1]));
128
129
                $this->dispatchToPlugins($plugins, $message);
130
131
                if ($message->isHandled()) {
132
                    return;
133
                }
134
            }
135
        }
136
    }
137
138
    protected function dispatchToPlugins(array $plugins, Message $message)
139
    {
140
        foreach ($plugins as $pluginId => $plugin) {
141
            /** @var PluginInterface $plugin */
142
            try {
143
                $plugin->handle($message);
144
145
            } catch (Throwable $throwable) {
146
                $errmsg = "Unhandled Exception in $pluginId\n"
147
                    .$throwable->getMessage()."\n"
148
                    .$throwable->getTraceAsString()."\n"
149
                    ."Payload data: ".json_encode($message->getData());
150
                $this->warning($errmsg);
151
            }
152
153
            if ($message->isHandled()) {
154
                return;
155
            }
156
        }
157
    }
158
159
    protected function addPlugin($pluginId, PluginInterface $plugin)
160
    {
161
        $this->pluginMap[$pluginId] = $plugin;
162
163
        $priority = $plugin->getPriority();
164
        if (!isset($this->priorityMap[$priority])) {
165
            $this->priorityMap[$priority] = [];
166
        }
167
168
        $prefix = $plugin->getPrefix();
169
        if (!isset($this->priorityMap[$priority][$prefix])) {
170
            $this->priorityMap[$priority][$prefix] = [];
171
        }
172
173
        $this->priorityMap[$priority][$prefix][$pluginId] = $plugin;
174
175
        krsort($this->priorityMap);
176
    }
177
178
    protected function getPluginMap() : array
179
    {
180
        return $this->pluginMap;
181
    }
182
183
    protected function getPriorityMap() : array
184
    {
185
        return $this->priorityMap;
186
    }
187
188
    protected function setPriorityMap(array $priorityMap)
189
    {
190
        $this->priorityMap = $priorityMap;
191
    }
192
193
    protected function getAuthedUser()
194
    {
195
        return $this->authedUser;
196
    }
197
198
    protected function updatePrefixes($authedUsername)
199
    {
200
        $updatedPriorityMap = [];
201
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
202
            $updatedPrefixMap = [];
203
            foreach ($prefixMap as $prefix => $plugins) {
204
                if ($prefix === self::AUTHED_USER_PREFIX) {
205
                    $prefix = '@'.$authedUsername;
206
                }
207
                $updatedPrefixMap[$prefix] = $plugins;
208
            }
209
            $updatedPriorityMap[$priority] = $updatedPrefixMap;
210
        }
211
        $this->priorityMap = $updatedPriorityMap;
212
    }
213
214
    protected function helpPrefix($prefix)
215
    {
216
        if ($prefix === self::NO_PREFIX) {
217
            return '';
218
        }
219
220
        if ($prefix === self::AUTHED_USER_PREFIX) {
221
            return '@'.$this->getAuthedUser()->getUsername().' ';
222
        }
223
224
        return "$prefix ";
225
    }
226
}