Skip to content

Commit

Permalink
[1.x] Fixes incorrect user_count on presence channels (#129)
Browse files Browse the repository at this point in the history
* fix: presence channel users count + avoid duplication on getting presence users

* wip

* wip

* Update InteractsWithChannelInformation.php

---------

Co-authored-by: Joe Dixon <[email protected]>
Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
3 people authored Apr 4, 2024
1 parent 0b5e383 commit 5cd1453
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private function occupiedInfo(Channel $channel, array $info): array

return [
'occupied' => in_array('occupied', $info) ? $count > 0 : null,
'user_count' => in_array('user_count', $info) && $this->isPresenceChannel($channel) ? $count : null,
'user_count' => in_array('user_count', $info) && $this->isPresenceChannel($channel) ? $this->userCount($channel) : null,
'subscription_count' => in_array('subscription_count', $info) && ! $this->isPresenceChannel($channel) ? $count : null,
'cache' => in_array('cache', $info) && $this->isCacheChannel($channel) ? $channel->cachedPayload() : null,
];
Expand Down Expand Up @@ -79,4 +79,15 @@ protected function isCacheChannel(Channel $channel): bool
{
return $channel instanceof CacheChannel;
}

/**
* Get the number of unique users subscribed to the presence channel.
*/
protected function userCount(Channel $channel): int
{
return collect($channel->connections())
->map(fn ($connection) => $connection->data())
->unique('user_id')
->count();
}
}
1 change: 1 addition & 0 deletions src/Protocols/Pusher/MetricsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ protected function channelUsers(Application $application, array $options): array

return collect($channel->connections())
->map(fn ($connection) => $connection->data())
->unique('user_id')
->map(fn ($data) => ['id' => $data['user_id']])
->values()
->all();
Expand Down
22 changes: 22 additions & 0 deletions tests/Feature/Protocols/Pusher/Reverb/ChannelControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
expect($response->getBody()->getContents())->toBe('{"occupied":true,"subscription_count":1,"cache":{"some":"data"}}');
});

it('can return presence channel attributes', function () {
subscribe('presence-test-channel-one', ['id' => 123]);
subscribe('presence-test-channel-one', ['id' => 123]);

$response = await($this->signedRequest('channels/presence-test-channel-one?info=user_count,subscription_count,cache'));

expect($response->getStatusCode())->toBe(200);
expect($response->getBody()->getContents())->toBe('{"occupied":true,"user_count":1}');
});

it('can return only the requested attributes', function () {
subscribe('test-channel-one');

Expand Down Expand Up @@ -82,6 +92,18 @@
expect($response->getBody()->getContents())->toBe('{"occupied":true,"subscription_count":1,"cache":{"some":"data"}}');
});

it('can gather presence channel attributes', function () {
$this->usingRedis();

subscribe('presence-test-channel-one', ['id' => 123]);
subscribe('presence-test-channel-one', ['id' => 123]);

$response = await($this->signedRequest('channels/presence-test-channel-one?info=user_count,subscription_count,cache'));

expect($response->getStatusCode())->toBe(200);
expect($response->getBody()->getContents())->toBe('{"occupied":true,"user_count":1}');
});

it('can gather only the requested attributes', function () {
$this->usingRedis();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@
expect($response->getBody()->getContents())->toBe('{"users":[{"id":1},{"id":2},{"id":3}]}');
});

it('returns the unique user data', function () {
$channel = app(ChannelManager::class)
->for(app()->make(ApplicationProvider::class)->findByKey('reverb-key'))
->findOrCreate('presence-test-channel');
$channel->subscribe($connection = new FakeConnection('test-connection-one'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 3, 'user_info' => ['name' => 'Taylor']])), $data);
$channel->subscribe($connection = new FakeConnection('test-connection-two'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 2, 'user_info' => ['name' => 'Joe']])), $data);
$channel->subscribe($connection = new FakeConnection('test-connection-three'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 3, 'user_info' => ['name' => 'Jess']])), $data);

$response = await($this->signedRequest('channels/presence-test-channel/users'));

expect($response->getStatusCode())->toBe(200);
expect($response->getBody()->getContents())->toBe('{"users":[{"id":3},{"id":2}]}');
});

it('returns an error when gathering a non-existent presence channel', function () {
$this->usingRedis();

Expand Down Expand Up @@ -62,3 +76,19 @@
expect($response->getStatusCode())->toBe(200);
expect($response->getBody()->getContents())->toBe('{"users":[{"id":1},{"id":2},{"id":3}]}');
});

it('gathers the unique user data', function () {
$this->usingRedis();

$channel = app(ChannelManager::class)
->for(app()->make(ApplicationProvider::class)->findByKey('reverb-key'))
->findOrCreate('presence-test-channel');
$channel->subscribe($connection = new FakeConnection('test-connection-one'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 2, 'user_info' => ['name' => 'Taylor']])), $data);
$channel->subscribe($connection = new FakeConnection('test-connection-two'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 2, 'user_info' => ['name' => 'Joe']])), $data);
$channel->subscribe($connection = new FakeConnection('test-connection-three'), validAuth($connection->id(), 'presence-test-channel', $data = json_encode(['user_id' => 3, 'user_info' => ['name' => 'Jess']])), $data);

$response = await($this->signedRequest('channels/presence-test-channel/users'));

expect($response->getStatusCode())->toBe(200);
expect($response->getBody()->getContents())->toBe('{"users":[{"id":2},{"id":3}]}');
});

0 comments on commit 5cd1453

Please sign in to comment.