diff --git a/README.md b/README.md index 2ce2893..0708e55 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Open your config/app.php and add the following to the providers array: ```php 'providers' => [ // ... - LaraComponents\Centrifuge\CentrifugeServiceProvider::class, + Emprove\Centrifugo\CentrifugoServiceProvider::class, // And uncomment BroadcastServiceProvider App\Providers\BroadcastServiceProvider::class, @@ -80,11 +80,11 @@ A simple example of using the client: namespace App\Http\Controllers; -use LaraComponents\Centrifuge\Centrifuge; +use Emprove\Centrifugo\Contracts\Centrifugo; class ExampleController extends Controller { - public function home(Centrifuge $centrifuge) + public function home(Centrifugo $centrifuge) { // Send message into channel $centrifuge->publish('channel-name', [ diff --git a/composer.json b/composer.json index 43db01b..3a85df6 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "emprove/centrifuge-broadcaster", "type": "library", - "description": "Centrifuge broadcaster for laravel >= 5.7", + "description": "Centrifuge broadcaster for laravel ^6", "keywords": ["laravel", "centrifuge", "centrifugo", "broadcaster"], "license": "MIT", "authors": [ @@ -16,22 +16,22 @@ "source": "https://github.com/emprove/centrifuge-broadcaster" }, "require": { - "php": "^7.1.3", - "illuminate/broadcasting": "^5.8|^6.0", + "php": "^7.2", + "illuminate/broadcasting": "^6.0", "guzzlehttp/guzzle": "^6.3.3", - "lcobucci/jwt": "^3.2" + "lcobucci/jwt": "3.4.*" }, "require-dev": {}, "autoload": { "psr-4": { - "LaraComponents\\Centrifuge\\": "src/" + "Emprove\\Centrifugo\\": "src/" } }, "autoload-dev": {}, "extra": { "laravel": { "providers": [ - "LaraComponents\\Centrifuge\\CentrifugeServiceProvider" + "Emprove\\Centrifugo\\CentrifugoServiceProvider" ] } }, diff --git a/src/Centrifuge.php b/src/Centrifuge.php deleted file mode 100644 index e3d1d13..0000000 --- a/src/Centrifuge.php +++ /dev/null @@ -1,282 +0,0 @@ -httpClient = $httpClient; - $this->config = $config; - } - - /** - * Send message into channel. - * - * @param string $channel - * @param array $data - * @param string $client - * - * @return mixed - */ - public function publish($channel, array $data, $client = null) - { - $params = ['channel' => $channel, 'data' => $data]; - - if (!is_null($client)) { - $params['client'] = $client; - } - - return $this->send('publish', $params); - } - - /** - * Send message into multiple channel. - * - * @param array $channels - * @param array $data - * @param string $client - * - * @return mixed - */ - public function broadcast(array $channels, array $data, $client = null) - { - $params = ['channels' => $channels, 'data' => $data]; - - if (!is_null($client)) { - $params['client'] = $client; - } - - return $this->send('broadcast', $params); - } - - /** - * Get channel presence information (all clients currently subscribed on this channel). - * - * @param string $channel - * - * @return mixed - */ - public function presence($channel) - { - return $this->send('presence', ['channel' => $channel]); - } - - /** - * Get channel history information (list of last messages sent into channel). - * - * @param string $channel - * - * @return mixed - */ - public function history($channel) - { - return $this->send('history', ['channel' => $channel]); - } - - /** - * Unsubscribe user from channel. - * - * @param string $user_id - * @param string $channel - * - * @return mixed - */ - public function unsubscribe($user_id, $channel = null) - { - $params = ['user' => (string) $user_id]; - - if (!is_null($channel)) { - $params['channel'] = $channel; - } - - return $this->send('unsubscribe', $params); - } - - /** - * Disconnect user by its ID. - * - * @param string $user_id - * - * @return mixed - */ - public function disconnect($user_id) - { - return $this->send('disconnect', ['user' => (string) $user_id]); - } - - /** - * Get channels information (list of currently active channels). - * - * @return mixed - */ - public function channels() - { - return $this->send('channels'); - } - - /** - * Get stats information about running server nodes. - * - * @return mixed - */ - public function stats() - { - return $this->send('stats'); - } - - /** - * Generate api sign. - * - * @param string $data - * - * @return string - */ - public function generateApiSign($data) - { - $ctx = hash_init('sha256', HASH_HMAC, $this->getSecret()); - hash_update($ctx, (string) $data); - - return hash_final($ctx); - } - - /** - * Get secret key. - * - * @return string - */ - protected function getSecret() - { - return $this->config['secret']; - } - - /** - * Send message to centrifuge server. - * - * @param string $method - * @param array $params - * - * @return mixed - */ - protected function send($method, array $params = []) - { - try { - $result = $this->httpSend($method, $params); - } catch (Exception $e) { - $result = [ - 'method' => $method, - 'error' => $e->getMessage(), - 'body' => $params, - ]; - } - - return $result; - } - - /** - * Send message to centrifuge server from http client. - * - * @param string $method - * @param array $params - * - * @return mixed - */ - protected function httpSend($method, array $params = []) - { - $json = json_encode(['method' => $method, 'params' => $params]); - - $headers = [ - 'Content-type' => 'application/json', - 'Authorization' => 'apikey ' . collect($this->config)->get('api_key'), - ]; - - try { - $url = parse_url($this->prepareUrl()); - - $config = collect([ - 'headers' => $headers, - 'body' => $json, - 'http_errors' => false, - ]); - - if ($url['scheme'] == 'https') { - $config->put('verify', collect($this->config)->get('verify', false)); - - if (collect($this->config)->get('ssl_key')) { - $config->put('ssl_key', collect($this->config)->get('ssl_key')); - } - } - - $response = $this->httpClient->post($this->prepareUrl(), $config->toArray()); - - $finally = json_decode((string) $response->getBody(), true); - } catch (ClientException $e) { - throw $e; - } - - return $finally; - } - - /** - * Prepare URL to send the http request. - * - * @return string - */ - protected function prepareUrl() - { - $address = rtrim($this->config['url'], '/'); - - if (substr_compare($address, static::API_PATH, -strlen(static::API_PATH)) !== 0) { - $address .= static::API_PATH; - } - - return $address; - } - - /** - * Generate JWT token for client. - * - * @param string $userId - * - * @return string - */ - public function generateToken(string $userId) - { - $signer = new Sha256(); - $expiresAt = (new \DateTimeImmutable)->add(new \DateInterval("PT{$this->config['token_ttl']}S")); - - return (new Builder())->issuedBy($this->config['token_issuer']) - ->expiresAt($expiresAt) - ->set('sub', $userId) - ->getToken($signer, new Key($this->config['secret'])); - } -} diff --git a/src/CentrifugeBroadcaster.php b/src/CentrifugeBroadcaster.php deleted file mode 100644 index db81901..0000000 --- a/src/CentrifugeBroadcaster.php +++ /dev/null @@ -1,128 +0,0 @@ -centrifuge = $centrifuge; - } - - /** - * Authenticate the incoming request for a given channel. - * - * @param \Illuminate\Http\Request $request - * - * @return mixed - */ - public function auth($request) - { - if ($request->user()) { - $client = $request->get('client', ''); - $channels = $request->get('channels', []); - $channels = is_array($channels) ? $channels : [$channels]; - - $response = []; - $info = json_encode([]); - - foreach ($channels as $channel) { - $channelName = (substr($channel, 0, 1) === '$') - ? substr($channel, 1) - : $channel; - - try { - $result = $this->verifyUserCanAccessChannel($request, $channelName); - } catch (HttpException $e) { - $result = false; - } - - $response[$channel] = $result ? [ - 'info' => $info, - ] : [ - 'status' => 403, - ]; - } - - return response()->json($response); - } else { - throw new HttpException(401); - } - } - - /** - * Return the valid authentication response. - * - * @param \Illuminate\Http\Request $request - * @param mixed $result - * - * @return mixed - */ - public function validAuthenticationResponse($request, $result) - { - return $result; - } - - /** - * Broadcast the given event. - * - * @param array $channels - * @param string $event - * @param array $payload - * - * @return void - */ - public function broadcast(array $channels, $event, array $payload = []) - { - $payload['event'] = $event; - - $socket = null; - - if (array_key_exists('socket', $payload)) { - $socket = $payload['socket']; - unset($payload['socket']); - } - - $response = $this->centrifuge->broadcast($this->formatChannels($channels), $payload, $socket); - - if (is_array($response) && empty($response) && !isset($response['error'])) { - return; - } - - if (isset($response['error'])) { - throw new BroadcastException( - $response['error'] instanceof Exception - ? $response['error']->getMessage() - : $response['error'] - ); - } - } - - /** - * Get the Centrifuge instance. - * - * @return \LaraComponents\Centrifuge\Contracts\Centrifuge - */ - public function getCentrifuge() - { - return $this->centrifuge; - } -} diff --git a/src/CentrifugeServiceProvider.php b/src/CentrifugeServiceProvider.php deleted file mode 100644 index f341440..0000000 --- a/src/CentrifugeServiceProvider.php +++ /dev/null @@ -1,40 +0,0 @@ -extend('centrifuge', function ($app) { - return new CentrifugeBroadcaster($app->make('centrifuge')); - }); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - $this->app->singleton('centrifuge', function ($app) { - $config = $app->make('config')->get('broadcasting.connections.centrifuge'); - $http = new Client(); - - return new Centrifuge($config, $http); - }); - - $this->app->alias('centrifuge', 'LaraComponents\Centrifuge\Centrifuge'); - $this->app->alias('centrifuge', 'LaraComponents\Centrifuge\Contracts\Centrifuge'); - } -} diff --git a/src/Centrifugo.php b/src/Centrifugo.php new file mode 100644 index 0000000..301a72f --- /dev/null +++ b/src/Centrifugo.php @@ -0,0 +1,282 @@ +httpClient = $httpClient; + $this->config = $config; + } + + /** + * Send message into channel. + * + * @param string $channel + * @param array $data + * @param string $client + * + * @return mixed + */ + public function publish($channel, array $data, $client = null) + { + $params = ['channel' => $channel, 'data' => $data]; + + if (!is_null($client)) { + $params['client'] = $client; + } + + return $this->send('publish', $params); + } + + /** + * Send message to centrifugo server. + * + * @param string $method + * @param array $params + * + * @return mixed + */ + protected function send($method, array $params = []) + { + try { + $result = $this->httpSend($method, $params); + } catch (Exception $e) { + $result = [ + 'method' => $method, + 'error' => $e->getMessage(), + 'body' => $params, + ]; + } + + return $result; + } + + /** + * Send message to centrifugo server from http client. + * + * @param string $method + * @param array $params + * + * @return mixed + */ + protected function httpSend($method, array $params = []) + { + $json = json_encode(['method' => $method, 'params' => $params]); + + $headers = [ + 'Content-type' => 'application/json', + 'Authorization' => 'apikey ' . collect($this->config)->get('api_key'), + ]; + + try { + $url = parse_url($this->prepareUrl()); + + $config = collect([ + 'headers' => $headers, + 'body' => $json, + 'http_errors' => false, + ]); + + if ($url['scheme'] == 'https') { + $config->put('verify', collect($this->config)->get('verify', false)); + + if (collect($this->config)->get('ssl_key')) { + $config->put('ssl_key', collect($this->config)->get('ssl_key')); + } + } + + $response = $this->httpClient->post($this->prepareUrl(), $config->toArray()); + + $finally = json_decode((string)$response->getBody(), true); + } catch (ClientException $e) { + throw $e; + } + + return $finally; + } + + /** + * Prepare URL to send the http request. + * + * @return string + */ + protected function prepareUrl() + { + $address = rtrim($this->config['url'], '/'); + + if (substr_compare($address, static::API_PATH, -strlen(static::API_PATH)) !== 0) { + $address .= static::API_PATH; + } + + return $address; + } + + /** + * Send message into multiple channel. + * + * @param array $channels + * @param array $data + * @param string $client + * + * @return mixed + */ + public function broadcast(array $channels, array $data, $client = null) + { + $params = ['channels' => $channels, 'data' => $data]; + + if (!is_null($client)) { + $params['client'] = $client; + } + + return $this->send('broadcast', $params); + } + + /** + * Get channel presence information (all clients currently subscribed on this channel). + * + * @param string $channel + * + * @return mixed + */ + public function presence($channel) + { + return $this->send('presence', ['channel' => $channel]); + } + + /** + * Get channel history information (list of last messages sent into channel). + * + * @param string $channel + * + * @return mixed + */ + public function history($channel) + { + return $this->send('history', ['channel' => $channel]); + } + + /** + * Unsubscribe user from channel. + * + * @param string $user_id + * @param string $channel + * + * @return mixed + */ + public function unsubscribe($user_id, $channel = null) + { + $params = ['user' => (string)$user_id]; + + if (!is_null($channel)) { + $params['channel'] = $channel; + } + + return $this->send('unsubscribe', $params); + } + + /** + * Disconnect user by its ID. + * + * @param string $user_id + * + * @return mixed + */ + public function disconnect($user_id) + { + return $this->send('disconnect', ['user' => (string)$user_id]); + } + + /** + * Get channels information (list of currently active channels). + * + * @return mixed + */ + public function channels() + { + return $this->send('channels'); + } + + /** + * Get stats information about running server nodes. + * + * @return mixed + */ + public function stats() + { + return $this->send('stats'); + } + + /** + * Generate api sign. + * + * @param string $data + * + * @return string + */ + public function generateApiSign($data) + { + $ctx = hash_init('sha256', HASH_HMAC, $this->getSecret()); + hash_update($ctx, (string)$data); + + return hash_final($ctx); + } + + /** + * Get secret key. + * + * @return string + */ + protected function getSecret() + { + return $this->config['secret']; + } + + /** + * Generate JWT token for client. + * + * @param string $userId + * + * @return string + */ + public function generateToken(string $userId) + { + $signer = new Sha256(); + $expiresAt = (new \DateTimeImmutable)->add(new \DateInterval("PT{$this->config['token_ttl']}S")); + + return (new Builder())->issuedBy($this->config['token_issuer']) + ->expiresAt($expiresAt) + ->set('sub', $userId) + ->getToken($signer, new Key($this->config['secret'])); + } +} diff --git a/src/CentrifugoBroadcaster.php b/src/CentrifugoBroadcaster.php new file mode 100644 index 0000000..409df36 --- /dev/null +++ b/src/CentrifugoBroadcaster.php @@ -0,0 +1,129 @@ +centrifugo = $centrifugo; + } + + /** + * Authenticate the incoming request for a given channel. + * + * @param Request $request + * + * @return mixed + */ + public function auth($request) + { + if ($request->user()) { + $client = $request->get('client', ''); + $channels = $request->get('channels', []); + $channels = is_array($channels) ? $channels : [$channels]; + + $response = []; + $info = json_encode([]); + + foreach ($channels as $channel) { + $channelName = (substr($channel, 0, 1) === '$') + ? substr($channel, 1) + : $channel; + + try { + $result = $this->verifyUserCanAccessChannel($request, $channelName); + } catch (HttpException $e) { + $result = false; + } + + $response[$channel] = $result ? [ + 'info' => $info, + ] : [ + 'status' => 403, + ]; + } + + return response()->json($response); + } else { + throw new HttpException(401); + } + } + + /** + * Return the valid authentication response. + * + * @param \Illuminate\Http\Request $request + * @param mixed $result + * + * @return mixed + */ + public function validAuthenticationResponse($request, $result) + { + return $result; + } + + /** + * Broadcast the given event. + * + * @param array $channels + * @param string $event + * @param array $payload + * + * @return void + */ + public function broadcast(array $channels, $event, array $payload = []) + { + $payload['event'] = $event; + + $socket = null; + + if (array_key_exists('socket', $payload)) { + $socket = $payload['socket']; + unset($payload['socket']); + } + + $response = $this->centrifugo->broadcast($this->formatChannels($channels), $payload, $socket); + + if (is_array($response) && empty($response) && !isset($response['error'])) { + return; + } + + if (isset($response['error'])) { + throw new BroadcastException( + $response['error'] instanceof Exception + ? $response['error']->getMessage() + : $response['error'] + ); + } + } + + /** + * Get the Centrifugo instance. + * + * @return CentrifugoContract + */ + public function getCentrifugo() + { + return $this->centrifugo; + } +} diff --git a/src/CentrifugoServiceProvider.php b/src/CentrifugoServiceProvider.php new file mode 100644 index 0000000..1797ae4 --- /dev/null +++ b/src/CentrifugoServiceProvider.php @@ -0,0 +1,40 @@ +extend('centrifugo', function ($app) { + return new CentrifugoBroadcaster($app->make('centrifugo')); + }); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->app->singleton('centrifugo', function ($app) { + $config = $app->make('config')->get('broadcasting.connections.centrifugo'); + $http = new Client(); + + return new Centrifugo($config, $http); + }); + + $this->app->alias('centrifugo', 'Emprove\Centrifugo\Centrifugo'); + $this->app->alias('centrifugo', 'Emprove\Centrifugo\Contracts\Centrifugo'); + } +} diff --git a/src/Contracts/Centrifuge.php b/src/Contracts/Centrifuge.php deleted file mode 100644 index 020629b..0000000 --- a/src/Contracts/Centrifuge.php +++ /dev/null @@ -1,97 +0,0 @@ -