nopolabs/yabot

View on GitHub
src/Yabot.php

Summary

Maintainability
A
45 mins
Test Coverage
<?php
 
namespace Nopolabs\Yabot;
 
use DateTime;
use Exception;
use Nopolabs\Yabot\Helpers\ConfigTrait;
use Nopolabs\Yabot\Helpers\LogTrait;
use Nopolabs\Yabot\Helpers\LoopTrait;
use Nopolabs\Yabot\Helpers\SlackTrait;
use Nopolabs\Yabot\Message\MessageFactory;
Possibly zero references to use statement for classlike/namespace `PluginInterface` `(\Nopolabs\Yabot\Plugin\PluginInterface)`
use Nopolabs\Yabot\Plugin\PluginInterface;
use Nopolabs\Yabot\Plugin\PluginManager;
use Nopolabs\Yabot\Slack\Client;
use Psr\Log\LoggerInterface;
use React\EventLoop\LoopInterface;
use React\EventLoop\Timer\TimerInterface;
use React\Promise\Timer;
use Slack\Payload;
use Slack\User;
use Throwable;
 
class Yabot
{
use LogTrait;
use LoopTrait;
use SlackTrait;
use ConfigTrait;
 
/** @var MessageFactory */
private $messageFactory;
 
/** @var PluginManager */
private $pluginManager;
 
/** @var string */
private $messageLog;
 
/** @var TimerInterface */
Property `\Nopolabs\Yabot\Yabot->monitor` has undeclared type `\React\EventLoop\Timer\TimerInterface`
private $monitor;
 
/** @var bool */
private $pong;
 
Parameter `$eventLoop` has undeclared type `\React\EventLoop\LoopInterface`
Parameter `$logger` has undeclared type `\Psr\Log\LoggerInterface`
public function __construct(
Method `__construct` has 6 arguments (exceeds 4 allowed). Consider refactoring.
LoggerInterface $logger,
LoopInterface $eventLoop,
Client $slackClient,
MessageFactory $messageFactory,
PluginManager $pluginManager,
array $config = []
) {
$this->setLog($logger);
$this->setLoop($eventLoop);
$this->setSlack($slackClient);
$this->setConfig($config);
$this->messageFactory = $messageFactory;
$this->pluginManager = $pluginManager;
Assigning `null` to property but `\Nopolabs\Yabot\Yabot->messageLog` is `string`
$this->messageLog = null;
}
 
public function getMessageLog()
{
return $this->messageLog;
}
 
public function setMessageLog(string $messageLog = null)
{
Assigning `?string|null` to property but `\Nopolabs\Yabot\Yabot->messageLog` is `string`
$this->messageLog = $messageLog ?? null;
}
 
public function init(array $plugins)
{
foreach ($plugins as $pluginId => $plugin) {
/** @var PluginInterface $plugin */
 
$this->info("loading $pluginId");
 
try {
$this->pluginManager->loadPlugin($pluginId, $plugin);
} catch (Exception $e) {
$this->warning("Unhandled Exception while loading $pluginId: ".$e->getMessage());
$this->warning($e->getTraceAsString());
}
}
}
 
public function run()
{
$this->getSlack()->init();
 
Call to method `info` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->info('Connecting...');
 
$this->connect();
 
$this->addMemoryReporting();
 
Call to method `run` from undeclared class `\React\EventLoop\LoopInterface`
$this->getLoop()->run();
}
 
public function shutDown()
{
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('Shutting down...');
 
$this->getSlack()->disconnect();
Call to method `stop` from undeclared class `\React\EventLoop\LoopInterface`
$this->getLoop()->stop();
}
 
public function reconnect()
{
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('Reconnecting...');
 
if ($this->monitor) {
Call to method `cancelTimer` from undeclared class `\React\EventLoop\LoopInterface`
$this->loop->cancelTimer($this->monitor);
}
 
Call to method `then` from undeclared class `\React\Promise\PromiseInterface`
$this->getSlack()->reconnect()->then(
function () {
Call to method `info` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->info('Reconnected');
$this->monitor = $this->startConnectionMonitor();
},
function () {
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('Reconnect failed, shutting down.');
$this->shutDown();
}
);
}
 
public function connected()
{
$slack = $this->getSlack();
 
Parameter `$authedUser` has undeclared type `\Slack\User`
Expected 1 space after FUNCTION keyword; 0 found
$slack->update(function(User $authedUser) {
$this->pluginManager->setAuthedUser($authedUser);
});
 
$slack->onEvent('message', [$this, 'onMessage']);
$slack->onEvent('team_join', [$this, 'onTeamJoin']);
 
$this->monitor = $this->startConnectionMonitor();
}
 
Parameter `$payload` has undeclared type `\Slack\Payload`
public function onMessage(Payload $payload)
{
Call to method `getData` from undeclared class `\Slack\Payload`
$data = $payload->getData();
 
$this->debug('Received message', $data);
 
try {
$this->logMessage($data);
$message = $this->messageFactory->create($data);
} catch (Throwable $throwable) {
$errmsg = $throwable->getMessage()."\n"
.$throwable->getTraceAsString()."\n"
."Payload data: ".json_encode($data);
$this->warning($errmsg);
return;
}
 
if ($message->isSelf()) {
return;
}
 
$this->pluginManager->dispatchMessage($message);
}
 
Avoid unused parameters such as '$payload'.
Parameter `$payload` has undeclared type `\Slack\Payload`
public function onTeamJoin(Payload $payload)
{
$this->getSlack()->updateUsers();
}
 
public function getHelp() : string
{
return implode("\n", $this->pluginManager->getHelp());
}
 
public function getStatus() : string
{
$statuses = $this->pluginManager->getStatuses();
 
array_unshift($statuses, $this->getFormattedMemoryUsage());
 
return implode("\n", $statuses);
}
 
protected function addMemoryReporting()
{
$now = new DateTime();
$then = new DateTime('+1 hour');
Argument 1 `(hour)` is `string` but `\DateTime::setTime()` takes `int`
$then->setTime($then->format('H'), 0, 0);
$delay = $then->getTimestamp() - $now->getTimestamp();
 
Expected 1 space after FUNCTION keyword; 0 found
$this->addTimer($delay, function() {
$this->info($this->getFormattedMemoryUsage());
Expected 1 space after FUNCTION keyword; 0 found
$this->addPeriodicTimer(3600, function() {
$this->info($this->getFormattedMemoryUsage());
});
});
}
 
protected function getFormattedMemoryUsage() : string
{
$memory = memory_get_usage() / 1024;
$formatted = number_format($memory, 3).'K';
return "Current memory usage: {$formatted}";
}
 
protected function logMessage($data)
{
if ($this->messageLog !== null) {
file_put_contents($this->messageLog, json_encode($data) . "\n", FILE_APPEND);
}
}
 
/**
* @return TimerInterface|null
*/
Avoid assigning values to variables in if clauses and the like (line '220', column '13').
Return type of `startConnectionMonitor()` is undeclared type `\React\EventLoop\Timer\TimerInterface`
protected function startConnectionMonitor()
{
Blank line found at start of control structure
if ($interval = $this->get('connection_monitor.interval')) {
 
Call to method `info` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->info("Monitoring websocket connection every $interval seconds.");
$this->notify("Monitoring websocket connection every $interval seconds.");
 
$this->ping();
 
Call to method `addPeriodicTimer` from undeclared class `\React\EventLoop\LoopInterface`
return $this->loop->addPeriodicTimer($interval, function () {
$this->checkPong();
$this->ping();
});
}
}
 
protected function checkPong()
{
if (!$this->pong) {
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('No pong.');
 
$failureStrategy = $this->get('connection_monitor.failure_strategy', 'reconnect');
 
if ($failureStrategy === 'reconnect') {
$this->reconnect();
return;
}
 
if ($failureStrategy !== 'shutdown') {
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error("Unknown connection_monitor.failure_strategy '$failureStrategy'");
}
 
$this->shutDown();
}
}
 
protected function ping()
{
$this->pong = false;
 
Call to method `then` from undeclared class `\React\Promise\PromiseInterface`
$this->getSlack()->ping()
->then(
Parameter `$payload` has undeclared type `\Slack\Payload`
function (Payload $payload) {
Call to method `toJson` from undeclared class `\Slack\Payload`
Call to method `info` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->info($payload->toJson());
$this->pong = true;
}
);
}
 
Avoid assigning values to variables in if clauses and the like (line '269', column '13').
protected function notify(string $message)
{
if ($user = $this->get('notify.user')) {
$this->getSlack()->directMessage($message, $user);
}
}
 
protected function connect()
{
Call to undeclared function `\React\Promise\Timer\timeout()`
Timer\timeout($this->getSlack()->connect(), 30, $this->getLoop())
->then(function () {
Call to method `info` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->info('Connected.');
$this->connected();
})
Parameter `$error` has undeclared type `\React\Promise\Timer\timeoutexception`
->otherwise(function (Timer\TimeoutException $error) {
Call to method `getMessage` from undeclared class `\React\Promise\Timer\timeoutexception`
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error($error->getMessage());
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('Connection failed, shutting down.');
$this->shutDown();
})
->otherwise(function ($error) {
Call to method `error` from undeclared class `\Psr\Log\LoggerInterface`
$this->getLog()->error('Connection failed, shutting down.');
$this->shutDown();
});
}
}