Completed
Push — master ( a21764...976a0d )
by Dan
01:41
created

PluginManager   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 4
dl 0
loc 207
rs 8.8
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A loadPlugin() 0 11 2
A __construct() 0 6 1
A getHelp() 0 15 3
A getStatuses() 0 13 2
A setAuthedUser() 0 6 1
A matchesPrefix() 0 10 2
A dispatchMessage() 0 16 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: ', ['formattedText' => $text]);
103
104
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
105
            $this->debug("Dispatching priority $priority");
106
107
            $this->dispatchToPrefixes($prefixMap, $message, $text);
108
109
            if ($message->isHandled()) {
110
                return;
111
            }
112
        }
113
    }
114
115
    protected function dispatchToPrefixes(array $prefixMap, Message $message, string $text)
116
    {
117
        foreach ($prefixMap as $prefix => $plugins) {
118
            if ($matches = $this->matchesPrefix($prefix, $text)) {
119
                $this->debug("Dispatching prefix '$prefix'");
120
121
                $message->setPluginText(ltrim($matches[1]));
122
123
                $this->dispatchToPlugins($plugins, $message);
124
125
                if ($message->isHandled()) {
126
                    return;
127
                }
128
            }
129
        }
130
    }
131
132
    protected function dispatchToPlugins(array $plugins, Message $message)
133
    {
134
        foreach ($plugins as $pluginId => $plugin) {
135
            /** @var PluginInterface $plugin */
136
            try {
137
                $plugin->handle($message);
138
139
            } catch (Throwable $throwable) {
140
                $errmsg = "Unhandled Exception in $pluginId\n"
141
                    .$throwable->getMessage()."\n"
142
                    .$throwable->getTraceAsString()."\n"
143
                    ."Payload data: ".json_encode($message->getData());
144
                $this->warning($errmsg);
145
            }
146
147
            if ($message->isHandled()) {
148
                return;
149
            }
150
        }
151
    }
152
153
    protected function addPlugin($pluginId, PluginInterface $plugin)
154
    {
155
        $this->pluginMap[$pluginId] = $plugin;
156
157
        $priority = $plugin->getPriority();
158
        if (!isset($this->priorityMap[$priority])) {
159
            $this->priorityMap[$priority] = [];
160
        }
161
162
        $prefix = $plugin->getPrefix();
163
        if (!isset($this->priorityMap[$priority][$prefix])) {
164
            $this->priorityMap[$priority][$prefix] = [];
165
        }
166
167
        $this->priorityMap[$priority][$prefix][$pluginId] = $plugin;
168
169
        krsort($this->priorityMap);
170
    }
171
172
    protected function getPluginMap() : array
173
    {
174
        return $this->pluginMap;
175
    }
176
177
    protected function getPriorityMap() : array
178
    {
179
        return $this->priorityMap;
180
    }
181
182
    protected function setPriorityMap(array $priorityMap)
183
    {
184
        $this->priorityMap = $priorityMap;
185
    }
186
187
    protected function getAuthedUser()
188
    {
189
        return $this->authedUser;
190
    }
191
192
    protected function updatePrefixes($authedUsername)
193
    {
194
        $updatedPriorityMap = [];
195
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
196
            $updatedPrefixMap = [];
197
            foreach ($prefixMap as $prefix => $plugins) {
198
                if ($prefix === self::AUTHED_USER_PREFIX) {
199
                    $prefix = '@'.$authedUsername;
200
                }
201
                $updatedPrefixMap[$prefix] = $plugins;
202
            }
203
            $updatedPriorityMap[$priority] = $updatedPrefixMap;
204
        }
205
        $this->priorityMap = $updatedPriorityMap;
206
    }
207
208
    protected function helpPrefix($prefix)
209
    {
210
        if ($prefix === self::NO_PREFIX) {
211
            return '';
212
        }
213
214
        if ($prefix === self::AUTHED_USER_PREFIX) {
215
            $prefix = '@'.$this->getAuthedUser()->getUsername();
216
        }
217
218
        return "$prefix ";
219
    }
220
}