I am currently building a chat application with spring reactive.
Each user can be part of multiple chat rooms.
I am trying to only send each chat message to clients connected to the corresponding rooms.
For example, if a user sends a message in the chat room with UUID "32e4adff-d0bd-4496-ae40-0e799eeb5fe7", only clients connected to the socket with endpoint "/chat/32e4adff-d0bd-4496-ae40-0e799eeb5fe7" will receive the message.
Currently, my websocket handler mapping is :
@Bean
public HandlerMapping webSocketHandlerMapping() {
String path = "/chat/*";
Map<String, WebSocketHandler> map = Map.of(path, webSocketHandler);
return new SimpleUrlHandlerMapping(map, -1);
}
And my ChatSocketHandler :
@Component
public class ChatSocketHandler implements WebSocketHandler {
private final ObjectMapper mapper = new ObjectMapper();
private Sinks.Many<ChatMessage> sinks = Sinks.many().multicast().directBestEffort();
private Flux<ChatMessage> flux = sinks.asFlux();
private final Sinks.EmitFailureHandler emitFailureHandler =
(signalType, emitResult) -> emitResult.equals(Sinks.EmitResult.FAIL_NON_SERIALIZED);
private final ChatService chatService;
@Autowired
public ChatSocketHandler(ChatService chatService) {
this.chatService = chatService;
}
@Override
public Mono<Void> handle(WebSocketSession session) {
// TODO get rid of subscribe
session
.receive()
.map(
webSocketMessage -> {
try {
return mapper.readValue(webSocketMessage.getPayloadAsText(), ChatMessage.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
return new ChatMessage();
}
})
.flatMap(chatService::sendMessage)
.subscribe(webSocketMessage -> sinks.emitNext(webSocketMessage, emitFailureHandler));
return session.send(
Mono.delay(Duration.ofMillis(100))
.thenMany(flux.map(it -> session.textMessage(toJson(it)))));
}
private String toJson(ChatMessage object) {
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
And chat service function to send a message :
public Mono<ChatMessage> sendMessage(ChatMessage chatMessage) {
return chatMessageRepository.insert(chatMessage);
}
For now, clients receive messages for all rooms, event the one they are not supposed to be connected to.
How to configure my websocket so that only users connected to a room receive the messages published there ?