Passed
Branch dev (7cf5cf)
by
unknown
02:40
created

Dramiel.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2016  Robert Sardinia
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 */
25
26
// Require the vendor stuff
27
/** @noinspection PhpIncludeInspection */
28
require_once __DIR__ . '/vendor/autoload.php';
29
30
// Setup logger
31
use Discord\Discord;
32
use Discord\Parts\User\Game;
33
use Discord\WebSockets\Event;
34
use Discord\WebSockets\WebSocket;
35
use Monolog\Handler\StreamHandler;
36
use Monolog\Logger;
37
38
// More memory allowance
39
ini_set('memory_limit', '1024M');
40
41
// Just in case we get launched from somewhere else
42
chdir(__DIR__);
43
44
// Enable garbage collection
45
gc_enable();
46
47
// When the bot started
48
$startTime = time();
49
50
// create a log channel
51
$logger = new Logger('Dramiel');
52
$logger->pushHandler(new StreamHandler(__DIR__ . '/log/dramielLog.log', Logger::INFO));
53
$logger->addInfo('Logger Initiated');
54
55
GLOBAL $logger;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
56
57
// Require the config
58
if (file_exists('config/config.php')) {
59
    /** @noinspection PhpIncludeInspection */
60
    require_once 'config/config.php';
61
} else {
62
    $logger->error('config.php not found (you might wanna start by editing and renaming config_new.php)');
63
    die();
64
}
65
66
// Load the library files (Probably a prettier way to do this that i haven't thought up yet)
67
foreach (glob(__DIR__ . '/src/lib/*.php') as $lib) {
68
    /** @noinspection PhpIncludeInspection */
69
    require_once $lib;
70
}
71
72
//Startup DB Check
73
updateDramielDB($logger);
74
75
// Init Discord
76
$discord = new Discord(['token' => $config['bot']['token']]);
77
78
// Load tick plugins
79
$pluginDirs = array('src/plugins/onTick/*.php');
80
$logger->info('Loading background plugins');
81
$plugins = array();
82
$pluginsT = array();
83
foreach ($pluginDirs as $dir) {
84
    foreach (glob($dir) as $plugin) {
85
        // Only load the plugins we want to load, according to the config
86
        if (!in_array(str_replace('.php', '', basename($plugin)), $config['enabledPlugins'])) {
87
            continue;
88
        }
89
90
        /** @noinspection PhpIncludeInspection */
91
        require_once $plugin;
92
        $fileName = str_replace('.php', '', basename($plugin));
93
        $p = new $fileName();
94
        $p->init($config, $discord, $logger);
95
        $pluginsT[] = $p;
96
    }
97
}
98
// Number of plugins loaded
99
$logger->info('Loaded: ' . count($pluginsT) . ' background plugins');
100
101
if ($config['bot']['silentMode'] == 'false' || !isset($config['bot']['silentMode'])) {
102
// Load chat plugins
103
    $pluginDirs = array('src/plugins/onMessage/*.php', 'src/plugins/admin/*.php');
104
    $adminPlugins = array('setNickname', 'getLog', 'setGame');
105
    $logger->addInfo('Loading in chat plugins');
106
    $plugins = array();
107
    foreach ($pluginDirs as $dir) {
108
        foreach (glob($dir) as $plugin) {
109
            // Only load the plugins we want to load, according to the config
110
            if (!in_array(str_replace('.php', '', basename($plugin)), $config['enabledPlugins']) && !in_array(str_replace('.php', '', basename($plugin)), $adminPlugins)) {
111
                continue;
112
            }
113
114
            /** @noinspection PhpIncludeInspection */
115
            require_once $plugin;
116
            $fileName = str_replace('.php', '', basename($plugin));
117
            $p = new $fileName();
118
            $p->init($config, $discord, $logger);
119
            $plugins[] = $p;
120
        }
121
    }
122
123
// Number of chat plugins loaded
124
    $logger->addInfo('Loaded: ' . count($plugins) . ' chat plugins');
125
}
126
127
// Clear queue at restart if it's too high
128
clearQueueCheck();
129
130
//Check initial server state (tick plugins will not run if eve is offline)
131
$crestData = json_decode(downloadData('https://crest-tq.eveonline.com/'), true);
132
$crestStatus = isset($crestData['serviceStatus']) ? $crestData['serviceStatus'] : 'offline';
133
setPermCache('serverState', $crestStatus);
134
setPermCache('statusLastState', $crestStatus);
135
$logger->addInfo("serverState: EVE is currently {$crestStatus}");
136
137
//Clean up any outdated databases
138
dbPrune();
139
140
$discord->on(
141
    'ready',
142
    function($discord) use ($logger, $config, $plugins, $pluginsT, $discord) {
0 ignored issues
show
Bug Best Practice introduced by
The parameter name $discord conflicts with one of the imported variables.
Loading history...
143
        // In here we can access any of the WebSocket events.
144
        //
145
        // There is a list of event constants that you can
146
        // find here: https://teamreflex.github.io/DiscordPHP/classes/Discord.WebSockets.Event.html
147
        //
148
        // We will echo to the console that the WebSocket is ready.
149
        $logger->addInfo('Discord WebSocket is ready!' . PHP_EOL);
150
151
        //Clear queue if it's super backed up
152
153
154
        //Set Initial Game
155
        $gameTitle = $config['bot']['game'];
156
        if (null !== getPermCache('botGame')) {
157
            $gameTitle = getPermCache('botGame');
158
        }
159
        $game = $discord->factory(Game::class, [
160
            'name' => $gameTitle,
161
        ]);
162
        $discord->updatePresence($game);
163
164
        // Server Status Check (tick plugins will not run if eve is offline)
165
        $discord->loop->addPeriodicTimer(60, function() use ($logger) {
166
            $crestData = json_decode(downloadData('https://crest-tq.eveonline.com/'), true);
167
            $crestStatus = isset($crestData['serviceStatus']) ? $crestData['serviceStatus'] : 'offline';
168
            setPermCache('serverState', $crestStatus);
169
        });
170
171
        // Run the Tick plugins
172
        $discord->loop->addPeriodicTimer(3, function() use ($pluginsT) {
173
            foreach ($pluginsT as $plugin) {
174
                $plugin->tick();
175
            }
176
        });
177
178
        // Message queue
179
        $discord->loop->addPeriodicTimer(7, function() use ($discord, $logger) {
180
            $x = 0;
181
            while ($x < 3) {
182
                $id = getOldestMessage();
0 ignored issues
show
Are you sure the assignment to $id is correct as getOldestMessage() seems to always returns null.
Loading history...
183
                $id = $id['MIN(id)'];
184
                if (null === $id) {
185
                    $id = 1;
186
                }
187
                $queuedMessage = getQueuedMessage($id);
0 ignored issues
show
Are you sure the assignment to $queuedMessage is correct as getQueuedMessage($id) (which targets getQueuedMessage()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
188
                if (null !== $queuedMessage) {
189
                    //Check if queued item is corrupt and delete it if it is
190
                    if (null === $queuedMessage['guild'] || null === $queuedMessage['channel'] || null === $queuedMessage['message']) {
191
                        $logger->addInfo("QueueProcessing Error- Item #{$id} : Queued item is badly formed, removing it from the queue");
192
                        clearQueuedMessages($id);
193
                    }
194
                    $guild = $discord->guilds->get('id', $queuedMessage['guild']);
0 ignored issues
show
The property guilds does not seem to exist. Did you mean largeGuilds?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
195
                    $channel = $guild->channels->get('id', $queuedMessage['channel']);
196
                    //Check if channel is bad
197
                    if (null === $channel || null === $guild) {
198
                        $logger->addInfo("QueueProcessing Error- Item #{$id} : Channel provided is incorrect, removing it from the queue");
199
                        clearQueuedMessages($id);
200
                    }
201
                    $logger->addInfo("QueueProcessing - Completing queued item #{$id}");
202
                    $channel->sendMessage($queuedMessage['message'], false);
203
                    clearQueuedMessages($id);
204
                }
205
                $x++;
206
            }
207
        });
208
209
        // Rename queue
210
        $discord->loop->addPeriodicTimer(10, function() use ($discord, $logger) {
211
            $x = 0;
212
            while ($x < 4) {
213
                $id = getOldestRename();
0 ignored issues
show
Are you sure the assignment to $id is correct as getOldestRename() seems to always returns null.
Loading history...
214
                $id = $id['MIN(id)'];
215
                if (null === $id) {
216
                    $id = 1;
217
                    $x = 4;
218
                }
219
                $queuedRename = getQueuedRename($id);
0 ignored issues
show
Are you sure the assignment to $queuedRename is correct as getQueuedRename($id) (which targets getQueuedRename()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
220
                if (null !== $queuedRename) {
221
                    //Check if queued item is corrupt and delete it if it is
222
                    if (null === $queuedRename['guild'] || null === $queuedRename['discordID']) {
223
                        clearQueuedRename($id);
224
                    }
225
                    $guild = $discord->guilds->get('id', $queuedRename['guild']);
0 ignored issues
show
The property guilds does not seem to exist. Did you mean largeGuilds?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
226
                    $member = $guild->members->get('id', $queuedRename['discordID']);
227
                    $member->setNickname($queuedRename['nick']);
228
                    clearQueuedRename($id);
229
                }
230
                $x++;
231
            }
232
        });
233
234
        // Mem cleanup every 30 minutes
235
        $discord->loop->addPeriodicTimer(1800, function() use ($logger) {
236
            $logger->addInfo('Memory in use: ' . memory_get_usage() / 1024 / 1024 . 'MB');
237
            gc_collect_cycles(); // Collect garbage
238
            $logger->addInfo('Memory in use after garbage collection: ' . memory_get_usage() / 1024 / 1024 . 'MB');
239
        });
240
241
        $discord->on(
242
            Event::MESSAGE_CREATE,
243
            function($message) use ($logger, $config, $plugins) {
244
245
                $msgData = array(
246
                    'message' => array(
247
                        'timestamp' => @$message->timestamp,
248
                        'id' => @$message->id,
249
                        'message' => @$message->content,
250
                        'channelID' => @$message->channel_id,
251
                        'from' => @$message->author->username,
252
                        'fromID' => @$message->author->id,
253
                        'fromDiscriminator' => @$message->author->discriminator,
254
                        'fromAvatar' => @$message->author->avatar
255
                    )
256
                );
257
258
                if ($message->content == '(╯°□°)╯︵ ┻━┻') {
259
                    $message->reply('┬─┬ ノ( ゜-゜ノ)');
260
                }
261
262
                // Check for plugins
263
                if (isset($message->content[0])) {
264
                    if ($message->content[0] == $config['bot']['trigger']) {
265
                        foreach ($plugins as $plugin) {
266
                            try {
267
                                $plugin->onMessage($msgData, $message);
268
                            } catch (Exception $e) {
269
                                $logger->addError('Error: ' . $e->getMessage());
270
                            }
271
                        }
272
                    }
273
                }
274
            }
275
        );
276
    }
277
);
278
$discord->on(
279
    'error',
280
    function($error) use ($logger) {
281
        $logger->addError($error);
282
        exit(1);
283
    }
284
);
285
$discord->on(
286
    'reconnecting',
287
    function() use ($logger) {
288
        $logger->addInfo('Websocket is reconnecting..');
289
    });
290
$discord->on(
291
    'reconnected',
292
    function() use ($logger) {
293
        $logger->addInfo('Websocket was reconnected..');
294
    });
295
// Now we will run the ReactPHP Event Loop!
296
$discord->run();
297
298