multi types
This commit is contained in:
parent
4c6b969f5d
commit
a2dc0fd6ae
@ -1,34 +0,0 @@
|
|||||||
package dev.struchkov.example;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import jakarta.websocket.DecodeException;
|
|
||||||
import jakarta.websocket.Decoder;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
public class ChatMessageDecoder implements Decoder.Text<ChatInputMessage> {
|
|
||||||
|
|
||||||
private final ObjectMapper jackson = ChatMessageDecoder.getJackson();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public ChatInputMessage decode(String s) throws DecodeException {
|
|
||||||
return jackson.readValue(s, ChatInputMessage.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean willDecode(String s) {
|
|
||||||
return s != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ObjectMapper getJackson() {
|
|
||||||
ObjectMapper om = new ObjectMapper();
|
|
||||||
om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
|
||||||
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
|
||||||
om.registerModule(new JavaTimeModule());
|
|
||||||
return om;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package dev.struchkov.example;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import jakarta.websocket.EncodeException;
|
|
||||||
import jakarta.websocket.Encoder;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
public class ChatMessageEncoder implements Encoder.Text<ChatOutputMessage> {
|
|
||||||
|
|
||||||
private final ObjectMapper jackson = ChatMessageDecoder.getJackson();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public String encode(ChatOutputMessage chatOutputMessage) throws EncodeException {
|
|
||||||
return jackson.writeValueAsString(chatOutputMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package dev.struchkov.example;
|
|
||||||
|
|
||||||
import io.smallrye.config.ConfigMapping;
|
|
||||||
import io.smallrye.config.WithName;
|
|
||||||
|
|
||||||
@ConfigMapping(prefix = "greeting")
|
|
||||||
public interface GreetingConfig {
|
|
||||||
|
|
||||||
@WithName("message")
|
|
||||||
String message();
|
|
||||||
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package dev.struchkov.example;
|
|
||||||
|
|
||||||
import org.eclipse.microprofile.graphql.DefaultValue;
|
|
||||||
import org.eclipse.microprofile.graphql.Description;
|
|
||||||
import org.eclipse.microprofile.graphql.GraphQLApi;
|
|
||||||
import org.eclipse.microprofile.graphql.Query;
|
|
||||||
|
|
||||||
@GraphQLApi
|
|
||||||
public class HelloGraphQLResource {
|
|
||||||
|
|
||||||
@Query
|
|
||||||
@Description("Say hello")
|
|
||||||
public String sayHello(@DefaultValue("World") String name) {
|
|
||||||
return "Hello " + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,12 @@
|
|||||||
package dev.struchkov.example;
|
package dev.struchkov.example;
|
||||||
|
|
||||||
|
import dev.struchkov.example.convert.EventContainerDecoder;
|
||||||
|
import dev.struchkov.example.convert.EventContainerEncoder;
|
||||||
|
import dev.struchkov.example.domain.EventContainer;
|
||||||
|
import dev.struchkov.example.domain.input.ChatInputMessage;
|
||||||
|
import dev.struchkov.example.domain.input.ChatViewInput;
|
||||||
|
import dev.struchkov.example.domain.output.ChatOutputMessage;
|
||||||
|
import dev.struchkov.example.domain.output.ChatViewOutput;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.websocket.OnClose;
|
import jakarta.websocket.OnClose;
|
||||||
import jakarta.websocket.OnError;
|
import jakarta.websocket.OnError;
|
||||||
@ -10,6 +17,7 @@ import jakarta.websocket.server.PathParam;
|
|||||||
import jakarta.websocket.server.ServerEndpoint;
|
import jakarta.websocket.server.ServerEndpoint;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -20,11 +28,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
@ServerEndpoint(
|
@ServerEndpoint(
|
||||||
value = "/chat/{chatId}",
|
value = "/chat/{chatId}",
|
||||||
decoders = ChatMessageDecoder.class,
|
decoders = EventContainerDecoder.class,
|
||||||
encoders = ChatMessageEncoder.class
|
encoders = EventContainerEncoder.class
|
||||||
)
|
)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class StartWebSocket {
|
public class WebSocket {
|
||||||
|
|
||||||
public static final ThreadLocal<UUID> CURRENT_USER = new ThreadLocal<>();
|
public static final ThreadLocal<UUID> CURRENT_USER = new ThreadLocal<>();
|
||||||
private final Map<String, List<Session>> sessions = new ConcurrentHashMap<>();
|
private final Map<String, List<Session>> sessions = new ConcurrentHashMap<>();
|
||||||
@ -47,9 +55,30 @@ public class StartWebSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OnMessage
|
@OnMessage
|
||||||
public void onMessage(Session session, @PathParam("chatId") String chatId, ChatInputMessage message) {
|
public void onMessage(Session session, @PathParam("chatId") String chatId, EventContainer event) {
|
||||||
System.out.println("onMessage> " + chatId + ": " + message);
|
System.out.println("onMessage> " + chatId + ": " + event);
|
||||||
sendMessage(session, chatId, message);
|
switch (event.getEventType()) {
|
||||||
|
case MESSAGE_NEW -> sendMessage(session, chatId, (ChatInputMessage) event.getEvent());
|
||||||
|
case MESSAGE_VIEWED -> viewMessage(session, chatId, (ChatViewInput) event.getEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void viewMessage(Session session, String chatId, ChatViewInput viewInput) {
|
||||||
|
final List<Session> chatSessions = sessions.get(chatId);
|
||||||
|
for (Session chatSession : chatSessions) {
|
||||||
|
if (session.getId().equals(chatSession.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final UUID fromUserId = CURRENT_USER.get();
|
||||||
|
final ChatViewOutput chatViewOutput = new ChatViewOutput(
|
||||||
|
viewInput.getMessageId(),
|
||||||
|
fromUserId,
|
||||||
|
LocalDateTime.now()
|
||||||
|
);
|
||||||
|
final EventContainer eventContainer = EventContainer.viewedOutput(chatViewOutput);
|
||||||
|
chatSession.getAsyncRemote().sendObject(eventContainer);
|
||||||
|
CURRENT_USER.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(Session session, String chatId, ChatInputMessage message) {
|
private void sendMessage(Session session, String chatId, ChatInputMessage message) {
|
||||||
@ -60,7 +89,8 @@ public class StartWebSocket {
|
|||||||
}
|
}
|
||||||
final UUID fromUserId = CURRENT_USER.get();
|
final UUID fromUserId = CURRENT_USER.get();
|
||||||
final ChatOutputMessage outputMessage = new ChatOutputMessage(fromUserId, message.getText());
|
final ChatOutputMessage outputMessage = new ChatOutputMessage(fromUserId, message.getText());
|
||||||
chatSession.getAsyncRemote().sendObject(outputMessage);
|
final EventContainer eventContainer = EventContainer.messageOutput(outputMessage);
|
||||||
|
chatSession.getAsyncRemote().sendObject(eventContainer);
|
||||||
CURRENT_USER.remove();
|
CURRENT_USER.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package dev.struchkov.example.convert;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import dev.struchkov.example.domain.EventContainer;
|
||||||
|
import dev.struchkov.example.domain.EventType;
|
||||||
|
import dev.struchkov.example.domain.input.ChatInputMessage;
|
||||||
|
import dev.struchkov.example.domain.input.ChatViewInput;
|
||||||
|
import jakarta.websocket.DecodeException;
|
||||||
|
import jakarta.websocket.Decoder;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
public class EventContainerDecoder implements Decoder.Text<EventContainer> {
|
||||||
|
|
||||||
|
private final ObjectMapper jackson = EventContainerDecoder.getJackson();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public EventContainer decode(String s) throws DecodeException {
|
||||||
|
final String eventType = jackson.readTree(s).get("eventType").asText();
|
||||||
|
final JsonNode event = jackson.readTree(s).get("event");
|
||||||
|
return switch (EventType.valueOf(eventType)) {
|
||||||
|
case MESSAGE_NEW -> EventContainer.messageInput(jackson.treeToValue(event, ChatInputMessage.class));
|
||||||
|
case MESSAGE_VIEWED -> EventContainer.viewInput(jackson.treeToValue(event, ChatViewInput.class));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean willDecode(String s) {
|
||||||
|
return s != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectMapper getJackson() {
|
||||||
|
ObjectMapper om = new ObjectMapper();
|
||||||
|
om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||||
|
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||||
|
om.registerModule(new JavaTimeModule());
|
||||||
|
return om;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package dev.struchkov.example.convert;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import dev.struchkov.example.domain.EventContainer;
|
||||||
|
import jakarta.websocket.EncodeException;
|
||||||
|
import jakarta.websocket.Encoder;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
public class EventContainerEncoder implements Encoder.Text<EventContainer> {
|
||||||
|
|
||||||
|
private final ObjectMapper jackson = EventContainerDecoder.getJackson();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public String encode(EventContainer eventContainer) throws EncodeException {
|
||||||
|
return jackson.writeValueAsString(eventContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package dev.struchkov.example.domain;
|
||||||
|
|
||||||
|
import dev.struchkov.example.domain.input.ChatInputMessage;
|
||||||
|
import dev.struchkov.example.domain.input.ChatViewInput;
|
||||||
|
import dev.struchkov.example.domain.output.ChatOutputMessage;
|
||||||
|
import dev.struchkov.example.domain.output.ChatViewOutput;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class EventContainer {
|
||||||
|
|
||||||
|
private EventType eventType;
|
||||||
|
private Object event;
|
||||||
|
|
||||||
|
public static EventContainer messageInput(ChatInputMessage chatInputMessage) {
|
||||||
|
return EventContainer.builder()
|
||||||
|
.eventType(EventType.MESSAGE_NEW)
|
||||||
|
.event(chatInputMessage)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventContainer viewInput(ChatViewInput chatViewInput) {
|
||||||
|
return EventContainer.builder()
|
||||||
|
.eventType(EventType.MESSAGE_VIEWED)
|
||||||
|
.event(chatViewInput)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventContainer viewedOutput(ChatViewOutput chatViewOutput) {
|
||||||
|
return EventContainer.builder()
|
||||||
|
.eventType(EventType.MESSAGE_VIEWED)
|
||||||
|
.event(chatViewOutput)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventContainer messageOutput(ChatOutputMessage chatOutputMessage) {
|
||||||
|
return EventContainer.builder()
|
||||||
|
.eventType(EventType.MESSAGE_NEW)
|
||||||
|
.event(chatOutputMessage)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package dev.struchkov.example.domain;
|
||||||
|
|
||||||
|
public enum EventType {
|
||||||
|
|
||||||
|
MESSAGE_NEW, MESSAGE_VIEWED
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package dev.struchkov.example;
|
package dev.struchkov.example.domain.input;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
@ -0,0 +1,14 @@
|
|||||||
|
package dev.struchkov.example.domain.input;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ChatViewInput {
|
||||||
|
|
||||||
|
private UUID messageId;
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package dev.struchkov.example;
|
package dev.struchkov.example.domain.output;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
@ -0,0 +1,21 @@
|
|||||||
|
package dev.struchkov.example.domain.output;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ChatViewOutput {
|
||||||
|
|
||||||
|
private UUID messageId;
|
||||||
|
private UUID chatMemberId;
|
||||||
|
private LocalDateTime dateRead;
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package dev.struchkov.example;
|
package dev.struchkov.example.filter;
|
||||||
|
|
||||||
|
import dev.struchkov.example.WebSocket;
|
||||||
import io.quarkus.vertx.web.RouteFilter;
|
import io.quarkus.vertx.web.RouteFilter;
|
||||||
import io.vertx.core.http.Cookie;
|
import io.vertx.core.http.Cookie;
|
||||||
import io.vertx.core.http.HttpServerRequest;
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
@ -39,10 +40,10 @@ public class WebsocketAuthFilter {
|
|||||||
private boolean authLogic(String sessionId) {
|
private boolean authLogic(String sessionId) {
|
||||||
// your auth logic here
|
// your auth logic here
|
||||||
if (sessionId.equals("user1")) {
|
if (sessionId.equals("user1")) {
|
||||||
StartWebSocket.CURRENT_USER.set(UUID.fromString("09e429de-a302-40b6-9d10-6b113ab9e89d"));
|
WebSocket.CURRENT_USER.set(UUID.fromString("09e429de-a302-40b6-9d10-6b113ab9e89d"));
|
||||||
return true;
|
return true;
|
||||||
} else if (sessionId.equals("user2")) {
|
} else if (sessionId.equals("user2")) {
|
||||||
StartWebSocket.CURRENT_USER.set(UUID.fromString("f84dbae1-f9a9-4c37-8922-4eb207103676"));
|
WebSocket.CURRENT_USER.set(UUID.fromString("f84dbae1-f9a9-4c37-8922-4eb207103676"));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
Loading…
Reference in New Issue
Block a user