Passed
Branch dev (68bed2)
by
unknown
02:25
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
foreach ($pluginDirs as $dir) {
83
    foreach (glob($dir) as $plugin) {
84
        // Only load the plugins we want to load, according to the config
85
        if (!in_array(str_replace('.php', '', basename($plugin)), $config['enabledPlugins'])) {
86
            continue;
87
        }
88
89
        /** @noinspection PhpIncludeInspection */
90
        require_once $plugin;
91
        $fileName = str_replace('.php', '', basename($plugin));
92
        $p = new $fileName();
93
        $p->init($config, $discord, $logger);
94
        $pluginsT[] = $p;
95
    }
96
}
97
// Number of plugins loaded
98
$logger->info('Loaded: ' . count($pluginsT) . ' background plugins');
99
100
if ($config['bot']['silentMode'] == 'false' || !isset($config['bot']['silentMode'])) {
101
// Load chat plugins
102
    $pluginDirs = array('src/plugins/onMessage/*.php', 'src/plugins/admin/*.php');
103
    $adminPlugins = array('setNickname', 'getLog', 'setGame');
104
    $logger->addInfo('Loading in chat plugins');
105
    $plugins = array();
106
    foreach ($pluginDirs as $dir) {
107
        foreach (glob($dir) as $plugin) {
108
            // Only load the plugins we want to load, according to the config
109
            if (!in_array(str_replace('.php', '', basename($plugin)), $config['enabledPlugins']) && !in_array(str_replace('.php', '', basename($plugin)), $adminPlugins)) {
110
                continue;
111
            }
112
113
            /** @noinspection PhpIncludeInspection */
114
            require_once $plugin;
115
            $fileName = str_replace('.php', '', basename($plugin));
116
            $p = new $fileName();
117
            $p->init($config, $discord, $logger);
118
            $plugins[] = $p;
119
        }
120
    }
121
122
// Number of chat plugins loaded
123
    $logger->addInfo('Loaded: ' . count($plugins) . ' chat plugins');
124
}
125
126
// Clear queue at restart if it's too high
127
clearQueueCheck();
128
129
//Check initial server state (tick plugins will not run if eve is offline)
130
$crestData = json_decode(downloadData('https://crest-tq.eveonline.com/'), true);
131
$crestStatus = isset($crestData['serviceStatus']) ? $crestData['serviceStatus'] : 'offline';
132
setPermCache('serverState', $crestStatus);
133
setPermCache('statusLastState', $crestStatus);
134
$logger->addInfo("serverState: EVE is currently {$crestStatus}");
135
136
//Clean up any outdated databases
137
dbPrune();
138
139
$discord->on(
140
    'ready',
141
    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...
142
        // In here we can access any of the WebSocket events.
143
        //
144
        // There is a list of event constants that you can
145
        // find here: https://teamreflex.github.io/DiscordPHP/classes/Discord.WebSockets.Event.html
146
        //
147
        // We will echo to the console that the WebSocket is ready.
148
        $logger->addInfo('Discord WebSocket is ready!' . PHP_EOL);
149
150
        //Clear queue if it's super backed up
151
152
153
        //Set Initial Game
154
        $gameTitle = $config['bot']['game'];
155
        if (null !== getPermCache('botGame')) {
156
            $gameTitle = getPermCache('botGame');
157
        }
158
        $game = $discord->factory(Game::class, [
159
            'name' => $gameTitle,
160
        ]);
161
        $discord->updatePresence($game);
162
163
        // Server Status Check (tick plugins will not run if eve is offline)
164
        $discord->loop->addPeriodicTimer(60, function() use ($logger) {
165
            $crestData = json_decode(downloadData('https://crest-tq.eveonline.com/'), true);
166
            $crestStatus = isset($crestData['serviceStatus']) ? $crestData['serviceStatus'] : 'offline';
167
            setPermCache('serverState', $crestStatus);
168
        });
169
170
        // Run the Tick plugins
171
        $discord->loop->addPeriodicTimer(3, function() use ($pluginsT) {
172
            foreach ($pluginsT as $plugin) {
173
                $plugin->tick();
174
            }
175
        });
176
177
        // Message queue
178
        $discord->loop->addPeriodicTimer(7, function() use ($discord, $logger) {
179
            $x = 0;
180
            while ($x < 3) {
181
                $id = getOldestMessage();
0 ignored issues
show
Are you sure the assignment to $id is correct as getOldestMessage() seems to always returns null.
Loading history...
182
                $id = $id['MIN(id)'];
183
                if (null === $id) {
184
                    $id = 1;
185
                }
186
                $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...
187
                if (null !== $queuedMessage) {
188
                    //Check if queued item is corrupt and delete it if it is
189
                    if (null === $queuedMessage['guild'] || null === $queuedMessage['channel'] || null === $queuedMessage['message']) {
190
                        $logger->addInfo("QueueProcessing Error- Item #{$id} : Queued item is badly formed, removing it from the queue");
191
                        clearQueuedMessages($id);
192
                    }
193
                    $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...
194
                    $channel = $guild->channels->get('id', $queuedMessage['channel']);
195
                    //Check if channel is bad
196
                    if (null === $channel || null === $guild) {
197
                        $logger->addInfo("QueueProcessing Error- Item #{$id} : Channel provided is incorrect, removing it from the queue");
198
                        clearQueuedMessages($id);
199
                    }
200
                    $logger->addInfo("QueueProcessing - Completing queued item #{$id}");
201
                    $channel->sendMessage($queuedMessage['message'], false);
202
                    clearQueuedMessages($id);
203
                }
204
                $x++;
205
            }
206
        });
207
208
        // Rename queue
209
        $discord->loop->addPeriodicTimer(10, function() use ($discord, $logger) {
210
            $x = 0;
211
            while ($x < 4) {
212
                $id = getOldestRename();
0 ignored issues
show
Are you sure the assignment to $id is correct as getOldestRename() seems to always returns null.
Loading history...
213
                $id = $id['MIN(id)'];
214
                if (null === $id) {
215
                    $id = 1;
216
                    $x = 4;
217
                }
218
                $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...
219
                if (null !== $queuedRename) {
220
                    //Check if queued item is corrupt and delete it if it is
221
                    if (null === $queuedRename['guild'] || null === $queuedRename['discordID']) {
222
                        clearQueuedRename($id);
223
                    }
224
                    $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...
225
                    $member = $guild->members->get('id', $queuedRename['discordID']);
226
                    $member->setNickname($queuedRename['nick']);
227
                    clearQueuedRename($id);
228
                }
229
                $x++;
230
            }
231
        });
232
233
        // Mem cleanup every 30 minutes
234
        $discord->loop->addPeriodicTimer(1800, function() use ($logger) {
235
            $logger->addInfo('Memory in use: ' . memory_get_usage() / 1024 / 1024 . 'MB');
236
            gc_collect_cycles(); // Collect garbage
237
            $logger->addInfo('Memory in use after garbage collection: ' . memory_get_usage() / 1024 / 1024 . 'MB');
238
        });
239
240
        $discord->on(
241
            Event::MESSAGE_CREATE,
242
            function($message) use ($logger, $config, $plugins) {
243
244
                $msgData = array(
245
                    'message' => array(
246
                        'timestamp' => @$message->timestamp,
247
                        'id' => @$message->id,
248
                        'message' => @$message->content,
249
                        'channelID' => @$message->channel_id,
250
                        'from' => @$message->author->username,
251
                        'fromID' => @$message->author->id,
252
                        'fromDiscriminator' => @$message->author->discriminator,
253
                        'fromAvatar' => @$message->author->avatar
254
                    )
255
                );
256
257
                if ($message->content == '(╯°□°)╯︵ ┻━┻') {
258
                    $message->reply('┬─┬ ノ( ゜-゜ノ)');
259
                }
260
261
                // Check for plugins
262
                if (isset($message->content[0])) {
263
                    if ($message->content[0] == $config['bot']['trigger']) {
264
                        foreach ($plugins as $plugin) {
265
                            try {
266
                                $plugin->onMessage($msgData, $message);
267
                            } catch (Exception $e) {
268
                                $logger->addError('Error: ' . $e->getMessage());
269
                            }
270
                        }
271
                    }
272
                }
273
            }
274
        );
275
    }
276
);
277
$discord->on(
278
    'error',
279
    function($error) use ($logger) {
280
        $logger->addError($error);
281
        exit(1);
282
    }
283
);
284
$discord->on(
285
    'reconnecting',
286
    function() use ($logger) {
287
        $logger->addInfo('Websocket is reconnecting..');
288
    });
289
$discord->on(
290
    'reconnected',
291
    function() use ($logger) {
292
        $logger->addInfo('Websocket was reconnected..');
293
    });
294
// Now we will run the ReactPHP Event Loop!
295
$discord->run();
296
297