mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 05:50:55 +01:00
Initial PhabricatorIRCFeedNotificationHandler
Summary: Follows Phabricator's feed and puts notifications into channels that are configured. ~~notification.all - bool - 1:1 stories to messages~~ notification.types - array - Specific story types to notify for - ["differential", "maniphest"] notification.verbosity - int - Range of 0-3 for verbosity notification.max_pages - int - Maximum number of pages to go back per poll notification.page_size - int - Size of pages (limit) to poll ~~notification.channels - array - Array of channels to send messages to~~ ~~notification.sleep - int - Seconds to sleep between polls~~ Test Plan: Run phabot with various configuration options Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin, asherkin Differential Revision: https://secure.phabricator.com/D4418
This commit is contained in:
parent
721071e5b3
commit
ff53b7942a
2 changed files with 161 additions and 0 deletions
|
@ -883,6 +883,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php',
|
||||
'PhabricatorIRCBot' => 'infrastructure/daemon/irc/PhabricatorIRCBot.php',
|
||||
'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/PhabricatorIRCDifferentialNotificationHandler.php',
|
||||
'PhabricatorIRCFeedNotificationHandler' => 'infrastructure/daemon/irc/handler/PhabricatorIRCFeedNotificationHandler.php',
|
||||
'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/PhabricatorIRCHandler.php',
|
||||
'PhabricatorIRCLogHandler' => 'infrastructure/daemon/irc/handler/PhabricatorIRCLogHandler.php',
|
||||
'PhabricatorIRCMacroHandler' => 'infrastructure/daemon/irc/handler/PhabricatorIRCMacroHandler.php',
|
||||
|
@ -2262,6 +2263,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
|
||||
'PhabricatorIRCBot' => 'PhabricatorDaemon',
|
||||
'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCFeedNotificationHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCMacroHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Watches the feed and puts notifications into channel(s) of choice
|
||||
*
|
||||
* @group irc
|
||||
*/
|
||||
final class PhabricatorIRCFeedNotificationHandler
|
||||
extends PhabricatorIRCHandler {
|
||||
|
||||
private $startupDelay = 30;
|
||||
private $lastSeenChronoKey = 0;
|
||||
|
||||
private function shouldShowStory($story) {
|
||||
$story_class = $story['class'];
|
||||
$story_text = $story['text'];
|
||||
|
||||
$show = $this->getConfig('notification.types');
|
||||
|
||||
if ($show) {
|
||||
$obj_type = str_replace('PhabricatorFeedStory', '', $story_class);
|
||||
if (!in_array(strtolower($obj_type), $show)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$verbosity = $this->getConfig('notification.verbosity', 3);
|
||||
|
||||
$verbs = array();
|
||||
|
||||
switch ($verbosity) {
|
||||
case 2:
|
||||
$verbs[] = array(
|
||||
'commented',
|
||||
'added',
|
||||
'changed',
|
||||
'resigned',
|
||||
'explained',
|
||||
'modified',
|
||||
'attached',
|
||||
'edited',
|
||||
'joined',
|
||||
'left',
|
||||
'removed'
|
||||
);
|
||||
// fallthrough
|
||||
case 1:
|
||||
$verbs[] = array(
|
||||
'updated',
|
||||
'accepted',
|
||||
'requested',
|
||||
'planned',
|
||||
'claimed',
|
||||
'summarized',
|
||||
'commandeered',
|
||||
'assigned'
|
||||
);
|
||||
// fallthrough
|
||||
case 0:
|
||||
$verbs[] = array(
|
||||
'created',
|
||||
'closed',
|
||||
'raised',
|
||||
'committed',
|
||||
'reopened',
|
||||
'deleted'
|
||||
);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
default:
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
$verbs = '/('.implode('|', array_mergev($verbs)).')/';
|
||||
|
||||
if (preg_match($verbs, $story_text)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function receiveMessage(PhabricatorIRCMessage $message) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function runBackgroundTasks() {
|
||||
if ($this->startupDelay > 0) {
|
||||
// the event loop runs every 1s so delay enough to fully conenct
|
||||
$this->startupDelay--;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($this->lastSeenChronoKey == 0) {
|
||||
// Since we only want to post notifications about new stories, skip
|
||||
// everything that's happened in the past when we start up so we'll
|
||||
// only process real-time stories.
|
||||
$latest = $this->getConduit()->callMethodSynchronous(
|
||||
'feed.query',
|
||||
array(
|
||||
'limit'=>1
|
||||
));
|
||||
|
||||
foreach ($latest as $story) {
|
||||
if ($story['chronologicalKey'] > $this->lastSeenChronoKey) {
|
||||
$this->lastSeenChronoKey = $story['chronologicalKey'];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$config_max_pages = $this->getConfig('notification.max_pages', 5);
|
||||
$config_page_size = $this->getConfig('notification.page_size', 10);
|
||||
|
||||
$last_seen_chrono_key = $this->lastSeenChronoKey;
|
||||
$chrono_key_cursor = 0;
|
||||
|
||||
// Not efficient but works due to feed.query API
|
||||
for ($max_pages = $config_max_pages; $max_pages > 0; $max_pages--) {
|
||||
$stories = $this->getConduit()->callMethodSynchronous(
|
||||
'feed.query',
|
||||
array(
|
||||
'limit'=>$config_page_size,
|
||||
'after'=>$chrono_key_cursor,
|
||||
'view'=>'text'
|
||||
));
|
||||
|
||||
foreach ($stories as $story) {
|
||||
if ($story['chronologicalKey'] == $last_seen_chrono_key) {
|
||||
// Caught up on feed
|
||||
return;
|
||||
}
|
||||
if ($story['chronologicalKey'] > $this->lastSeenChronoKey) {
|
||||
// Keep track of newest seen story
|
||||
$this->lastSeenChronoKey = $story['chronologicalKey'];
|
||||
}
|
||||
if (!$chrono_key_cursor ||
|
||||
$story['chronologicalKey'] < $chrono_key_cursor) {
|
||||
// Keep track of oldest story on this page
|
||||
$chrono_key_cursor = $story['chronologicalKey'];
|
||||
}
|
||||
|
||||
if (!$story['text'] ||
|
||||
!$this->shouldShowStory($story)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$channels = $this->getConfig('join');
|
||||
foreach ($channels as $channel) {
|
||||
$this->write('PRIVMSG', "{$channel} :{$story['text']}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue