namespace App\TwitchBot;
use App\Models\Channel;
+use App\Models\TwitchBotCommand;
use App\Models\TwitchToken;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
public function __construct() {
$this->logger = new Logger('TwitchBot');
- $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));
+ $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::INFO));
$this->token = TwitchToken::firstWhere('nick', 'localhorsttv');
if (!$this->token) {
$this->connector = new Connector();
$this->connect();
+ $this->listenCommands();
+ $this->startPinger();
}
public function getLogger() {
public function handleWsMessage(Message $message, WebSocket $ws) {
$irc_messages = explode("\r\n", rtrim($message->getPayload(), "\r\n"));
foreach ($irc_messages as $irc_message) {
- $this->logger->debug('received IRC message '.$irc_message);
+ $this->logger->info('received IRC message '.$irc_message);
$this->handleIRCMessage(IRCMessage::fromString($irc_message));
}
}
public function handleWsClose(int $op, string $reason) {
+ $this->ready = false;
$this->logger->info('websocket connection closed: '.$reason.' ['.$op.']');
if (!$this->shutting_down) {
- $this->logger->info('reconnecting in 10 seconds');
- Loop::addTimer(10, [$this, 'connect']);
+ $this->logger->info('reconnecting in 5 seconds');
+ Loop::addTimer(5, [$this, 'connect']);
}
}
public function handleIRCMessage(IRCMessage $msg) {
- if ($msg->isPrivMsg()) {
- $this->handlePrivMsg($msg);
- return;
- }
+ $this->last_contact = time();
if ($msg->isPing()) {
$this->sendIRCMessage($msg->makePong());
return;
}
+ if ($msg->isPong()) {
+ return;
+ }
+ $msg->log();
+ if ($msg->isPrivMsg()) {
+ $this->handlePrivMsg($msg);
+ return;
+ }
if ($msg->isNotice() && $msg->getText() == 'Login authentication failed') {
$this->logger->notice('login failed, refreshing access token');
$this->token->refresh();
if ($msg->command == '001') {
// successful login
$this->joinChannels();
+ $this->ready = true;
return;
}
}
public function handlePrivMsg(IRCMessage $msg) {
$target = $msg->getPrivMsgTarget();
- if ($target[0] != '#') return;
+ if ($target[0] != '#') return; // direct message
$text = $msg->getText();
if ($text[0] != '!') return;
$channel = Channel::firstWhere('twitch_chat', '=', $target);
if (!$channel) return;
- $this->logger->info('got command '.$text.' on channel '.$channel->title);
+ $this->handleChatCommand($channel, $msg);
+ }
+
+ public function handleChatCommand(Channel $channel, IRCMessage $msg) {
+ $cmd = explode(' ', ltrim($msg->getText(), '!'), 2);
+ if (!isset($channel->chat_commands[$cmd[0]])) return;
+ $config = $channel->chat_commands[$cmd[0]];
+ $this->logger->info('got command '.$cmd[0].' on channel '.$channel->title);
+ try {
+ $command = ChatCommand::create($this, $channel, $config);
+ $command->execute($cmd[1] ?? '');
+ } catch (\Exception $e) {
+ $this->logger->warning('error executing command '.$cmd[0].' on channel '.$channel->title.': '.$e->getMessage());
+ }
}
public function login() {
public function joinChannels() {
$this->logger->info('joining channels');
- $channels = Channel::where('twitch_chat', '!=', '')->get();
+ $channels = Channel::where('twitch_chat', '!=', '')->where('join', '=', true)->get();
$names = [];
foreach ($channels as $channel) {
$names[] = $channel->twitch_chat;
}
}
+ private function listenCommands() {
+ $this->getLoop()->addPeriodicTimer(1, function () {
+ if (!$this->ready) return;
+ $command = TwitchBotCommand::where('status', '=', 'pending')->oldest()->first();
+ if ($command) {
+ try {
+ $command->execute($this);
+ } catch (\Exception $e) {
+ }
+ }
+ });
+ }
+
+ private function startPinger() {
+ $this->getLoop()->addPeriodicTimer(15, function () {
+ if (!$this->ready) return;
+ if (time() - $this->last_contact < 60) return;
+ try {
+ $this->sendIRCMessage(IRCMessage::ping());
+ } catch (\Exception $e) {
+ }
+ });
+ }
+
public function sendIRCMessage(IRCMessage $msg) {
$irc_message = $msg->encode();
- $this->logger->debug('sending IRC message '.$irc_message);
+ $this->logger->info('sending IRC message '.$irc_message);
$this->ws->send($irc_message);
+ $this->last_contact = time();
}
private $connector;
private $ws;
+ private $ready = false;
private $shutting_down = false;
+ private $last_contact;
+
}
?>