Send message
public sendMessage ( Thruway\Message\Message $msg ) : mixed | void | ||
$msg | Thruway\Message\Message | |
return | mixed | void |
private function processInvocationError(Session $session, ErrorMessage $msg) { $call = $this->getCallByRequestId($msg->getRequestId()); if (!$call) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $this->manager->error('No call for invocation error message: ' . $msg->getRequestId()); // TODO: do we send a message back to the callee? $errorMsg->setErrorURI('wamp.error.no_such_procedure'); $session->sendMessage($errorMsg); return false; } $this->calls->detach($call); $errorMsg = ErrorMessage::createErrorMessageFromMessage($call->getCallMessage()); $errorMsg->setErrorURI($msg->getErrorURI()); $errorMsg->setArguments($msg->getArguments()); $errorMsg->setArgumentsKw($msg->getArgumentsKw()); $call->getCallerSession()->sendMessage($errorMsg); }
/** * Process call * * @param \Thruway\Session $session * @param Call $call * @throws \Exception * @return bool | Call */ public function processCall(Session $session, Call $call) { // find a registration to call if (count($this->registrations) == 0) { $session->sendMessage(ErrorMessage::createErrorMessageFromMessage($call->getCallMessage(), 'wamp.error.no_such_procedure')); return false; } // just send it to the first one if we don't allow multiple registrations if (!$this->getAllowMultipleRegistrations()) { $this->registrations[0]->processCall($call); } else { $this->callQueue->enqueue($call); $this->processQueue(); } return true; }
/** * Handle process received message * * @param \Thruway\Session $session * @param \Thruway\Message\Message $msg */ public function onMessage(Session $session, Message $msg) { if ($msg instanceof GoodByeMessage) { Logger::info($this, "Received a GoodBye, so shutting the session down"); $session->sendMessage(new GoodbyeMessage(new \stdClass(), "wamp.error.goodbye_and_out")); $session->shutdown(); } elseif ($session->isAuthenticated()) { $this->processAuthenticated($session, $msg); } elseif ($msg instanceof AbortMessage) { $this->processAbort($session, $msg); } elseif ($msg instanceof HelloMessage) { $this->processHello($session, $msg); } elseif ($msg instanceof AuthenticateMessage) { $this->processAuthenticate($session, $msg); } else { Logger::error($this, "Unhandled message sent to unauthenticated realm: " . $msg->getMsgCode()); $session->abort(new \stdClass(), "wamp.error.not_authorized"); } }
/** * @param \Thruway\Session $session * @param \Thruway\Message\Message $msg */ public function processGoodbye(Session $session, Message $msg) { Logger::info($this, "Received a GoodBye, so shutting the session down"); $session->sendMessage(new GoodbyeMessage(new \stdClass(), "wamp.error.goodbye_and_out")); $session->shutdown(); }
/** * processCancel processes cancel message from the caller. * Return true if the Call should be removed from active calls * * @param Session $session * @param CancelMessage $msg * @return bool */ public function processCancel(Session $session, CancelMessage $msg) { if ($this->getCallerSession() !== $session) { Logger::warning($this, "session attempted to cancel call they did not own."); return false; } if ($this->getCalleeSession() === null) { // this call has not been sent to a callee yet (it is in a queue) // we can just kill it and say it was canceled $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled"); $details = $errorMsg->getDetails() ?: (object) []; $details->_thruway_removed_from_queue = true; $session->sendMessage($errorMsg); return true; } $details = (object) []; if ($this->getCalleeSession()->getHelloMessage() instanceof HelloMessage) { $details = $this->getCalleeSession()->getHelloMessage()->getDetails(); } $calleeSupportsCancel = false; if (isset($details->roles->callee->features->call_canceling) && is_scalar($details->roles->callee->features->call_canceling)) { $calleeSupportsCancel = (bool) $details->roles->callee->features->call_canceling; } if (!$calleeSupportsCancel) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $errorMsg->setErrorURI('wamp.error.not_supported'); $session->sendMessage($errorMsg); return false; } $this->setCancelMessage($msg); $this->canceling = true; $calleeSession = $this->getCalleeSession(); $interruptMessage = new InterruptMessage($this->getInvocationRequestId(), (object) []); $calleeSession->sendMessage($interruptMessage); $this->setInterruptMessage($interruptMessage); if (isset($msg->getOptions()->mode) && is_scalar($msg->getOptions()->mode) && $msg->getOptions()->mode == "killnowait") { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg, "wamp.error.canceled"); $session->sendMessage($errorMsg); return true; } return false; }
/** * Process InvocationError * * @param \Thruway\Session $session * @param \Thruway\Message\ErrorMessage $msg */ private function processInvocationError(Session $session, ErrorMessage $msg) { //$call = $this->getCallByRequestId($msg->getRequestId()); $call = $this->callInvocationIndex[$msg->getRequestId()]; if (!$call) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); Logger::error($this, 'No call for invocation error message: ' . $msg->getRequestId()); // TODO: do we send a message back to the callee? $errorMsg->setErrorURI('wamp.error.no_such_procedure'); $session->sendMessage($errorMsg); return; } if ($call->getCalleeSession() !== $session) { Logger::error($this, "Attempted Invocation Error from session that does not own the call"); return; } $call->getRegistration()->removeCall($call); $this->removeCall($call); $errorMsg = ErrorMessage::createErrorMessageFromMessage($call->getCallMessage()); $errorMsg->setErrorURI($msg->getErrorURI()); $errorMsg->setArguments($msg->getArguments()); $errorMsg->setArgumentsKw($msg->getArgumentsKw()); // not sure if this detail should pass through $errorMsg->setDetails($msg->getDetails()); $call->getCallerSession()->sendMessage($errorMsg); }
/** * @param Session $session * @param UnsubscribeMessage $msg * @return UnsubscribedMessage */ public function processUnsubscribe(Session $session, UnsubscribeMessage $msg) { $subscription = $this->getSubscriptionById($msg->getSubscriptionId()); if (!$subscription || !isset($this->topics[$subscription->getTopic()])) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $session->sendMessage($errorMsg->setErrorURI('wamp.error.no_such_subscription')); } $topicName = $subscription->getTopic(); $subscribers = $this->topics[$topicName]; /* @var $subscriber Session */ foreach ($this->topics[$topicName] as $key => $subscriber) { if ($subscriber == $session) { unset($subscribers[$key]); } } $this->subscriptions->detach($subscription); $session->sendMessage(new UnsubscribedMessage($msg->getRequestId())); }
/** * Call the handler that was registered to handle the Authenticate Message * * @param $authMethod * @param $authMethodInfo * @param Realm $realm * @param Session $session * @param AuthenticateMessage $msg */ private function onAuthenticateHandler($authMethod, $authMethodInfo, Realm $realm, Session $session, AuthenticateMessage $msg) { $onAuthenticateSuccess = function ($res) use($realm, $session) { if (count($res) < 1) { $session->abort(new \stdClass(), "thruway.error.authentication_failure"); return; } // we should figure out a way to have the router send the welcome // message so that the roles and extras that go along with it can be // filled in if ($res[0] == "SUCCESS") { $welcomeDetails = new \stdClass(); if (isset($res[1]->authid)) { $session->getAuthenticationDetails()->setAuthId($res[1]->authid); } else { $session->getAuthenticationDetails()->setAuthId('authenticated_user'); } $authRole = 'authenticated_user'; $session->getAuthenticationDetails()->addAuthRole($authRole); if (isset($res[1]->authroles)) { $session->getAuthenticationDetails()->addAuthRole($res[1]->authroles); } if (isset($res[1]->authrole)) { $session->getAuthenticationDetails()->addAuthRole($res[1]->authrole); } if (isset($res[1]->_thruway_authextra)) { $session->getAuthenticationDetails()->setAuthExtra($res[1]->_thruway_authextra); } if (isset($res[1]) && is_object($res[1])) { $res[1]->authrole = $session->getAuthenticationDetails()->getAuthRole(); $res[1]->authroles = $session->getAuthenticationDetails()->getAuthRoles(); $res[1]->authid = $session->getAuthenticationDetails()->getAuthId(); foreach ($res[1] as $k => $v) { $welcomeDetails->{$k} = $v; } } $session->setAuthenticated(true); $session->sendMessage(new WelcomeMessage($session->getSessionId(), $welcomeDetails)); } else { $session->abort(new \stdClass(), "thruway.error.authentication_failure"); } }; $onAuthenticateError = function () use($session) { Logger::error($this, "onauthenticate rejected the promise"); $session->abort("thruway.error.unknown"); }; $extra = new \stdClass(); $extra->challenge_details = $session->getAuthenticationDetails()->getChallengeDetails(); $arguments = new \stdClass(); $arguments->extra = $extra; $arguments->authid = $session->getAuthenticationDetails()->getAuthId(); $arguments->challenge = $session->getAuthenticationDetails()->getChallenge(); $arguments->signature = $msg->getSignature(); $arguments->authmethod = $authMethod; $arguments->hello_message = $session->getHelloMessage(); // now we send our authenticate information to the RPC $onAuthenticateHandler = $authMethodInfo['handlers']->onauthenticate; $this->session->call($onAuthenticateHandler, [$arguments])->then($onAuthenticateSuccess, $onAuthenticateError); }
/** * Process subscribe message * * @param \Thruway\Session $session * @param \Thruway\Message\SubscribeMessage $msg * @throws \Exception */ protected function processSubscribe(Session $session, SubscribeMessage $msg) { // get a subscription group "hash" /** @var MatcherInterface $matcher */ $matcher = $this->getMatcherForMatchType($msg->getMatchType()); if ($matcher === null) { Logger::alert($this, "no matching match type for \"" . $msg->getMatchType() . "\" for URI \"" . $msg->getUri() . "\""); return; } if (!$matcher->uriIsValid($msg->getUri(), $msg->getOptions())) { $errorMsg = ErrorMessage::createErrorMessageFromMessage($msg); $session->sendMessage($errorMsg->setErrorURI('wamp.error.invalid_uri')); return; } $matchHash = $matcher->getMatchHash($msg->getUri(), $msg->getOptions()); if (!isset($this->subscriptionGroups[$matchHash])) { $this->subscriptionGroups[$matchHash] = new SubscriptionGroup($matcher, $msg->getUri(), $msg->getOptions()); } /** @var SubscriptionGroup $subscriptionGroup */ $subscriptionGroup = $this->subscriptionGroups[$matchHash]; $subscription = $subscriptionGroup->processSubscribe($session, $msg); $registry = $this->getStateHandlerRegistry(); if ($registry !== null) { $registry->processSubscriptionAdded($subscription); } }
/** * @param Session $session * @param UnsubscribeMessage $msg * @return bool|Subscription */ public function processUnsubscribe(Session $session, UnsubscribeMessage $msg) { if ($this->containsSubscriptionId($msg->getSubscriptionId())) { /** @var Subscription $subscription */ $subscription = $this->subscriptions[$msg->getSubscriptionId()]; if ($session !== $subscription->getSession()) { Logger::alert($this, "Unsubscribe request from non-owner: " . json_encode($msg)); return false; } $this->removeSubscription($subscription); $session->sendMessage(new UnsubscribedMessage($msg->getRequestId())); return $subscription; } return false; }
/** * Handle Authenticate message * * @param \Thruway\Realm $realm * @param \Thruway\Session $session * @param \Thruway\Message\AuthenticateMessage $msg * @throws \Exception */ public function handleAuthenticateMessage(Realm $realm, Session $session, AuthenticateMessage $msg) { if ($session->getAuthenticationDetails() === null) { throw new \Exception('Authenticate with no previous auth details'); } $authMethod = $session->getAuthenticationDetails()->getAuthMethod(); // find the auth method foreach ($this->authMethods as $am => $authMethodInfo) { if ($authMethod == $am) { // found it // now we send our authenticate information to the RPC $this->getCaller()->call($this->session, $authMethodInfo['handlers']['onauthenticate'], ['authmethod' => $authMethod, 'challenge' => $session->getAuthenticationDetails()->getChallenge(), 'extra' => ['challenge_details' => $session->getAuthenticationDetails()->getChallengeDetails()], 'signature' => $msg->getSignature(), 'authid' => $session->getAuthenticationDetails()->getAuthId()])->then(function ($res) use($session) { // if (!is_array($res)) { // return; // } if (count($res) < 1) { return; } // we should figure out a way to have the router send the welcome // message so that the roles and extras that go along with it can be // filled in if ($res[0] == "SUCCESS") { $welcomeDetails = ["roles" => []]; if (isset($res[1]) && isset($res[1]['authid'])) { $session->getAuthenticationDetails()->setAuthId($res[1]['authid']); } else { $session->getAuthenticationDetails()->setAuthId('authenticated_user'); $res[1]['authid'] = $session->getAuthenticationDetails()->getAuthId(); } $authRole = 'authenticated_user'; $session->getAuthenticationDetails()->addAuthRole($authRole); if (isset($res[1]) && isset($res[1]['authroles'])) { $session->getAuthenticationDetails()->addAuthRole($res[1]['authroles']); $authRole = $session->getAuthenticationDetails()->getAuthRole(); } if (isset($res[1]) && isset($res[1]['authrole'])) { $session->getAuthenticationDetails()->addAuthRole($res[1]['authrole']); } if (isset($res[1])) { $res[1]['authrole'] = $session->getAuthenticationDetails()->getAuthRole(); $res[1]['authroles'] = $session->getAuthenticationDetails()->getAuthRoles(); $res[1]['authid'] = $session->getAuthenticationDetails()->getAuthId(); if (is_array($res[1])) { $welcomeDetails = array_merge($welcomeDetails, $res[1]); } } $session->setAuthenticated(true); $session->sendMessage(new WelcomeMessage($session->getSessionId(), $welcomeDetails)); } else { $session->abort(new \stdClass(), "bad.login"); } }, function () use($session) { Logger::error($this, "onauthenticate rejected the promise"); $session->abort("thruway.error.unknown"); }); } } }