Completed
Push — master ( e1d324...363ea4 )
by Dan
02:22
created

PluginManager::setPriorityMap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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 Throwable;
12
13
class PluginManager
14
{
15
    use LogTrait;
16
17
    const NO_PREFIX = '<none>';
18
    const AUTHED_USER_PREFIX = '<authed_user>';
19
    const DEFAULT_PRIORITY = 100;
20
21
    /** @var array */
22
    protected $pluginMap;
23
24
    /** @var array */
25
    protected $priorityMap;
26
27
    public function __construct(LoggerInterface $logger)
28
    {
29
        $this->setLog($logger);
30
31
        $this->priorityMap = [];
32
    }
33
34
    public function loadPlugin($pluginId, PluginInterface $plugin)
35
    {
36
        if (isset($this->pluginMap[$pluginId])) {
37
            $this->warning("$pluginId already loaded, ignoring duplicate.");
38
            return;
39
        }
40
41
        $this->addPlugin($pluginId, $plugin);
42
43
        $this->info('loaded', ['pluginId' => $pluginId, 'prefix' => $plugin->getPrefix()]);
44
    }
45
46
    public function getHelp() : array
47
    {
48
        $help = [];
49
        foreach ($this->getPluginMap() as $pluginId => $plugin) {
50
            /** @var PluginInterface $plugin */
51
            $help[] = $pluginId;
52
            foreach (explode("\n", trim($plugin->help())) as $line) {
53
                $prefix = $plugin->getPrefix();
54
                $prefix = ($prefix === self::NO_PREFIX) ? '' : $prefix;
55
                $help[] = '    '.str_replace('<prefix>', $prefix, $line);
56
            }
57
        }
58
59
        return $help;
60
    }
61
62
    public function getStatuses() : array
63
    {
64
        $count = count($this->getPluginMap());
65
66
        $statuses = [];
67
        $statuses[] = "There are $count plugins loaded.";
68
        foreach ($this->getPluginMap() as $pluginId => $plugin) {
69
            /** @var PluginInterface $plugin */
70
            $statuses[] = "$pluginId ".$plugin->status();
71
        }
72
73
        return $statuses;
74
    }
75
76
    public function updatePrefixes($authedUsername)
77
    {
78
        $updatedPriorityMap = [];
79
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
80
            $updatedPrefixMap = [];
81
            foreach ($prefixMap as $prefix => $plugins) {
82
                if ($prefix === self::AUTHED_USER_PREFIX) {
83
                    $prefix = '@'.$authedUsername;
84
                }
85
                $updatedPrefixMap[$prefix] = $plugins;
86
            }
87
            $updatedPriorityMap[$priority] = $updatedPrefixMap;
88
        }
89
        $this->priorityMap = $updatedPriorityMap;
90
    }
91
92
    public function matchesPrefix($prefix, $text) : array
93
    {
94
        if ($prefix === self::NO_PREFIX) {
95
            return [$text, $text];
96
        }
97
98
        preg_match("/^$prefix\\s+(.*)/", $text, $matches);
99
100
        return $matches;
101
    }
102
103
    public function dispatchMessage(Message $message)
104
    {
105
        $text = $message->getFormattedText();
106
107
        $this->info('dispatchMessage: ', ['formattedText' => $text]);
108
109
        foreach ($this->getPriorityMap() as $priority => $prefixMap) {
110
            $this->debug("Dispatching priority $priority");
111
112
            $this->dispatchToPrefixes($prefixMap, $message, $text);
113
114
            if ($message->isHandled()) {
115
                return;
116
            }
117
        }
118
    }
119
120
    protected function dispatchToPrefixes(array $prefixMap, Message $message, string $text)
121
    {
122
        foreach ($prefixMap as $prefix => $plugins) {
123
            if ($matches = $this->matchesPrefix($prefix, $text)) {
124
                $this->debug("Dispatching prefix '$prefix'");
125
126
                $message->setPluginText(ltrim($matches[1]));
127
128
                $this->dispatchToPlugins($plugins, $message);
129
130
                if ($message->isHandled()) {
131
                    return;
132
                }
133
            }
134
        }
135
    }
136
137
    protected function dispatchToPlugins(array $plugins, Message $message)
138
    {
139
        foreach ($plugins as $pluginId => $plugin) {
140
            /** @var PluginInterface $plugin */
141
            try {
142
                $plugin->handle($message);
143
144
            } catch (Throwable $throwable) {
145
                $errmsg = "Unhandled Exception in $pluginId\n"
146
                    .$throwable->getMessage()."\n"
147
                    .$throwable->getTraceAsString()."\n"
148
                    ."Payload data: ".json_encode($message->getData());
149
                $this->warning($errmsg);
150
            }
151
152
            if ($message->isHandled()) {
153
                return;
154
            }
155
        }
156
    }
157
158
    protected function addPlugin($pluginId, PluginInterface $plugin)
159
    {
160
        $this->pluginMap[$pluginId] = $plugin;
161
162
        $priority = $plugin->getPriority();
163
        if (!isset($this->priorityMap[$priority])) {
164
            $this->priorityMap[$priority] = [];
165
        }
166
167
        $prefix = $plugin->getPrefix();
168
        if (!isset($this->priorityMap[$priority][$prefix])) {
169
            $this->priorityMap[$priority][$prefix] = [];
170
        }
171
172
        $this->priorityMap[$priority][$prefix][$pluginId] = $plugin;
173
174
        krsort($this->priorityMap);
175
    }
176
177
    protected function getPluginMap() : array
178
    {
179
        return $this->pluginMap;
180
    }
181
182
    protected function getPriorityMap() : array
183
    {
184
        return $this->priorityMap;
185
    }
186
187
    protected function setPriorityMap(array $priorityMap)
188
    {
189
        $this->priorityMap = $priorityMap;
190
    }
191
}