8889841cWebSocketServerFactory.php000066600000004446150515666720011713 0ustar00loop = LoopFactory::create(); } public function useRoutes(RouteCollection $routes) { $this->routes = $routes; return $this; } public function setHost(string $host) { $this->host = $host; return $this; } public function setPort(string $port) { $this->port = $port; return $this; } public function setLoop(LoopInterface $loop) { $this->loop = $loop; return $this; } public function setConsoleOutput(OutputInterface $consoleOutput) { $this->consoleOutput = $consoleOutput; return $this; } public function createServer(): IoServer { $socket = new Server("{$this->host}:{$this->port}", $this->loop); if (config('websockets.ssl.local_cert')) { $socket = new SecureServer($socket, $this->loop, config('websockets.ssl')); } $urlMatcher = new UrlMatcher($this->routes, new RequestContext); $router = new Router($urlMatcher); $app = new OriginCheck($router, config('websockets.allowed_origins', [])); $httpServer = new HttpServer($app, config('websockets.max_request_size_in_kb') * 1024); if (HttpLogger::isEnabled()) { $httpServer = HttpLogger::decorate($httpServer); } return new IoServer($httpServer, $socket, $this->loop); } } HttpServer.php000066600000000534150515666720007406 0ustar00_reqParser->maxSize = $maxRequestSize; } } OriginCheck.php000066600000003274150515666720007471 0ustar00_component = $component; $this->allowedOrigins = $allowedOrigins; } public function onOpen(ConnectionInterface $connection, RequestInterface $request = null) { if ($request->hasHeader('Origin')) { $this->verifyOrigin($connection, $request); } return $this->_component->onOpen($connection, $request); } public function onMessage(ConnectionInterface $from, $msg) { return $this->_component->onMessage($from, $msg); } public function onClose(ConnectionInterface $connection) { return $this->_component->onClose($connection); } public function onError(ConnectionInterface $connection, \Exception $e) { return $this->_component->onError($connection, $e); } protected function verifyOrigin(ConnectionInterface $connection, RequestInterface $request) { $header = (string) $request->getHeader('Origin')[0]; $origin = parse_url($header, PHP_URL_HOST) ?: $header; if (! empty($this->allowedOrigins) && ! in_array($origin, $this->allowedOrigins)) { return $this->close($connection, 403); } } } Router.php000066600000006775150515666720006575 0ustar00routes = new RouteCollection; $this->customRoutes = new Collection(); } public function getRoutes(): RouteCollection { return $this->routes; } public function echo() { $this->get('/app/{appKey}', WebSocketHandler::class); $this->post('/apps/{appId}/events', TriggerEventController::class); $this->get('/apps/{appId}/channels', FetchChannelsController::class); $this->get('/apps/{appId}/channels/{channelName}', FetchChannelController::class); $this->get('/apps/{appId}/channels/{channelName}/users', FetchUsersController::class); } public function customRoutes() { $this->customRoutes->each(function ($action, $uri) { $this->get($uri, $action); }); } public function get(string $uri, $action) { $this->addRoute('GET', $uri, $action); } public function post(string $uri, $action) { $this->addRoute('POST', $uri, $action); } public function put(string $uri, $action) { $this->addRoute('PUT', $uri, $action); } public function patch(string $uri, $action) { $this->addRoute('PATCH', $uri, $action); } public function delete(string $uri, $action) { $this->addRoute('DELETE', $uri, $action); } public function webSocket(string $uri, $action) { if (! is_subclass_of($action, MessageComponentInterface::class)) { throw InvalidWebSocketController::withController($action); } $this->customRoutes->put($uri, $action); } public function addRoute(string $method, string $uri, $action) { $this->routes->add($uri, $this->getRoute($method, $uri, $action)); } protected function getRoute(string $method, string $uri, $action): Route { /** * If the given action is a class that handles WebSockets, then it's not a regular * controller but a WebSocketHandler that needs to converted to a WsServer. * * If the given action is a regular controller we'll just instanciate it. */ $action = is_subclass_of($action, MessageComponentInterface::class) ? $this->createWebSocketsServer($action) : app($action); return new Route($uri, ['_controller' => $action], [], [], null, [], [$method]); } protected function createWebSocketsServer(string $action): WsServer { $app = app($action); if (WebsocketsLogger::isEnabled()) { $app = WebsocketsLogger::decorate($app); } return new WsServer($app); } } Logger/Logger.php000066600000003050150515666720007732 0ustar00enabled; } public function __construct(OutputInterface $consoleOutput) { $this->consoleOutput = $consoleOutput; } public function enable($enabled = true) { $this->enabled = $enabled; return $this; } public function verbose($verbose = false) { $this->verbose = $verbose; return $this; } protected function info(string $message) { $this->line($message, 'info'); } protected function warn(string $message) { if (! $this->consoleOutput->getFormatter()->hasStyle('warning')) { $style = new OutputFormatterStyle('yellow'); $this->consoleOutput->getFormatter()->setStyle('warning', $style); } $this->line($message, 'warning'); } protected function error(string $message) { $this->line($message, 'error'); } protected function line(string $message, string $style) { $styled = $style ? "<$style>$message" : $message; $this->consoleOutput->writeln($styled); } } Logger/ConnectionLogger.php000066600000002547150515666720011764 0ustar00setConnection($app); } public function setConnection(ConnectionInterface $connection) { $this->connection = $connection; return $this; } protected function getConnection() { return $this->connection; } public function send($data) { $socketId = $this->connection->socketId ?? null; $this->info("Connection id {$socketId} sending message {$data}"); $this->connection->send($data); } public function close() { $this->warn("Connection id {$this->connection->socketId} closing."); $this->connection->close(); } public function __set($name, $value) { return $this->connection->$name = $value; } public function __get($name) { return $this->connection->$name; } public function __isset($name) { return isset($this->connection->$name); } public function __unset($name) { unset($this->connection->$name); } } Logger/WebsocketsLogger.php000066600000004044150515666720011770 0ustar00setApp($app); } public function setApp(MessageComponentInterface $app) { $this->app = $app; return $this; } public function onOpen(ConnectionInterface $connection) { $appKey = QueryParameters::create($connection->httpRequest)->get('appKey'); $this->warn("New connection opened for app key {$appKey}."); $this->app->onOpen(ConnectionLogger::decorate($connection)); } public function onMessage(ConnectionInterface $connection, MessageInterface $message) { $this->info("{$connection->app->id}: connection id {$connection->socketId} received message: {$message->getPayload()}."); $this->app->onMessage(ConnectionLogger::decorate($connection), $message); } public function onClose(ConnectionInterface $connection) { $socketId = $connection->socketId ?? null; $this->warn("Connection id {$socketId} closed."); $this->app->onClose(ConnectionLogger::decorate($connection)); } public function onError(ConnectionInterface $connection, Exception $exception) { $exceptionClass = get_class($exception); $appId = $connection->app->id ?? 'Unknown app id'; $message = "{$appId}: exception `{$exceptionClass}` thrown: `{$exception->getMessage()}`."; if ($this->verbose) { $message .= $exception->getTraceAsString(); } $this->error($message); $this->app->onError(ConnectionLogger::decorate($connection), $exception); } } Logger/HttpLogger.php000066600000002527150515666720010602 0ustar00setApp($app); } public function setApp(MessageComponentInterface $app) { $this->app = $app; return $this; } public function onOpen(ConnectionInterface $connection) { $this->app->onOpen($connection); } public function onMessage(ConnectionInterface $connection, $message) { $this->app->onMessage($connection, $message); } public function onClose(ConnectionInterface $connection) { $this->app->onClose($connection); } public function onError(ConnectionInterface $connection, Exception $exception) { $exceptionClass = get_class($exception); $message = "Exception `{$exceptionClass}` thrown: `{$exception->getMessage()}`"; if ($this->verbose) { $message .= $exception->getTraceAsString(); } $this->error($message); $this->app->onError($connection, $exception); } }