Permalink
Browse files

Bring macros to IRC

Summary:
Adds a macro handler that spams your channel with macros. Config is:

  - macro.size: scale macros to this size before rasterizing
  - macro.sleep: sleep this many seconds between lines (evade flood protection)

Test Plan: derpderp

Reviewers: kdeggelman, btrahan

Reviewed By: btrahan

CC: aran, epriestley

Differential Revision: https://secure.phabricator.com/D1838
  • Loading branch information...
epriestley committed Mar 9, 2012
1 parent 226d032 commit 6712dbb70966a922afb5ffeff2e9898476f58292
@@ -10,12 +10,17 @@
"PhabricatorIRCObjectNameHandler",
"PhabricatorIRCLogHandler",
"PhabricatorIRCWhatsNewHandler",
- "PhabricatorIRCDifferentialNotificationHandler"
+ "PhabricatorIRCDifferentialNotificationHandler",
+ "PhabricatorIRCMacroHandler"
],
"conduit.uri" : null,
"conduit.user" : null,
"conduit.cert" : null,
+ "macro.size" : 48,
+ "macro.sleep" : 0.25,
+ "macro.aspect" : 0.66,
+
"notification.channels" : ["#phabot-test"]
}
@@ -140,6 +140,8 @@
'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
'ConduitAPI_file_info_Method' => 'applications/conduit/method/file/info',
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
+ 'ConduitAPI_macro_Method' => 'applications/conduit/method/macro/base',
+ 'ConduitAPI_macro_query_Method' => 'applications/conduit/method/macro/query',
'ConduitAPI_maniphest_Method' => 'applications/conduit/method/maniphest/base',
'ConduitAPI_maniphest_createtask_Method' => 'applications/conduit/method/maniphest/createtask',
'ConduitAPI_maniphest_find_Method' => 'applications/conduit/method/maniphest/find',
@@ -581,6 +583,7 @@
'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/differentialnotification',
'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base',
'PhabricatorIRCLogHandler' => 'infrastructure/daemon/irc/handler/log',
+ 'PhabricatorIRCMacroHandler' => 'infrastructure/daemon/irc/handler/macro',
'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
@@ -1018,6 +1021,8 @@
'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_info_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
+ 'ConduitAPI_macro_Method' => 'ConduitAPIMethod',
+ 'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method',
'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod',
'ConduitAPI_maniphest_createtask_Method' => 'ConduitAPI_maniphest_Method',
'ConduitAPI_maniphest_find_Method' => 'ConduitAPI_maniphest_Method',
@@ -1359,6 +1364,7 @@
'PhabricatorIRCBot' => 'PhabricatorDaemon',
'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler',
+ 'PhabricatorIRCMacroHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCWhatsNewHandler' => 'PhabricatorIRCHandler',
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @group conduit
+ */
+abstract class ConduitAPI_macro_Method extends ConduitAPIMethod {
+
+
+}
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/conduit/method/base');
+
+
+phutil_require_source('ConduitAPI_macro_Method.php');
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @group conduit
+ */
+final class ConduitAPI_macro_query_Method extends ConduitAPI_macro_Method {
+
+ public function getMethodDescription() {
+ return "Retrieve image macro information.";
+ }
+
+ public function defineParamTypes() {
+ return array(
+ );
+ }
+
+ public function defineReturnType() {
+ return 'list<dict>';
+ }
+
+ public function defineErrorTypes() {
+ return array(
+ );
+ }
+
+ protected function execute(ConduitAPIRequest $request) {
+
+ $macros = id(new PhabricatorFileImageMacro())->loadAll();
+
+ $files = array();
+ if ($macros) {
+ $files = id(new PhabricatorFile())->loadAllWhere(
+ 'phid IN (%Ls)',
+ mpull($macros, 'getFilePHID'));
+ $files = mpull($files, null, 'getPHID');
+ }
+
+ $results = array();
+ foreach ($macros as $macro) {
+ if (empty($files[$macro->getFilePHID()])) {
+ continue;
+ }
+ $results[$macro->getName()] = array(
+ 'uri' => $files[$macro->getFilePHID()]->getBestURI(),
+ );
+ }
+
+ return $results;
+ }
+
+}
@@ -0,0 +1,16 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/conduit/method/macro/base');
+phutil_require_module('phabricator', 'applications/files/storage/file');
+phutil_require_module('phabricator', 'applications/files/storage/imagemacro');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('ConduitAPI_macro_query_Method.php');
@@ -0,0 +1,200 @@
+<?php
+
+/*
+ * Copyright 2012 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @group irc
+ */
+final class PhabricatorIRCMacroHandler extends PhabricatorIRCHandler {
+
+ private $macros;
+ private $regexp;
+
+ private $buffer = array();
+ private $next = 0;
+
+ private function init() {
+ if ($this->macros === false) {
+ return false;
+ }
+
+ if ($this->macros !== null) {
+ return true;
+ }
+
+ $macros = $this->getConduit()->callMethodSynchronous(
+ 'macro.query',
+ array());
+
+ $this->macros = $macros;
+
+ $regexp = array();
+ foreach ($this->macros as $macro_name => $macro) {
+ $regexp[] = preg_quote($macro_name, '/');
+ }
+ $regexp = '/('.implode('|', $regexp).')/';
+
+ $this->regexp = $regexp;
+
+ return true;
+ }
+
+ public function receiveMessage(PhabricatorIRCMessage $message) {
+ if (!$this->init()) {
+ return;
+ }
+
+ switch ($message->getCommand()) {
+ case 'PRIVMSG':
+ $reply_to = $message->getReplyTo();
+ if (!$reply_to) {
+ break;
+ }
+
+ $message = $message->getMessageText();
+
+ $matches = null;
+ if (!preg_match($this->regexp, $message, $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->write('PRIVMSG', "{$channel} :{$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 = @file_get_contents($macro['uri']);
+ if (!$image) {
+ return false;
+ }
+
+ $img = @imagecreatefromstring($image);
+ if (!$img) {
+ return false;
+ }
+
+ $sx = imagesx($img);
+ $sy = imagesy($img);
+
+ if ($sx > $size || $sy > $size) {
+ $scale = max($sx, $sy) / $size;
+ $dx = floor($sx / $scale);
+ $dy = floor($sy / $scale);
+ } else {
+ $dx = $sx;
+ $dy = $sy;
+ }
+
+ $dy = floor($dy * $aspect);
+
+ $dst = imagecreatetruecolor($dx, $dy);
+ if (!$dst) {
+ return false;
+ }
+ imagealphablending($dst, false);
+
+ $ok = imagecopyresampled(
+ $dst, $img,
+ 0, 0,
+ 0, 0,
+ $dx, $dy,
+ $sx, $sy);
+
+ if (!$ok) {
+ return false;
+ }
+
+ $map = array(
+ ' ',
+ '.',
+ ',',
+ ':',
+ ';',
+ '!',
+ '|',
+ '*',
+ '=',
+ '@',
+ '$',
+ '#',
+ );
+
+ $lines = array();
+
+ for ($ii = 0; $ii < $dy; $ii++) {
+ $buf = '';
+ for ($jj = 0; $jj < $dx; $jj++) {
+ $c = imagecolorat($dst, $jj, $ii);
+
+ $a = ($c >> 24) & 0xFF;
+ $r = ($c >> 16) & 0xFF;
+ $g = ($c >> 8) & 0xFF;
+ $b = ($c) & 0xFF;
+
+ $luma = (255 - ((0.30 * $r) + (0.59 * $g) + (0.11 * $b))) / 256;
+ $luma *= ((127 - $a) / 127);
+
+ $char = $map[max(0, floor($luma * count($map)))];
+ $buf .= $char;
+ }
+
+ $lines[] = $buf;
+ }
+
+ return $lines;
+ }
+
+}
@@ -0,0 +1,14 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'infrastructure/daemon/irc/handler/base');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorIRCMacroHandler.php');

0 comments on commit 6712dbb

Please sign in to comment.