diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php --- a/src/infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php @@ -3,11 +3,12 @@ abstract class PhabricatorBotBaseStreamingProtocolAdapter extends PhabricatorBaseProtocolAdapter { + protected $readHandles; + protected $multiHandle; + protected $authtoken; + private $readBuffers; - private $authtoken; private $server; - private $readHandles; - private $multiHandle; private $active; private $inRooms = array(); @@ -38,26 +39,28 @@ // Set up the curl stream for reading $url = $this->buildStreamingUrl($room_id); - $this->readHandle[$url] = curl_init(); - curl_setopt($this->readHandle[$url], CURLOPT_URL, $url); - curl_setopt($this->readHandle[$url], CURLOPT_RETURNTRANSFER, true); - curl_setopt($this->readHandle[$url], CURLOPT_FOLLOWLOCATION, 1); + $ch = $this->readHandles[$url] = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt( - $this->readHandle[$url], + $ch, CURLOPT_USERPWD, $this->authtoken.':x'); + curl_setopt( - $this->readHandle[$url], + $ch, CURLOPT_HTTPHEADER, array('Content-type: application/json')); curl_setopt( - $this->readHandle[$url], + $ch, CURLOPT_WRITEFUNCTION, array($this, 'read')); - curl_setopt($this->readHandle[$url], CURLOPT_BUFFERSIZE, 128); - curl_setopt($this->readHandle[$url], CURLOPT_TIMEOUT, 0); + curl_setopt($ch, CURLOPT_BUFFERSIZE, 128); + curl_setopt($ch, CURLOPT_TIMEOUT, 0); - curl_multi_add_handle($this->multiHandle, $this->readHandle[$url]); + curl_multi_add_handle($this->multiHandle, $ch); // Initialize read buffer $this->readBuffers[$url] = ''; @@ -153,10 +156,15 @@ } protected function getAuthorizationHeader() { - return 'Basic '.base64_encode($this->authtoken.':x'); + return 'Basic '.$this->getEncodedAuthToken(); + } + + protected function getEncodedAuthToken() { + return base64_encode($this->authtoken.':x'); } abstract protected function buildStreamingUrl($channel); abstract protected function processMessage($raw_object); + } diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php --- a/src/infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php @@ -8,42 +8,50 @@ } protected function buildStreamingUrl($channel) { - $organization = $this->getConfig('organization'); + $organization = $this->getConfig('flowdock.organization'); + if (empty($organization)) { + $this->getConfig('organization'); + } + if (empty($organization)) { + throw new Exception( + '"flowdock.organization" configuration variable not set'); + } + + $ssl = $this->getConfig('ssl'); $url = ($ssl) ? 'https://' : 'http://'; - $url .= "stream.flowdock.com/flows/{$organization}/{$channel}"; - + $url .= "{$this->authtoken}@stream.flowdock.com/flows/{$organization}/{$channel}"; return $url; } protected function processMessage($m_obj) { - $command = null; - switch ($m_obj['event']) { - case 'message': - $command = 'MESSAGE'; - break; - default: - // For now, ignore anything which we don't otherwise know about. - break; - } + $command = null; + switch ($m_obj['event']) { + case 'message': + $command = 'MESSAGE'; + break; + default: + // For now, ignore anything which we don't otherwise know about. + break; + } - if ($command === null) { - return false; - } + if ($command === null) { + return false; + } - // TODO: These should be usernames, not user IDs. - $sender = id(new PhabricatorBotUser()) - ->setName($m_obj['user']); + // TODO: These should be usernames, not user IDs. + $sender = id(new PhabricatorBotUser()) + ->setName($m_obj['user']); - $target = id(new PhabricatorBotChannel()) - ->setName($m_obj['flow']); + $target = id(new PhabricatorBotChannel()) + ->setName($m_obj['flow']); - return id(new PhabricatorBotMessage()) - ->setCommand($command) - ->setSender($sender) - ->setTarget($target) - ->setBody($m_obj['content']); + return id(new PhabricatorBotMessage()) + ->setCommand($command) + ->setSender($sender) + ->setTarget($target) + ->setBody($m_obj['content']); } public function writeMessage(PhabricatorBotMessage $message) { @@ -59,15 +67,16 @@ private function speak( $body, PhabricatorBotTarget $flow) { - - list($organization, $room_id) = explode(':', $flow->getName()); - - $this->performPost( - "/flows/{$organization}/{$room_id}/messages", - array( - 'event' => 'message', - 'content' => $body)); - } + // The $flow->getName() returns the flow's UUID, + // as such, the Flowdock API does not require the organization + // to be specified in the URI + $this->performPost( + '/messages', + array( + 'flow' => $flow->getName(), + 'event' => 'message', + 'content' => $body)); + } public function __destruct() { if ($this->readHandles) {