Completed
Push — master ( 72e54c...a21764 )
by Dan
01:33
created

PluginManager   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 4
dl 0
loc 204
rs 9
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A loadPlugin() 0 11 2
A __construct() 0 6 1
B getHelp() 0 25 5
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
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 = $plugin->getPrefix();
56
            if ($prefix === self::NO_PREFIX) {
57
                $prefix = '';
58
            } else {
59
                if ($prefix === self::AUTHED_USER_PREFIX) {
60
                    $prefix = '@'.$this->getAuthedUser()->getUsername();
61
                }
62
63
                $prefix = "$prefix ";
64
            }
65
66
            $help[] = $pluginId;
67
            $lines = explode("\n", trim($plugin->help()));
68
            foreach ($lines as $line) {
69
                $help[] = '    '.str_replace('<prefix> ', $prefix, $line);
70
            }
71
        }
72
73
        return $help;
74
    }
75
76
    public function getStatuses() : array
77
    {
78
        $count = count($this->getPluginMap());
79
80
        $statuses = [];
81
        $statuses[] = "There are $count plugins loaded.";
82
        foreach ($this->getPluginMap() as $pluginId => $plugin) {
83
            /** @var PluginInterface $plugin */
84
            $statuses[] = "$pluginId ".$plugin->status();
85
        }
86
87
        return $statuses;
88
    }
89
90
    public function setAuthedUser(User $authedUser)
91
    {
92
        $this->authedUser = $authedUser;
93
94
        $this->updatePrefixes($authedUser->getUsername());
95
    }
96
97
    public function matchesPrefix($prefix, $text) : array
98
    {
99
        if ($prefix === self::NO_PREFIX) {
100
            return [$text, $text];
101
        }
102
103
        preg_match("/^$prefix\\s+(.*)/", $text, $matches);
104
105
        return $matches;
106
    }
107
108
    public function dispatchMessage(Message $message)
109
    {
110
        $text = $message->getFormattedText();
111
112
        $this->info('dispatchMessage: ', ['formattedText' => $text]);
113
114
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
115
            $this->debug("Dispatching priority $priority");
116
117
            $this->dispatchToPrefixes($prefixMap, $message, $text);
118
119
            if ($message->isHandled()) {
120
                return;
121
            }
122
        }
123
    }
124
125
    protected function dispatchToPrefixes(array $prefixMap, Message $message, string $text)
126
    {
127
        foreach ($prefixMap as $prefix => $plugins) {
128
            if ($matches = $this->matchesPrefix($prefix, $text)) {
129
                $this->debug("Dispatching prefix '$prefix'");
130
131
                $message->setPluginText(ltrim($matches[1]));
132
133
                $this->dispatchToPlugins($plugins, $message);
134
135
                if ($message->isHandled()) {
136
                    return;
137
                }
138
            }
139
        }
140
    }
141
142
    protected function dispatchToPlugins(array $plugins, Message $message)
143
    {
144
        foreach ($plugins as $pluginId => $plugin) {
145
            /** @var PluginInterface $plugin */
146
            try {
147
                $plugin->handle($message);
148
149
            } catch (Throwable $throwable) {
150
                $errmsg = "Unhandled Exception in $pluginId\n"
151
                    .$throwable->getMessage()."\n"
152
                    .$throwable->getTraceAsString()."\n"
153
                    ."Payload data: ".json_encode($message->getData());
154
                $this->warning($errmsg);
155
            }
156
157
            if ($message->isHandled()) {
158
                return;
159
            }
160
        }
161
    }
162
163
    protected function addPlugin($pluginId, PluginInterface $plugin)
164
    {
165
        $this->pluginMap[$pluginId] = $plugin;
166
167
        $priority = $plugin->getPriority();
168
        if (!isset($this->priorityMap[$priority])) {
169
            $this->priorityMap[$priority] = [];
170
        }
171
172
        $prefix = $plugin->getPrefix();
173
        if (!isset($this->priorityMap[$priority][$prefix])) {
174
            $this->priorityMap[$priority][$prefix] = [];
175
        }
176
177
        $this->priorityMap[$priority][$prefix][$pluginId] = $plugin;
178
179
        krsort($this->priorityMap);
180
    }
181
182
    protected function getPluginMap() : array
183
    {
184
        return $this->pluginMap;
185
    }
186
187
    protected function getPriorityMap() : array
188
    {
189
        return $this->priorityMap;
190
    }
191
192
    protected function setPriorityMap(array $priorityMap)
193
    {
194
        $this->priorityMap = $priorityMap;
195
    }
196
197
    protected function getAuthedUser()
198
    {
199
        return $this->authedUser;
200
    }
201
202
    protected function updatePrefixes($authedUsername)
203
    {
204
        $updatedPriorityMap = [];
205
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
206
            $updatedPrefixMap = [];
207
            foreach ($prefixMap as $prefix => $plugins) {
208
                if ($prefix === self::AUTHED_USER_PREFIX) {
209
                    $prefix = '@'.$authedUsername;
210
                }
211
                $updatedPrefixMap[$prefix] = $plugins;
212
            }
213
            $updatedPriorityMap[$priority] = $updatedPrefixMap;
214
        }
215
        $this->priorityMap = $updatedPriorityMap;
216
    }
217
}