diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9cfd660138..ef248e6d62 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -707,6 +707,7 @@ phutil_register_library_map(array( 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php', 'PhabricatorBaseProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBaseProtocolAdapter.php', 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', + 'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', 'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', 'PhabricatorBotDifferentialNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDifferentialNotificationHandler.php', 'PhabricatorBotFeedNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotFeedNotificationHandler.php', @@ -716,6 +717,8 @@ phutil_register_library_map(array( 'PhabricatorBotMessage' => 'infrastructure/daemon/bot/PhabricatorBotMessage.php', 'PhabricatorBotObjectNameHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php', 'PhabricatorBotSymbolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotSymbolHandler.php', + 'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php', + 'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php', 'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorButtonsExample' => 'applications/uiexample/examples/PhabricatorButtonsExample.php', @@ -2163,6 +2166,7 @@ phutil_register_library_map(array( 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation', 'PhabricatorBot' => 'PhabricatorDaemon', + 'PhabricatorBotChannel' => 'PhabricatorBotTarget', 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotDifferentialNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler', @@ -2170,6 +2174,7 @@ phutil_register_library_map(array( 'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler', 'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler', 'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler', + 'PhabricatorBotUser' => 'PhabricatorBotTarget', 'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorButtonsExample' => 'PhabricatorUIExample', diff --git a/src/infrastructure/daemon/bot/PhabricatorBotMessage.php b/src/infrastructure/daemon/bot/PhabricatorBotMessage.php index c3c03748f1..27f0c17dbb 100644 --- a/src/infrastructure/daemon/bot/PhabricatorBotMessage.php +++ b/src/infrastructure/daemon/bot/PhabricatorBotMessage.php @@ -13,7 +13,7 @@ final class PhabricatorBotMessage { $this->public = true; } - public function setSender($sender) { + public function setSender(PhabricatorBotTarget $sender = null) { $this->sender = $sender; return $this; } @@ -40,7 +40,7 @@ final class PhabricatorBotMessage { return $this->body; } - public function setTarget($target) { + public function setTarget(PhabricatorBotTarget $target = null) { $this->target = $target; return $this; } @@ -49,20 +49,4 @@ final class PhabricatorBotMessage { return $this->target; } - public function isPublic() { - return $this->public; - } - - public function setPublic($is_public) { - $this->public = $is_public; - return $this; - } - - public function getReplyTo() { - if ($this->public) { - return $this->target; - } else { - return $this->sender; - } - } } diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php index b567a42d1f..4e78f40380 100644 --- a/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php @@ -115,11 +115,34 @@ final class PhabricatorCampfireProtocolAdapter $buffer = substr($buffer, $until + 2); $m_obj = json_decode($message, true); + $command = null; + switch ($m_obj['type']) { + case 'TextMessage': + $command = 'MESSAGE'; + break; + case 'PasteMessage': + $command = 'PASTE'; + break; + default: + // For now, ignore anything which we don't otherwise know about. + break; + } + + if ($command === null) { + continue; + } + + // TODO: These should be usernames, not user IDs. + $sender = id(new PhabricatorBotUser()) + ->setName($m_obj['user_id']); + + $target = id(new PhabricatorBotChannel()) + ->setName($m_obj['room_id']); return id(new PhabricatorBotMessage()) - ->setCommand('MESSAGE') - ->setSender($m_obj['user_id']) - ->setTarget($m_obj['room_id']) + ->setCommand($command) + ->setSender($sender) + ->setTarget($target) ->setBody($m_obj['body']); } @@ -159,7 +182,13 @@ final class PhabricatorCampfireProtocolAdapter unset($this->inRooms[$room_id]); } - private function speak($message, $room_id, $type='TextMessage') { + private function speak( + $message, + PhabricatorBotTarget $channel, + $type = 'TextMessage') { + + $room_id = $channel->getName(); + $this->performPost( "/room/{$room_id}/speak.json", array( diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php index 2d799ed4cd..970917d40e 100644 --- a/src/infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php @@ -128,7 +128,7 @@ final class PhabricatorIRCProtocolAdapter switch ($message->getCommand()) { case 'MESSAGE': $data = $irc_command.' '. - $message->getTarget().' :'. + $message->getTarget()->getName().' :'. $message->getBody()."\r\n"; break; default: @@ -164,16 +164,19 @@ final class PhabricatorIRCProtocolAdapter $command = $this->getBotCommand($matches['command']); list($target, $body) = $this->parseMessageData($command, $matches['data']); + if (!strlen($matches['sender'])) { + $sender = null; + } else { + $sender = id(new PhabricatorBotUser()) + ->setName($matches['sender']); + } + $bot_message = id(new PhabricatorBotMessage()) - ->setSender(idx($matches, 'sender')) + ->setSender($sender) ->setCommand($command) ->setTarget($target) ->setBody($body); - if (!empty($target) && strncmp($target, '#', 1) !== 0) { - $bot_message->setPublic(false); - } - return $bot_message; } @@ -201,8 +204,18 @@ final class PhabricatorIRCProtocolAdapter case 'MESSAGE': $matches = null; if (preg_match('/^(\S+)\s+:?(.*)$/', $data, $matches)) { + + $target_name = $matches[1]; + if (strncmp($target_name, '#', 1) === 0) { + $target = id(new PhabricatorBotChannel()) + ->setName($target_name); + } else { + $target = id(new PhabricatorBotUser()) + ->setName($target_name); + } + return array( - $matches[1], + $target, rtrim($matches[2], "\r\n")); } break; diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotHandler.php index 025cc51a1e..a2543b319c 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotHandler.php @@ -48,15 +48,14 @@ abstract class PhabricatorBotHandler { $reply = id(new PhabricatorBotMessage()) ->setCommand('MESSAGE'); - if ($original_message->isPublic()) { + if ($original_message->getTarget()->isPublic()) { // This is a public target, like a chatroom. Send the response to the // chatroom. $reply->setTarget($original_message->getTarget()); } else { // This is a private target, like a private message. Send the response // back to the sender (presumably, we are the target). - $reply->setTarget($original_message->getSender()) - ->setPublic(false); + $reply->setTarget($original_message->getSender()); } $reply->setBody($body); diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php index bc2962365e..f852efefb7 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php @@ -13,21 +13,20 @@ final class PhabricatorBotLogHandler extends PhabricatorBotHandler { switch ($message->getCommand()) { case 'MESSAGE': - $reply_to = $message->getReplyTo(); - if (!$reply_to) { - break; - } - if (!$message->isPublic()) { + $target = $message->getTarget(); + if (!$target->isPublic()) { // Don't log private messages, although maybe we should for debugging? break; } + $target_name = $target->getName(); + $logs = array( array( - 'channel' => $reply_to, + 'channel' => $target_name, 'type' => 'mesg', 'epoch' => time(), - 'author' => $message->getSender(), + 'author' => $message->getSender()->getName(), 'message' => $message->getBody(), ), ); @@ -54,7 +53,7 @@ final class PhabricatorBotLogHandler extends PhabricatorBotHandler { if ($tell) { $response = $this->getURI( - '/chatlog/channel/'.phutil_escape_uri($reply_to).'/'); + '/chatlog/channel/'.phutil_escape_uri($target_name).'/'); $this->replyTo($message, $response); } diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php index daa92424a0..9b02e2965c 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php @@ -8,7 +8,6 @@ final class PhabricatorBotMacroHandler extends PhabricatorBotHandler { private $macros; private $regexp; - private $buffer = array(); private $next = 0; private function init() { @@ -46,66 +45,37 @@ final class PhabricatorBotMacroHandler extends PhabricatorBotHandler { } switch ($message->getCommand()) { - case 'MESSAGE': - $reply_to = $message->getReplyTo(); - if (!$reply_to) { + case 'MESSAGE': + $message_body = $message->getBody(); + + $matches = null; + if (!preg_match($this->regexp, $message_body, $matches)) { + return; + } + + $macro = $matches[1]; + + $ascii = idx($this->macros[$macro], 'ascii'); + if ($ascii === false) { + return; + } + + if (!$ascii) { + $this->macros[$macro]['ascii'] = $this->rasterize( + $this->macros[$macro], + $this->getConfig('macro.size', 48), + $this->getConfig('macro.aspect', 0.66)); + $ascii = $this->macros[$macro]['ascii']; + } + + $target_name = $message->getTarget()->getName(); + foreach ($ascii as $line) { + $this->replyTo($message, $line); + } break; - } - - $message_body = $message->getBody(); - - $matches = null; - if (!preg_match($this->regexp, $message_body, $matches)) { - return; - } - - $macro = $matches[1]; - - $ascii = idx($this->macros[$macro], 'ascii'); - if ($ascii === false) { - return; - } - - if (!$ascii) { - $this->macros[$macro]['ascii'] = $this->rasterize( - $this->macros[$macro], - $this->getConfig('macro.size', 48), - $this->getConfig('macro.aspect', 0.66)); - $ascii = $this->macros[$macro]['ascii']; - } - - foreach ($ascii as $line) { - $this->buffer[$reply_to][] = $line; - } - break; } } - public function runBackgroundTasks() { - if (microtime(true) < $this->next) { - return; - } - - foreach ($this->buffer as $channel => $lines) { - if (empty($lines)) { - unset($this->buffer[$channel]); - continue; - } - foreach ($lines as $key => $line) { - $this->writeMessage( - id(new PhabricatorBotMessage()) - ->setCommand('MESSAGE') - ->setTarget($channel) - ->setBody($line)); - unset($this->buffer[$channel][$key]); - break 2; - } - } - - $sleep = $this->getConfig('macro.sleep', 0.25); - $this->next = microtime(true) + ((mt_rand(75, 150) / 100) * $sleep); - } - public function rasterize($macro, $size, $aspect) { $image = HTTPSFuture::loadContent($macro['uri']); if (!$image) { diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php index 5a6ff48ad9..34dbf50b55 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php @@ -170,13 +170,13 @@ final class PhabricatorBotObjectNameHandler extends PhabricatorBotHandler { // in public channels, so we avoid spamming the chat over and over // again for discsussions of a specific revision, for example. - $reply_to = $original_message->getReplyTo(); - if (empty($this->recentlyMentioned[$reply_to])) { - $this->recentlyMentioned[$reply_to] = array(); + $target_name = $original_message->getTarget()->getName(); + if (empty($this->recentlyMentioned[$target_name])) { + $this->recentlyMentioned[$target_name] = array(); } $quiet_until = idx( - $this->recentlyMentioned[$reply_to], + $this->recentlyMentioned[$target_name], $phid, 0) + (60 * 10); @@ -185,7 +185,7 @@ final class PhabricatorBotObjectNameHandler extends PhabricatorBotHandler { continue; } - $this->recentlyMentioned[$reply_to][$phid] = time(); + $this->recentlyMentioned[$target_name][$phid] = time(); $this->replyTo($original_message, $description); } break; diff --git a/src/infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php b/src/infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php index 15fc2ecb85..c2c593f024 100644 --- a/src/infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php +++ b/src/infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php @@ -13,11 +13,6 @@ final class PhabricatorBotWhatsNewHandler extends PhabricatorBotHandler { switch ($message->getCommand()) { case 'MESSAGE': - $reply_to = $message->getReplyTo(); - if (!$reply_to) { - break; - } - $message_body = $message->getBody(); $prompt = '~what( i|\')?s new\?~i'; @@ -27,17 +22,17 @@ final class PhabricatorBotWhatsNewHandler extends PhabricatorBotHandler { } $this->floodblock = time() + 60; - $this->getLatest($reply_to); + $this->getLatest($message); } break; } } - public function getLatest($reply_to) { + public function getLatest(PhabricatorBotMessage $message) { $latest = $this->getConduit()->callMethodSynchronous( 'feed.query', array( - 'limit'=>5 + 'limit' => 5 )); $phids = array(); @@ -112,11 +107,7 @@ final class PhabricatorBotWhatsNewHandler extends PhabricatorBotHandler { // $content = "{$bold}{$user}{$reset} {$gray}{$action} {$blue}{$bold}". // "{$title}{$reset} - {$gray}{$uri}{$reset}"; $content = "{$user} {$action} {$title} - {$uri}"; - $this->writeMessage( - id(new PhabricatorBotMessage()) - ->setCommand('MESSAGE') - ->setTarget($reply_to) - ->setBody($content)); + $this->replyTo($message, $content); } return; } diff --git a/src/infrastructure/daemon/bot/target/PhabricatorBotChannel.php b/src/infrastructure/daemon/bot/target/PhabricatorBotChannel.php new file mode 100644 index 0000000000..030df925b6 --- /dev/null +++ b/src/infrastructure/daemon/bot/target/PhabricatorBotChannel.php @@ -0,0 +1,12 @@ +name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + abstract public function isPublic(); + +} diff --git a/src/infrastructure/daemon/bot/target/PhabricatorBotUser.php b/src/infrastructure/daemon/bot/target/PhabricatorBotUser.php new file mode 100644 index 0000000000..1bc0c82219 --- /dev/null +++ b/src/infrastructure/daemon/bot/target/PhabricatorBotUser.php @@ -0,0 +1,12 @@ +