forked from Qortal/qortal
Rework ApiWebSocket so it can manage sessions and in readiness to conversion from "notifiers" to event-bus
This commit is contained in:
parent
ce5cf87094
commit
d507383487
@ -10,7 +10,6 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||||
import org.qortal.controller.ChatNotifier;
|
import org.qortal.controller.ChatNotifier;
|
||||||
import org.qortal.crypto.Crypto;
|
import org.qortal.crypto.Crypto;
|
||||||
@ -22,7 +21,7 @@ import org.qortal.repository.RepositoryManager;
|
|||||||
|
|
||||||
@WebSocket
|
@WebSocket
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class ActiveChatsWebSocket extends WebSocketServlet implements ApiWebSocket {
|
public class ActiveChatsWebSocket extends ApiWebSocket {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSocketServletFactory factory) {
|
public void configure(WebSocketServletFactory factory) {
|
||||||
@ -31,7 +30,7 @@ public class ActiveChatsWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
|
|
||||||
@OnWebSocketConnect
|
@OnWebSocketConnect
|
||||||
public void onWebSocketConnect(Session session) {
|
public void onWebSocketConnect(Session session) {
|
||||||
Map<String, String> pathParams = this.getPathParams(session, "/{address}");
|
Map<String, String> pathParams = getPathParams(session, "/{address}");
|
||||||
|
|
||||||
String address = pathParams.get("address");
|
String address = pathParams.get("address");
|
||||||
if (address == null || !Crypto.isValidAddress(address)) {
|
if (address == null || !Crypto.isValidAddress(address)) {
|
||||||
@ -70,7 +69,7 @@ public class ActiveChatsWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
|
||||||
this.marshall(stringWriter, activeChats);
|
marshall(stringWriter, activeChats);
|
||||||
|
|
||||||
// Only output if something has changed
|
// Only output if something has changed
|
||||||
String output = stringWriter.toString();
|
String output = stringWriter.toString();
|
||||||
|
@ -9,7 +9,6 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||||
import org.qortal.api.model.NodeStatus;
|
import org.qortal.api.model.NodeStatus;
|
||||||
import org.qortal.controller.StatusNotifier;
|
import org.qortal.controller.StatusNotifier;
|
||||||
@ -19,7 +18,7 @@ import org.qortal.repository.RepositoryManager;
|
|||||||
|
|
||||||
@WebSocket
|
@WebSocket
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class AdminStatusWebSocket extends WebSocketServlet implements ApiWebSocket {
|
public class AdminStatusWebSocket extends ApiWebSocket {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSocketServletFactory factory) {
|
public void configure(WebSocketServletFactory factory) {
|
||||||
@ -51,7 +50,7 @@ public class AdminStatusWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
|
||||||
this.marshall(stringWriter, nodeStatus);
|
marshall(stringWriter, nodeStatus);
|
||||||
|
|
||||||
// Only output if something has changed
|
// Only output if something has changed
|
||||||
String output = stringWriter.toString();
|
String output = stringWriter.toString();
|
||||||
|
@ -3,7 +3,10 @@ package org.qortal.api.websocket;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
@ -13,24 +16,28 @@ import javax.xml.bind.Marshaller;
|
|||||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||||
|
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||||
import org.eclipse.persistence.jaxb.JAXBContextFactory;
|
import org.eclipse.persistence.jaxb.JAXBContextFactory;
|
||||||
import org.eclipse.persistence.jaxb.MarshallerProperties;
|
import org.eclipse.persistence.jaxb.MarshallerProperties;
|
||||||
import org.qortal.api.ApiError;
|
import org.qortal.api.ApiError;
|
||||||
import org.qortal.api.ApiErrorRoot;
|
import org.qortal.api.ApiErrorRoot;
|
||||||
|
|
||||||
interface ApiWebSocket {
|
@SuppressWarnings("serial")
|
||||||
|
abstract class ApiWebSocket extends WebSocketServlet {
|
||||||
|
|
||||||
default String getPathInfo(Session session) {
|
private static final Map<Class<? extends ApiWebSocket>, List<Session>> SESSIONS_BY_CLASS = new HashMap<>();
|
||||||
|
|
||||||
|
protected static String getPathInfo(Session session) {
|
||||||
ServletUpgradeRequest upgradeRequest = (ServletUpgradeRequest) session.getUpgradeRequest();
|
ServletUpgradeRequest upgradeRequest = (ServletUpgradeRequest) session.getUpgradeRequest();
|
||||||
return upgradeRequest.getHttpServletRequest().getPathInfo();
|
return upgradeRequest.getHttpServletRequest().getPathInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
default Map<String, String> getPathParams(Session session, String pathSpec) {
|
protected static Map<String, String> getPathParams(Session session, String pathSpec) {
|
||||||
UriTemplatePathSpec uriTemplatePathSpec = new UriTemplatePathSpec(pathSpec);
|
UriTemplatePathSpec uriTemplatePathSpec = new UriTemplatePathSpec(pathSpec);
|
||||||
return uriTemplatePathSpec.getPathParams(this.getPathInfo(session));
|
return uriTemplatePathSpec.getPathParams(getPathInfo(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
default void sendError(Session session, ApiError apiError) {
|
protected static void sendError(Session session, ApiError apiError) {
|
||||||
ApiErrorRoot apiErrorRoot = new ApiErrorRoot();
|
ApiErrorRoot apiErrorRoot = new ApiErrorRoot();
|
||||||
apiErrorRoot.setApiError(apiError);
|
apiErrorRoot.setApiError(apiError);
|
||||||
|
|
||||||
@ -43,7 +50,7 @@ interface ApiWebSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default void marshall(Writer writer, Object object) throws IOException {
|
protected static void marshall(Writer writer, Object object) throws IOException {
|
||||||
Marshaller marshaller = createMarshaller(object.getClass());
|
Marshaller marshaller = createMarshaller(object.getClass());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -53,7 +60,7 @@ interface ApiWebSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default void marshall(Writer writer, Collection<?> collection) throws IOException {
|
protected static void marshall(Writer writer, Collection<?> collection) throws IOException {
|
||||||
// If collection is empty then we're returning "[]" anyway
|
// If collection is empty then we're returning "[]" anyway
|
||||||
if (collection.isEmpty()) {
|
if (collection.isEmpty()) {
|
||||||
writer.append("[]");
|
writer.append("[]");
|
||||||
@ -92,4 +99,22 @@ interface ApiWebSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onWebSocketConnect(Session session) {
|
||||||
|
synchronized (SESSIONS_BY_CLASS) {
|
||||||
|
SESSIONS_BY_CLASS.computeIfAbsent(this.getClass(), clazz -> new ArrayList<>()).add(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onWebSocketClose(Session session, int statusCode, String reason) {
|
||||||
|
synchronized (SESSIONS_BY_CLASS) {
|
||||||
|
SESSIONS_BY_CLASS.get(this.getClass()).remove(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Session> getSessions() {
|
||||||
|
synchronized (SESSIONS_BY_CLASS) {
|
||||||
|
return new ArrayList<>(SESSIONS_BY_CLASS.get(this.getClass()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||||
import org.qortal.api.ApiError;
|
import org.qortal.api.ApiError;
|
||||||
import org.qortal.controller.BlockNotifier;
|
import org.qortal.controller.BlockNotifier;
|
||||||
@ -20,7 +19,7 @@ import org.qortal.utils.Base58;
|
|||||||
|
|
||||||
@WebSocket
|
@WebSocket
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class BlocksWebSocket extends WebSocketServlet implements ApiWebSocket {
|
public class BlocksWebSocket extends ApiWebSocket {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSocketServletFactory factory) {
|
public void configure(WebSocketServletFactory factory) {
|
||||||
@ -98,7 +97,7 @@ public class BlocksWebSocket extends WebSocketServlet implements ApiWebSocket {
|
|||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.marshall(stringWriter, blockData);
|
marshall(stringWriter, blockData);
|
||||||
|
|
||||||
session.getRemote().sendString(stringWriter.toString());
|
session.getRemote().sendString(stringWriter.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -12,7 +12,6 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||||
import org.qortal.controller.ChatNotifier;
|
import org.qortal.controller.ChatNotifier;
|
||||||
import org.qortal.data.chat.ChatMessage;
|
import org.qortal.data.chat.ChatMessage;
|
||||||
@ -23,7 +22,7 @@ import org.qortal.repository.RepositoryManager;
|
|||||||
|
|
||||||
@WebSocket
|
@WebSocket
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class ChatMessagesWebSocket extends WebSocketServlet implements ApiWebSocket {
|
public class ChatMessagesWebSocket extends ApiWebSocket {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSocketServletFactory factory) {
|
public void configure(WebSocketServletFactory factory) {
|
||||||
@ -123,7 +122,7 @@ public class ChatMessagesWebSocket extends WebSocketServlet implements ApiWebSoc
|
|||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.marshall(stringWriter, chatMessages);
|
marshall(stringWriter, chatMessages);
|
||||||
|
|
||||||
session.getRemote().sendString(stringWriter.toString());
|
session.getRemote().sendString(stringWriter.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -13,7 +13,6 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
|||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||||
import org.qortal.api.model.CrossChainOfferSummary;
|
import org.qortal.api.model.CrossChainOfferSummary;
|
||||||
import org.qortal.controller.BlockNotifier;
|
import org.qortal.controller.BlockNotifier;
|
||||||
@ -28,7 +27,7 @@ import org.qortal.utils.NTP;
|
|||||||
|
|
||||||
@WebSocket
|
@WebSocket
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class TradeOffersWebSocket extends WebSocketServlet implements ApiWebSocket {
|
public class TradeOffersWebSocket extends ApiWebSocket {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSocketServletFactory factory) {
|
public void configure(WebSocketServletFactory factory) {
|
||||||
@ -116,7 +115,8 @@ public class TradeOffersWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onNotify(Session session, BlockData blockData, final Map<String, BTCACCT.Mode> previousAtModes) {
|
private void onNotify(Session session, BlockData blockData, final Map<String, BTCACCT.Mode> previousAtModes) {
|
||||||
synchronized (previousAtModes) { //NOSONAR squid:S2445 suppressed because previousAtModes is final and curried in lambda
|
List<CrossChainOfferSummary> crossChainOfferSummaries = null;
|
||||||
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
// Find any new trade ATs since this block
|
// Find any new trade ATs since this block
|
||||||
final Boolean isFinished = null;
|
final Boolean isFinished = null;
|
||||||
@ -131,8 +131,12 @@ public class TradeOffersWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
if (atStates == null)
|
if (atStates == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<CrossChainOfferSummary> crossChainOfferSummaries = produceSummaries(repository, atStates, blockData.getTimestamp());
|
crossChainOfferSummaries = produceSummaries(repository, atStates, blockData.getTimestamp());
|
||||||
|
} catch (DataException e) {
|
||||||
|
// No output this time
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (previousAtModes) { //NOSONAR squid:S2445 suppressed because previousAtModes is final and curried in lambda
|
||||||
// Remove any entries unchanged from last time
|
// Remove any entries unchanged from last time
|
||||||
crossChainOfferSummaries.removeIf(offerSummary -> previousAtModes.get(offerSummary.getQortalAtAddress()) == offerSummary.getMode());
|
crossChainOfferSummaries.removeIf(offerSummary -> previousAtModes.get(offerSummary.getQortalAtAddress()) == offerSummary.getMode());
|
||||||
|
|
||||||
@ -146,16 +150,13 @@ public class TradeOffersWebSocket extends WebSocketServlet implements ApiWebSock
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
previousAtModes.putAll(crossChainOfferSummaries.stream().collect(Collectors.toMap(CrossChainOfferSummary::getQortalAtAddress, CrossChainOfferSummary::getMode)));
|
previousAtModes.putAll(crossChainOfferSummaries.stream().collect(Collectors.toMap(CrossChainOfferSummary::getQortalAtAddress, CrossChainOfferSummary::getMode)));
|
||||||
} catch (DataException e) {
|
|
||||||
// No output this time
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sendOfferSummaries(Session session, List<CrossChainOfferSummary> crossChainOfferSummaries) {
|
private boolean sendOfferSummaries(Session session, List<CrossChainOfferSummary> crossChainOfferSummaries) {
|
||||||
try {
|
try {
|
||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
this.marshall(stringWriter, crossChainOfferSummaries);
|
marshall(stringWriter, crossChainOfferSummaries);
|
||||||
|
|
||||||
String output = stringWriter.toString();
|
String output = stringWriter.toString();
|
||||||
session.getRemote().sendStringByFuture(output);
|
session.getRemote().sendStringByFuture(output);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user