Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agent header support #7

Merged
merged 11 commits into from
Oct 31, 2022
68 changes: 36 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

_[Ably](https://ably.com) is the platform that powers synchronized digital experiences in realtime. Whether attending an event in a virtual venue, receiving realtime financial information, or monitoring live car performance data – consumers simply expect realtime digital experiences as standard. Ably provides a suite of APIs to build, extend, and deliver powerful digital experiences in realtime for more than 250 million devices across 80 countries each month. Organizations like Bloomberg, HubSpot, Verizon, and Hopin depend on Ably’s platform to offload the growing complexity of business-critical realtime data synchronization at global scale. For more information, see the [Ably documentation](https://ably.com/docs)._

This implements ably broadcaster as a independent service provider library for [Laravel](https://laravel.com/) using [ably-php](https://github.com/ably/ably-php). This library works with [ably-js](https://github.com/ably/ably-js) based [ably-laravel-echo](https://github.com/ably-forks/echo) framework having enhanced features at client side. Main aim is to replace old [pusher-client based ably broadcaster](https://laravel.com/docs/9.x/broadcasting#client-ably).
This implements ably broadcaster as a independent service provider library for [Laravel](https://laravel.com/) using [ably-php](https://github.com/ably/ably-php). This library works with the [ably-js](https://github.com/ably/ably-js) based [ably-laravel-echo](https://github.com/ably-forks/echo) client framework with enhanced features. This project is the successor to the [pusher-client based ably broadcaster](https://laravel.com/docs/9.x/broadcasting#client-ably).

## Features
- Native ably-js support.
- Low latency for client-events.
- Disable public channels.
- Update channel permissions for a user.
- Update token expirty.
- Fully compatible with [pusher/pusher-based](https://laravel.com/docs/9.x/broadcasting#client-ably) broadcasters, see [migrating section](#migrating-from-old-ablybroadcaster)

## Bug Fixes
- Fixes [broadcasting events to others](https://faqs.ably.com/why-isnt-the-broadcast-only-to-others-functionality-working-in-laravel-with-the-ably-broadcaster).
Expand All @@ -37,8 +38,6 @@ composer require ably/laravel-broadcaster
```dotenv
BROADCAST_DRIVER=ably
ABLY_KEY=ROOT_API_KEY_COPIED_FROM_ABLY_WEB_DASHBOARD
ABLY_DISABLE_PUBLIC_CHANNELS=false // optional, default : false
ABLY_TOKEN_EXPIRY=3600 // optional, default : 3600 seconds
```

2. Uncomment `BroadcastServiceProvider` in `config/app.php`
Expand All @@ -53,22 +52,14 @@ ABLY_TOKEN_EXPIRY=3600 // optional, default : 3600 seconds
App\Providers\RouteServiceProvider::class,
</pre>

4. If running Laravel 8 or older, edit `config/broadcasting.php`, set following env. variables in the `connections` array
4. If running Laravel 8 or older, edit `config/broadcasting.php`, add `ably` section to the `connections` array
```php
'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
'disable_public_channels' => env('ABLY_DISABLE_PUBLIC_CHANNELS', false),
'token_expiry' => env('ABLY_TOKEN_EXPIRY', 3600)
'key' => env('ABLY_KEY')
],
```

5. For Laravel 9, edit `config/broadcasting.php`, set following env. variables in the `connections->ably` array
```php
'disable_public_channels' => env('ABLY_DISABLE_PUBLIC_CHANNELS', false),
'token_expiry' => env('ABLY_TOKEN_EXPIRY', 3600)
```

Finally, you are ready to install and configure [Ably Laravel Echo](https://github.com/ably-forks/echo/), which will receive the broadcast events on the client-side.

## Using Laravel Echo on client-side
Expand Down Expand Up @@ -114,11 +105,7 @@ npm run dev

## Configure advanced features

**1. Update token expiry. Default: 3600 seconds (1 hr)**
- Update `ABLY_TOKEN_EXPIRY` in `.env` file.
- Update `ably` section under `config/broadcasting.php` with `'token_expiry' => env('ABLY_TOKEN_EXPIRY', 3600)`

**2. Modify channel capability**
**1. Modify private/presence channel capability. Default: Full capability**
- Channel access can be changed as per [Channel Capabilities](https://ably.com/docs/core-features/authentication#capability-operations)
```php
// file - routes/channels.php
Expand All @@ -134,24 +121,40 @@ npm run dev
});
```

**3. Disable public channels**
**2. Disable public channels. Default: false**
- Update `ABLY_DISABLE_PUBLIC_CHANNELS`, set as **true** in `.env` file.
- Update `ably` section under `config/broadcasting.php` with `'disable_public_channels' => env('ABLY_DISABLE_PUBLIC_CHANNELS', false)`

**3. Update token expiry. Default: 3600 seconds (1 hr)**
- Update `ABLY_TOKEN_EXPIRY` in `.env` file.
- Update `ably` section under `config/broadcasting.php` with `'token_expiry' => env('ABLY_TOKEN_EXPIRY', 3600)`

<a name="migrate-pusher-to-ably"></a>
## Migrating from old AblyBroadcaster
- The current Ably broadcaster is fully compatible with the old Pusher based AblyBroadcaster.
- The only difference is for **Leaving the channel**, you should use [Ably Channel Namespaces](https://ably.com/docs/general/channel-rules-namespaces) conventions
```js
Echo.channel('channel1').leaveChannel("public:channel1")
Echo.private('channel2').leaveChannel("private:channel2")
Echo.join('channel3').leaveChannel("presence:channel3")
// public channel
Echo.channel('channel1');
Echo.leaveChannel("public:channel1");
// private channel
Echo.private('channel2');
Echo.leaveChannel("private:channel2")
// presence channel
Echo.join('channel3');
Echo.leaveChannel("presence:channel3")
```
instead of [Pusher Channel Conventions](https://pusher.com/docs/channels/using_channels/channels/#channel-types)
```js
Echo.channel('channel1').leaveChannel("channel1")
Echo.private('channel2').leaveChannel("private-channel2")
Echo.join('channel3').leaveChannel("presence-channel3")
// public channel
Echo.channel('channel1');
Echo.leaveChannel("channel1");
// private channel
Echo.private('channel2');
Echo.leaveChannel("private-channel2")
// presence channel
Echo.join('channel3');
Echo.leaveChannel("presence-channel3")
```

## Addtional Documentation
Expand Down Expand Up @@ -186,10 +189,11 @@ Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recen
This library uses [semantic versioning](http://semver.org/). For each release, the following needs to be done:

1. Create a new branch for the release, named like `release/1.2.4` (where `1.2.4` is what you're releasing, being the new version)
2. Run [`github_changelog_generator`](https://github.com/skywinder/Github-Changelog-Generator) to automate the update of the [CHANGELOG](./CHANGELOG.md). Once the `CHANGELOG` update has completed, manually change the `Unreleased` heading and link with the current version number such as `1.2.4`. Also ensure that the `Full Changelog` link points to the new version tag instead of the `HEAD`.
3. Commit generated [CHANGELOG.md](./CHANGELOG.md) file.
4. Make a PR against `main`.
5. Once the PR is approved, merge it into `main`.
6. Add a tag and push it to origin - e.g.: `git tag v1.2.4 && git push origin v1.2.4`.
7. Visit https://github.com/ably/laravel-broadcaster/tags and add release notes for the release including links to the changelog entry.
8. Visit https://packagist.org/packages/ably/laravel-broadcaster, log in to Packagist, and click the "Update" button.
2. Update the lib version in `src/AblyBroadcaster.php`
3. Run [`github_changelog_generator`](https://github.com/skywinder/Github-Changelog-Generator) to automate the update of the [CHANGELOG](./CHANGELOG.md). Once the `CHANGELOG` update has completed, manually change the `Unreleased` heading and link with the current version number such as `1.2.4`. Also ensure that the `Full Changelog` link points to the new version tag instead of the `HEAD`.
4. Commit generated [CHANGELOG.md](./CHANGELOG.md) file.
5. Make a PR against `main`.
6. Once the PR is approved, merge it into `main`.
7. Add a tag and push it to origin - e.g.: `git tag v1.2.4 && git push origin v1.2.4`.
8. Visit https://github.com/ably/laravel-broadcaster/tags and add release notes for the release including links to the changelog entry.
9. Visit https://packagist.org/packages/ably/laravel-broadcaster, log in to Packagist, and click the "Update" button.
2 changes: 2 additions & 0 deletions src/AblyBroadcaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

class AblyBroadcaster extends Broadcaster
{
const LIB_VERSION = '1.0.0';

/**
* The AblyRest SDK instance.
*
Expand Down
1 change: 1 addition & 0 deletions src/LaravelAblyBroadcasterServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class LaravelAblyBroadcasterServiceProvider extends ServiceProvider
public function boot()
{
Broadcast::extend('ably', function ($broadcasting, $config) {
AblyRest::setAblyAgentHeader('laravel-broadcaster', AblyBroadcaster::LIB_VERSION);
return new AblyBroadcaster(new AblyRest($config), $config);
});
}
Expand Down
32 changes: 32 additions & 0 deletions tests/AblyBroadcasterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Ably\LaravelBroadcaster\Tests;

use Ably\AblyRest;
use Ably\Http;
use Ably\LaravelBroadcaster\AblyBroadcaster;
use Ably\LaravelBroadcaster\Utils;
use Ably\Utils\Miscellaneous;
use Illuminate\Http\Request;
use Mockery as m;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -325,4 +327,34 @@ protected function getMockRequestWithoutUserForChannel($channel, $token)

return $request;
}

public function testLaravelAblyAgentHeader()
{
$ably = (new AblyFactory())->make([
'key' => 'abcd:efgh',
'httpClass' => 'Ably\LaravelBroadcaster\Tests\HttpMock',
]);
$ably->time();
$expectedLaravelHeader = 'ably-php/'.\Ably\Defaults::LIB_VERSION.' '.'php/'.Miscellaneous::getNumeric(phpversion()).' laravel-broadcaster/'. AblyBroadcaster::LIB_VERSION;
$this->assertcontains( 'Ably-Agent: '.$expectedLaravelHeader, $ably->http->lastHeaders, 'Expected Laravel broadcaster header in HTTP request' );
}
}


class HttpMock extends Http
{
public $lastUrl;
public $lastHeaders;

public function request($method, $url, $headers = array(), $params = array())
{
$this->lastUrl = $url;
$this->lastHeaders = $headers;

// mock response to /time
return array(
'headers' => "HTTP/1.1 200 OK\n",
'body' => array(round(microtime(true) * 1000 ), 0),
);
}
}
37 changes: 37 additions & 0 deletions tests/AblyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
namespace Ably\LaravelBroadcaster\Tests;

use Ably\AblyRest;
use Ably\LaravelBroadcaster\AblyBroadcaster;

/**
* Instantiates AblyRest objects
*/
class AblyFactory
{
/**
* Make a new AblyRest client
*
* @param array|null $clientOptions Options for the created instance
*
* @return \Ably\AblyRest
*/
public function make($clientOptions)
{
return $this->createInstance($clientOptions);
}

/**
* Creates a new AblyRest instance
*
* @param array|null $clientOptions
*
* @return \Ably\AblyRest
* @throws \Ably\Exceptions\AblyException
*/
protected function createInstance($clientOptions)
{
AblyRest::setAblyAgentHeader('laravel-broadcaster', AblyBroadcaster::LIB_VERSION);
return new AblyRest($clientOptions);
}
}