/** * Handles incoming websocket messages, parses them, and emits them as remote events. * * @param WebSocketMessageInterface $messageRaw A websocket message. */ private function onMessage(WebSocketMessageInterface $message) { // parse the message and get the event name $payload = Payload::fromJson($message->getData()); if (isset($payload['type'])) { switch ($payload['type']) { case 'hello': $this->connected = true; break; case 'team_rename': $this->team->data['name'] = $payload['name']; break; case 'team_domain_change': $this->team->data['domain'] = $payload['domain']; break; case 'channel_created': $this->getChannelById($payload['channel']['id'])->then(function (Channel $channel) { $this->channels[$channel->getId()] = $channel; }); break; case 'channel_deleted': unset($this->channels[$payload['channel']['id']]); break; case 'channel_rename': $this->channels[$payload['channel']['id']]->data['name'] = $payload['channel']['name']; break; case 'channel_archive': $this->channels[$payload['channel']['id']]->data['is_archived'] = true; break; case 'channel_unarchive': $this->channels[$payload['channel']['id']]->data['is_archived'] = false; break; case 'group_joined': $group = new Group($this, $payload['channel']); $this->groups[$group->getId()] = $group; break; case 'group_rename': $this->groups[$payload['group']['id']]->data['name'] = $payload['channel']['name']; break; case 'group_archive': $this->groups[$payload['group']['id']]->data['is_archived'] = true; break; case 'group_unarchive': $this->groups[$payload['group']['id']]->data['is_archived'] = false; break; case 'im_created': $dm = new DirectMessageChannel($this, $payload['channel']); $this->dms[$dm->getId()] = $dm; break; } // emit an event with the attached json $this->emit($payload['type'], [$payload]); } else { // If reply_to is set, then it is a server confirmation for a previously // sent message if (isset($payload['reply_to'])) { if (isset($this->pendingMessages[$payload['reply_to']])) { $deferred = $this->pendingMessages[$payload['reply_to']]; // Resolve or reject the promise that was waiting for the reply. if (isset($payload['ok']) && $payload['ok'] === true) { $deferred->resolve(); } else { $deferred->reject($payload['error']); } unset($this->pendingMessages[$payload['reply_to']]); } } } }
/** * Sends an API request. * * @param string $method The API method to call. * @param array $args An associative array of arguments to pass to the * method call. * * @return \React\Promise\PromiseInterface A promise for an API response. */ public function apiCall($method, array $args = []) { // create the request url $requestUrl = self::BASE_URL . $method; // set the api token $args['token'] = $this->token; // send a post request with all arguments $promise = $this->httpClient->postAsync($requestUrl, ['form_params' => $args]); // Add requests to the event loop to be handled at a later date. $this->loop->futureTick(function () use($promise) { $promise->wait(); }); // When the response has arrived, parse it and resolve. Note that our // promises aren't pretty; Guzzle promises are not compatible with React // promises, so the only Guzzle promises ever used die in here and it is // React from here on out. $deferred = new Deferred(); $promise->then(function (ResponseInterface $response) use($deferred) { // get the response as a json object $payload = Payload::fromJson((string) $response->getBody()); // check if there was an error if (isset($payload['ok']) && $payload['ok'] === true) { $deferred->resolve($payload); } else { // make a nice-looking error message and throw an exception $niceMessage = ucfirst(str_replace('_', ' ', $payload['error'])); $deferred->reject(new ApiException($niceMessage)); } }); return $deferred->promise(); }