multi types

This commit is contained in:
Struchkov Mark 2023-06-04 23:00:06 +03:00
parent 4c6b969f5d
commit a2dc0fd6ae
Signed by: upagge
GPG Key ID: D3018BE7BA428CA6
14 changed files with 202 additions and 93 deletions

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
} }
} }

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,7 @@
package dev.struchkov.example.domain;
public enum EventType {
MESSAGE_NEW, MESSAGE_VIEWED
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;