<?php
namespace App\TwitchBot;
-use Illuminate\Support\Facades\Http;
+
+use App\Models\Channel;
+use App\Models\TwitchToken;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Ratchet\Client\Connector;
public function __construct() {
$this->logger = new Logger('TwitchBot');
- $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::INFO));
+ $this->logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));
- $this->fetchToken();
+ $this->token = TwitchToken::firstWhere('nick', 'localhorsttv');
+ if (!$this->token) {
+ throw new \Exception('unable to find access token');
+ }
$this->connector = new Connector();
$this->connect();
}
public function run() {
+ $this->shutting_down = false;
$this->getLoop()->run();
}
public function stop() {
+ $this->logger->info('shutting down');
+ $this->shutting_down = true;
$this->disconnect();
$this->getLoop()->stop();
}
- public function fetchToken() {
- $this->logger->info('acquiring token');
- $rsp = Http::post('https://id.twitch.tv/oauth2/token', [
- 'client_id' => config('twitch.client_id'),
- 'client_secret' => config('twitch.client_secret'),
- 'code' => config('twitch.code'),
- 'grant_type' => 'authorization_code',
- 'redirect_uri' => config('twitch.redirect_uri'),
- ]);
- var_dump($rsp);
- var_dump($rsp->body());
- $this->token = $rsp->json();
- }
-
-
public function connect() {
($this->connector)('wss://irc-ws.chat.twitch.tv:443')->done(
[$this, 'handleWsConnect'],
}
public function handleWsConnect(WebSocket $ws) {
- $this->logger->info('websocket connection estblished');
+ $this->logger->info('websocket connection established');
$this->ws = $ws;
- $ws->on('message', [$this, 'handleWsMessage']);
- $ws->on('close', [$this, 'handleWsClose']);
- $ws->on('error', [$this, 'handleWsError']);
+ $ws->on('message', [$this, 'handleWsMessage']);
+ $ws->on('close', [$this, 'handleWsClose']);
+ $ws->on('error', [$this, 'handleWsError']);
$ws->send('CAP REQ :twitch.tv/tags twitch.tv/commands');
- $ws->send('PASS oauth:'.$this->token->access_token);
- $ws->send('NICK localhorsttv');
+ $this->login();
}
public function handleWsConnectError(WebSocket $ws) {
}
public function handleWsMessage(Message $message, WebSocket $ws) {
- $this->logger->info('websocket message received');
- var_dump($message->getPayload());
+ $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->handleIRCMessage(IRCMessage::fromString($irc_message));
+ }
}
- public function handleWsClose(int $op, string $reason) {
+ public function handleWsClose(int $op, string $reason) {
$this->logger->info('websocket connection closed: '.$reason.' ['.$op.']');
+ if (!$this->shutting_down) {
+ $this->logger->info('reconnecting in 10 seconds');
+ Loop::addTimer(10, [$this, 'connect']);
+ }
}
- public function handleWsError(\Exception $e, WebSocket $ws) {
+ public function handleWsError(\Exception $e, WebSocket $ws) {
$this->logger->error('websocket error '.$e->getMessage());
}
+ public function handleIRCMessage(IRCMessage $msg) {
+ if ($msg->isPrivMsg()) {
+ $this->handlePrivMsg($msg);
+ return;
+ }
+ if ($msg->isPing()) {
+ $this->sendIRCMessage($msg->makePong());
+ return;
+ }
+ if ($msg->isNotice() && $msg->getText() == 'Login authentication failed') {
+ $this->logger->notice('login failed, refreshing access token');
+ $this->token->refresh();
+ $this->login();
+ return;
+ }
+ if ($msg->command == '001') {
+ // successful login
+ $this->joinChannels();
+ return;
+ }
+ }
+
+ public function handlePrivMsg(IRCMessage $msg) {
+ $target = $msg->getPrivMsgTarget();
+ if ($target[0] != '#') return;
+ $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);
+ }
+
+ public function login() {
+ $this->ws->send('PASS oauth:'.$this->token->access);
+ $this->ws->send('NICK localhorsttv');
+ }
+
+ public function joinChannels() {
+ $this->logger->info('joining channels');
+ $channels = Channel::where('twitch_chat', '!=', '')->get();
+ $names = [];
+ foreach ($channels as $channel) {
+ $names[] = $channel->twitch_chat;
+ }
+ $chunks = array_chunk($names, 10);
+ foreach ($chunks as $chunk) {
+ $this->sendIRCMessage(IRCMessage::join($chunk));
+ }
+ }
+
+ public function sendIRCMessage(IRCMessage $msg) {
+ $irc_message = $msg->encode();
+ $this->logger->debug('sending IRC message '.$irc_message);
+ $this->ws->send($irc_message);
+ }
+
+
private $logger;
- private $loop;
private $token;
private $connector;
private $ws;
+ private $shutting_down = false;
}