/**
  * @param InputInterface $input
  * @param OutputInterface $output
  *
  * @return int|null|void
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $redis = new Client(sprintf('tcp://%s:%d', ConfigurationLoader::get('client.async.redis.host'), ConfigurationLoader::get('client.async.redis.port')));
     $logger = LoggerFactory::create('Client #' . $input->getArgument('client_id'), true);
     $client = ClientFactory::create($logger, $redis, $input->getArgument('account_key'), $input->getArgument('client_id'), true);
     $connector = new ClientWorker($logger, $client, $redis);
     $connector->listen();
 }
Example #2
0
 /**
  * Show the asynchronous client logs in the main process logger (console)
  *
  * @return string|null
  *
  * @throws \RuntimeException
  */
 public static function subscribe()
 {
     if (!isset(self::$redisClient)) {
         throw new \RuntimeException('Redis client has not been initialised');
     }
     while (null != ($log = self::$redisClient->lpop(ConfigurationLoader::get('client.async.redis.key') . '.client.logs'))) {
         list($level, $message) = explode('|', $log);
         self::$logger->addRecord($level, $message);
     }
 }
Example #3
0
 /**
  * @param string $regionUniqueName
  *
  * @return RegionInterface
  *
  * @throws RegionNotFoundException
  */
 private static function createRegion($regionUniqueName)
 {
     try {
         $region = ConfigurationLoader::get('region.servers.' . $regionUniqueName);
     } catch (ConfigurationKeyNotFoundException $e) {
         throw new RegionNotFoundException('The region with unique name "' . $regionUniqueName . '" is not found');
     }
     $class = ConfigurationLoader::get('region.class');
     return new $class($regionUniqueName, $region['name'], $region['server'], $region['loginQueue']);
 }
Example #4
0
 /**
  * @param string $protocol
  * @param string $server
  * @param int    $port
  */
 public function __construct($protocol, $server, $port)
 {
     $this->timeout = (int) ConfigurationLoader::get('client.request.timeout');
     if (1 > $this->timeout) {
         $this->timeout = 5;
     }
     $this->socket = stream_socket_client(sprintf('%s://%s:%d', $protocol, $server, $port), $errorCode, $errorMessage, $this->timeout);
     if (0 != $errorCode) {
         $this->errorMessage = $errorMessage;
     } else {
         stream_set_timeout($this->socket, $this->timeout);
         stream_set_blocking($this->socket, false);
     }
 }
Example #5
0
 /**
  * @param LoggerInterface    $logger
  * @param LOLClientInterface $client
  * @param Client             $redis
  *
  * @throws \Exception
  */
 public function __construct(LoggerInterface $logger, LOLClientInterface $client, $redis)
 {
     $this->logger = $logger;
     $this->client = $client;
     $this->redis = $redis;
     // Init configuration to handle exception and log them
     try {
         $this->expire = (int) ConfigurationLoader::get('client.response.expire');
         if ($this->expire < (int) ConfigurationLoader::get('client.request.timeout')) {
             $this->expire = (int) ConfigurationLoader::get('client.request.timeout');
         }
         $this->key = ConfigurationLoader::get('client.async.redis.key');
         $this->defaultPort = ConfigurationLoader::get('client.async.startPort');
     } catch (\Exception $e) {
         $this->logger->critical($e->getMessage());
         throw $e;
     }
 }
