-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #55 from L1nkWave/feature/LWB-36_flex-broadcast-ma…
…nager feature/LWB-36_flex-broadcast-manager
- Loading branch information
Showing
14 changed files
with
492 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
backend/ws-server/src/main/java/org/linkwave/ws/websocket/routing/RoutingAutoConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
backend/ws-server/src/main/java/org/linkwave/ws/websocket/routing/bpp/Broadcasts.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.linkwave.ws.websocket.routing.bpp; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Container for {@link Broadcast} annotations in order to | ||
* support broadcast for different destinations. | ||
*/ | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface Broadcasts { | ||
|
||
Broadcast[] value() default {}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
...rc/main/java/org/linkwave/ws/websocket/routing/broadcast/BroadcastRepositoryResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.linkwave.ws.websocket.routing.broadcast; | ||
|
||
import org.linkwave.ws.websocket.routing.bpp.Broadcast; | ||
import org.springframework.lang.NonNull; | ||
|
||
import java.util.Set; | ||
|
||
/** | ||
* Defines which sessions should be retrieved that corresponds to<br/> | ||
* key-pattern set in {@link Broadcast#value()}. | ||
*/ | ||
public interface BroadcastRepositoryResolver { | ||
|
||
/** | ||
* Retrieves a set of sessions ids based on key-pattern. | ||
* @param broadcastKeyPattern key-pattern set in {@link Broadcast#value()} | ||
* @param resolvedKeyPattern key-pattern with resolved key variables | ||
* @return set of sessions ids that matched the specified criteria | ||
*/ | ||
Set<String> resolve(@NonNull String broadcastKeyPattern, @NonNull String resolvedKeyPattern); | ||
|
||
} |
67 changes: 67 additions & 0 deletions
67
...ain/java/org/linkwave/ws/websocket/routing/broadcast/BroadcastRepositoryResolverImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.linkwave.ws.websocket.routing.broadcast; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.linkwave.ws.repository.ChatRepository; | ||
import org.springframework.lang.NonNull; | ||
|
||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.function.BiFunction; | ||
|
||
import static org.linkwave.ws.utils.RouteUtils.isPathVariable; | ||
import static org.linkwave.ws.websocket.routing.broadcast.BroadcastManager.KEY_SEPARATOR; | ||
|
||
@RequiredArgsConstructor | ||
public class BroadcastRepositoryResolverImpl implements BroadcastRepositoryResolver { | ||
|
||
private final ChatRepository<Long, String> chatRepository; | ||
|
||
/** | ||
* If the field type seems a bit complicated, this is an example how this looks like: | ||
* <pre> {@code | ||
* return new BroadcastRepositoryResolverImpl( | ||
* Map.of( | ||
* "user:{}", SessionRepository::getUserSessions, | ||
* "chat:{}", ChatRepository::getSessions | ||
* ) | ||
* ); | ||
* }</pre> | ||
*/ | ||
private final Map< | ||
String, | ||
BiFunction<ChatRepository<Long, String>, String, Set<String>> | ||
> repositoryResolvers; | ||
|
||
@Override | ||
public Set<String> resolve(@NonNull String broadcastKeyPattern, @NonNull String resolvedKeyPattern) { | ||
Objects.requireNonNull(broadcastKeyPattern); | ||
Objects.requireNonNull(resolvedKeyPattern); | ||
|
||
if (broadcastKeyPattern.equals(resolvedKeyPattern)) { | ||
throw new IllegalArgumentException("Invalid broadcast keys"); | ||
} | ||
|
||
return repositoryResolvers | ||
.get(eraseKey(broadcastKeyPattern)) | ||
.apply(chatRepository, resolvedKeyPattern); | ||
} | ||
|
||
/** | ||
* Erases key variables names from passed key-pattern.<br/> | ||
* <b>Example:</b> For key-pattern {@code "chat:{id}"} it returns {@code "chat:{}"}. | ||
* | ||
* @param keyPattern non-null string that contains key pattern | ||
* @return key pattern without its variables names | ||
*/ | ||
@NonNull | ||
private String eraseKey(@NonNull String keyPattern) { | ||
final String[] components = keyPattern.trim().split(KEY_SEPARATOR); | ||
final var sb = new StringBuilder(); | ||
for (String part : components) { | ||
sb.append(isPathVariable(part) ? "{}" : part).append(KEY_SEPARATOR); | ||
} | ||
return sb.substring(0, sb.length() - 1); | ||
} | ||
|
||
} |
81 changes: 81 additions & 0 deletions
81
...erver/src/main/java/org/linkwave/ws/websocket/routing/broadcast/FlexBroadcastManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package org.linkwave.ws.websocket.routing.broadcast; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.linkwave.ws.repository.ChatRepository; | ||
import org.linkwave.ws.websocket.routing.bpp.Broadcast; | ||
import org.springframework.lang.NonNull; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import static java.util.function.Function.identity; | ||
import static java.util.stream.Collectors.toMap; | ||
|
||
@Slf4j | ||
public class FlexBroadcastManager extends SimpleBroadcastManager { | ||
|
||
private final BroadcastRepositoryResolver repositoryResolver; | ||
|
||
public FlexBroadcastManager(WebSocketMessageBroadcast messageBroadcast, | ||
ChatRepository<Long, String> chatRepository, | ||
BroadcastRepositoryResolver repositoryResolver) { | ||
super(messageBroadcast, chatRepository); | ||
this.repositoryResolver = repositoryResolver; | ||
} | ||
|
||
@Override | ||
public void process(@NonNull Method routeHandler, @NonNull Map<String, String> pathVariables, | ||
@NonNull Object message, @NonNull String serializedMessage) { | ||
|
||
// if it's necessary to broadcast message | ||
if (!isBroadcast(routeHandler)) { | ||
return; | ||
} | ||
|
||
log.debug("-> process(): routeHandler=[{}.{}]", | ||
routeHandler.getDeclaringClass().getSimpleName(), | ||
routeHandler.getName() | ||
); | ||
|
||
Broadcast[] broadcasts = routeHandler.getAnnotationsByType(Broadcast.class); | ||
|
||
if (broadcasts.length > 1) { | ||
// remove duplicate key-patterns | ||
final Map<String, Broadcast> broadcastMap = Arrays | ||
.stream(broadcasts) | ||
.collect(toMap(Broadcast::value, identity(), (b1, b2) -> b1)); | ||
|
||
if (broadcastMap.size() != broadcasts.length) { | ||
log.warn("-> process(): found duplicate key-patterns"); | ||
broadcasts = broadcastMap.values().toArray(new Broadcast[0]); | ||
} | ||
} | ||
|
||
for (Broadcast broadcastAnn : broadcasts) { | ||
|
||
final String broadcastKeyPattern = broadcastAnn.value(); | ||
final String resolveBroadcastKey = resolveKey( | ||
broadcastKeyPattern, | ||
pathVariables, | ||
broadcastAnn.analyzeMessage() ? message : null | ||
); | ||
|
||
// resolve sessions ids | ||
final Set<String> members = repositoryResolver.resolve(broadcastKeyPattern, resolveBroadcastKey); | ||
|
||
if (members.isEmpty()) { | ||
log.debug("-> process({}): sessions not found", broadcastKeyPattern); | ||
continue; | ||
} | ||
|
||
broadcast(broadcastAnn, members, serializedMessage); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isBroadcast(@NonNull Method routeHandler) { | ||
return routeHandler.getAnnotationsByType(Broadcast.class).length != 0; | ||
} | ||
} |
Oops, something went wrong.