Skip to content

Commit

Permalink
Merge pull request #309 from pusher/add_global_event_listner
Browse files Browse the repository at this point in the history
Add global event listner
  • Loading branch information
singhashmeet authored Nov 30, 2021
2 parents 7afdfde + 2414cc9 commit 80b1c8b
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 3 deletions.
51 changes: 51 additions & 0 deletions src/main/java/com/pusher/client/channel/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ public interface Channel {
*/
void bind(String eventName, SubscriptionEventListener listener);

/**
* Binds a {@link SubscriptionEventListener} to all events. The
* {@link SubscriptionEventListener} will be notified whenever an
* event is received on this channel.
*
* @param listener
* A listener to receive notifications when the event is
* received.
* @throws IllegalArgumentException
* If the {@link SubscriptionEventListener} is null.
* @throws IllegalStateException
* If the channel has been unsubscribed by calling
* {@link com.pusher.client.Pusher#unsubscribe(String)}. This
* puts the {@linkplain Channel} in a terminal state from which
* it can no longer be used. To resubscribe, call
* {@link com.pusher.client.Pusher#subscribe(String)} or
* {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)}
* again to receive a fresh {@linkplain Channel} instance.
*/
void bindGlobal(SubscriptionEventListener listener);

/**
* <p>
* Unbinds a previously bound {@link SubscriptionEventListener} from an
Expand Down Expand Up @@ -80,6 +101,36 @@ public interface Channel {
*/
void unbind(String eventName, SubscriptionEventListener listener);

/**
* <p>
* Unbinds a previously bound {@link SubscriptionEventListener} from global
* events. The {@link SubscriptionEventListener} will no longer be notified
* whenever the any event is received on this channel.
* </p>
*
* <p>
* Calling this method does not unsubscribe from the channel even if there
* are no more {@link SubscriptionEventListener}s bound to it. If you want
* to unsubscribe from the channel completely, call
* {@link com.pusher.client.Pusher#unsubscribe(String)}. It is not necessary
* to unbind your {@link SubscriptionEventListener}s first.
* </p>
*
* @param listener
* The listener to unbind from the event.
* @throws IllegalArgumentException
* If the {@link SubscriptionEventListener} is null.
* @throws IllegalStateException
* If the channel has been unsubscribed by calling
* {@link com.pusher.client.Pusher#unsubscribe(String)}. This
* puts the {@linkplain Channel} in a terminal state from which
* it can no longer be used. To resubscribe, call
* {@link com.pusher.client.Pusher#subscribe(String)} or
* {@link com.pusher.client.Pusher#subscribe(String, ChannelEventListener, String...)}
* again to receive a fresh {@linkplain Channel} instance.
*/
void unbindGlobal(SubscriptionEventListener listener);

/**
*
* @return Whether or not the channel is subscribed.
Expand Down
35 changes: 32 additions & 3 deletions src/main/java/com/pusher/client/channel/impl/ChannelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ChannelImpl implements InternalChannel {
private static final String INTERNAL_EVENT_PREFIX = "pusher_internal:";
protected static final String SUBSCRIPTION_SUCCESS_EVENT = "pusher_internal:subscription_succeeded";
protected final String name;
private Set<SubscriptionEventListener> globalListeners = new HashSet<SubscriptionEventListener>();
private final Map<String, Set<SubscriptionEventListener>> eventNameToListenerMap = new HashMap<String, Set<SubscriptionEventListener>>();
protected volatile ChannelState state = ChannelState.INITIAL;
private ChannelEventListener eventListener;
Expand Down Expand Up @@ -66,6 +67,15 @@ public void bind(final String eventName, final SubscriptionEventListener listene
}
}

@Override
public void bindGlobal(SubscriptionEventListener listener) {
validateArguments("", listener);

synchronized(lock) {
globalListeners.add(listener);
}
}

@Override
public void unbind(final String eventName, final SubscriptionEventListener listener) {

Expand All @@ -82,6 +92,17 @@ public void unbind(final String eventName, final SubscriptionEventListener liste
}
}

@Override
public void unbindGlobal(SubscriptionEventListener listener) {
validateArguments("", listener);

synchronized(lock) {
if (globalListeners != null) {
globalListeners.remove(listener);
}
}
}

@Override
public boolean isSubscribed() {
return state == ChannelState.SUBSCRIBED;
Expand Down Expand Up @@ -212,15 +233,23 @@ private void validateArguments(final String eventName, final SubscriptionEventLi

protected Set<SubscriptionEventListener> getInterestedListeners(String event) {
synchronized (lock) {

Set<SubscriptionEventListener> listeners = new HashSet<SubscriptionEventListener>();

final Set<SubscriptionEventListener> sharedListeners =
eventNameToListenerMap.get(event);

if (sharedListeners == null) {
if (sharedListeners != null ) {
listeners.addAll(sharedListeners);
}
if (!globalListeners.isEmpty()) {
listeners.addAll(globalListeners);
}

if (listeners.isEmpty()){
return null;
}

return new HashSet<>(sharedListeners);
return listeners;
}
}
}
18 changes: 18 additions & 0 deletions src/test/java/com/pusher/client/channel/impl/ChannelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListener() {
assertEquals("{\"fish\":\"chips\"}", argCaptor.getValue().getData());
}
@Test
public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() {
channel.bindGlobal(mockListener);
channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}");

verify(mockListener, times(1)).onEvent(argCaptor.capture());
assertEquals("event1", argCaptor.getValue().getEventName());
assertEquals("{\"fish\":\"chips\"}", argCaptor.getValue().getData());
}
@Test
public void testDataIsExtractedFromMessageAndPassedToMultipleListeners() {
final ChannelEventListener mockListener2 = getEventListener();

Expand Down Expand Up @@ -154,6 +163,15 @@ public void testEventIsNotPassedOnIfListenerHasUnboundFromEvent() {

verify(mockListener, never()).onEvent(any(PusherEvent.class));
}
@Test
public void testEventIsNotPassedOnIfListenerHasUnboundFromGlobalEvent() {

channel.bindGlobal(mockListener);
channel.unbindGlobal(mockListener);
channel.onMessage(EVENT_NAME, "{\"event\":\"event1\",\"data\":\"{\\\"fish\\\":\\\"chips\\\"}\"}");

verify(mockListener, never()).onEvent(any(PusherEvent.class));
}

@Test(expected = IllegalArgumentException.class)
public void testBindWithNullEventNameThrowsException() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,36 @@ public void testDataIsExtractedFromMessageAndPassedToSingleListener() {
assertEquals("{\"message\":\"hello world\"}", argCaptor.getValue().getData());
}

@Test
public void testDataIsExtractedFromMessageAndPassedToSingleListenerGlobalEvent() {
PrivateEncryptedChannelImpl channel = new PrivateEncryptedChannelImpl(
mockInternalConnection,
getChannelName(),
mockAuthorizer,
factory,
mockSecretBoxOpenerFactory);

when(mockAuthorizer.authorize(Matchers.anyString(), Matchers.anyString()))
.thenReturn(AUTH_RESPONSE);
when(mockSecretBoxOpenerFactory.create(any()))
.thenReturn(new SecretBoxOpener(Base64.decode(SHARED_SECRET)));

channel.toSubscribeMessage();

PrivateEncryptedChannelEventListener mockListener = mock(PrivateEncryptedChannelEventListener.class);

channel.bindGlobal(mockListener);

channel.onMessage("my-event", "{\"event\":\"event1\",\"data\":\"{" +
"\\\"nonce\\\": \\\"4sVYwy4j/8dCcjyxtPCWyk19GaaViaW9\\\"," +
"\\\"ciphertext\\\": \\\"/GMESnFGlbNn01BuBjp31XYa3i9vZsGKR8fgR9EDhXKx3lzGiUD501A=\\\"" +
"}\"}");

verify(mockListener, times(1)).onEvent(argCaptor.capture());
assertEquals("event1", argCaptor.getValue().getEventName());
assertEquals("{\"message\":\"hello world\"}", argCaptor.getValue().getData());
}

@Test
public void testDataIsExtractedFromMessageAndPassedToMultipleListeners() {
PrivateEncryptedChannelImpl channel = new PrivateEncryptedChannelImpl(
Expand Down

0 comments on commit 80b1c8b

Please sign in to comment.