Example #6
0
 /**
  * Fetch the result from client, transform it into an array and store it into the $this->results array
  *
  * @param int           $invokeId
  * @param null|callable $resultsCallback This callback will format the result if needed
  * @param int           $timeout
  * @param bool          $bypassOverload  Some API return nothing on error, we need to bypass overload system to<br />
  *                                       avoid timeout issue.
  */
 protected function fetchResult($invokeId, \Closure $resultsCallback = null, $timeout = null, $bypassOverload = false)
 {
     $this->invokeCount++;
     if (null == $timeout) {
         $timeout = ConfigurationLoader::get('client.request.timeout');
     }
     $timedOut = time() + $timeout;
     $this->onClientReady(function (LOLClientInterface $client) use($invokeId, $timedOut, $bypassOverload, $resultsCallback, $timeout) {
         $this->apiManager->getLoop()->addPeriodicTimer(0.0001, function (TimerInterface $timer) use($invokeId, $timedOut, $bypassOverload, $client, $resultsCallback, $timeout) {
             if ($this->hasError) {
                 $timer->cancel();
                 return;
             }
             // Timeout process
             if (time() > $timedOut) {
                 $this->hasError = true;
                 $this->conn->emit('api-error', [new RequestTimeoutException('Request timeout, the client will reconnect', $client)]);
                 $timer->cancel();
                 return null;
             }
             $resultParams = $client->getResult($invokeId);
             if (null == $resultParams) {
                 return;
             }
             list($data, $callback) = $resultParams;
             $formatter = new ResultFormatter();
             try {
                 // RTMP API return error
                 if ('_error' == $data['result']) {
                     $this->hasError = true;
                     $errorParams = $formatter->format($data['data']->getData()->rootCause);
                     $this->conn->emit('api-error', [new ApiException($errorParams['rootCauseClassname'], $errorParams['message'])]);
                     $timer->cancel();
                     return;
                 }
                 $result = $formatter->format($data['data']->getData()->body);
                 if (null != $callback) {
                     if ($callback instanceof Callback) {
                         $result = $callback->getResult($result);
                     } else {
                         $result = $callback($result);
                     }
                 }
                 if (null != $resultsCallback) {
                     $this->results = $resultsCallback($result, $this->results);
                 } else {
                     $this->results[] = $result;
                 }
                 $this->responseCount++;
                 $timer->cancel();
             } catch (ClientOverloadException $e) {
                 if ($bypassOverload) {
                     $this->results[] = [];
                     // empty response
                     $this->responseCount++;
                     $timer->cancel();
                 } else {
                     // Flag client as overloaded & retry
                     $client->setIsOverloaded();
                     $timer->cancel();
                     $this->fetchResult($invokeId, $resultsCallback, $timeout, $bypassOverload);
                 }
             }
         });
     });
 }
Example #7
0
 /**
  * The RTMP LoL API will temporary ban you if you call too many times a service<br />
  * To avoid this limitation, you must wait before making a new request
  *
  * @param string   $regionUniqueName
  * @param callable $callback
  *
  * @return LOLClientInterface
  *
  * @throws RegionNotFoundException When there is not client with the selected region unique name
  */
 public function getClient($regionUniqueName, \Closure $callback)
 {
     if (!isset($this->clients[$regionUniqueName])) {
         throw new RegionNotFoundException('There is no registered client with the region "' . $regionUniqueName . '"');
     }
     $nextAvailableTime = (double) ConfigurationLoader::get('client.request.overload.available');
     $nextAvailableTime /= 2;
     foreach ($this->clients[$regionUniqueName] as $client) {
         if ($client->isAvailable()) {
             return $callback($client);
         }
     }
     $this->loop->addPeriodicTimer($nextAvailableTime, function (TimerInterface $timer) use($regionUniqueName, $callback) {
         foreach ($this->clients[$regionUniqueName] as $client) {
             if ($client->isAvailable()) {
                 $timer->cancel();
                 return $callback($client);
             }
         }
     });
 }
Example #8
0
 /**
  * {@inheritdoc}
  */
 public function setIsOverloaded()
 {
     $this->lastCall += (int) ConfigurationLoader::get('client.request.overload.wait');
 }
Example #9
0
 /**
  * @param string          $commandName
  * @param array           $parameters
  * @param int|string|null $invokeId
  *
  * @return int|string
  */
 protected function send($commandName, array $parameters = array(), $invokeId = null)
 {
     if (null == $invokeId) {
         $invokeId = $this->redis->incr($this->getKey('invokeId'));
     }
     $nextAvailableTime = (double) ConfigurationLoader::get('client.request.overload.available');
     $this->lastCall = microtime(true) + $nextAvailableTime;
     $this->con->send(json_encode(['invokeId' => $invokeId, 'command' => $commandName, 'parameters' => $parameters]), \ZMQ::MODE_DONTWAIT);
     return $invokeId;
 }
Example #10
0
 /**
  * @param array  $results
  * @param string $format
  *
  * @return mixed
  *
  * @throws UnknownFormatException
  */
 protected function format(array $results, $format = null)
 {
     if (null == $format) {
         $format = ConfigurationLoader::get('server.format');
     } else {
         if (!isset($this->formatters[$format])) {
             throw new UnknownFormatException('Unknown format for "' . $format . '". Did you mean : "' . join(', ', array_keys($this->formatters)) . '" ?');
         }
     }
     return $this->formatters[$format]->format($results);
 }