SUPPORT-8957: add websocket service
This commit is contained in:
parent
9db55c846d
commit
1540780cdf
11 changed files with 277 additions and 1 deletions
|
|
@ -216,6 +216,14 @@
|
|||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import java.time.Duration;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import net.javacrumbs.shedlock.core.LockProvider;
|
||||
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
|
||||
|
|
@ -81,4 +83,10 @@ public class AppConfig {
|
|||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper()
|
||||
.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,18 @@ import ru.micord.ervu.account_applications.security.model.jwt.UserSession;
|
|||
import ru.micord.ervu.account_applications.security.model.jwt.authentication.JwtTokenAuthentication;
|
||||
import ru.micord.ervu.account_applications.security.model.jwt.authentication.JwtTokenDummy;
|
||||
import ru.micord.ervu.account_applications.security.service.JwtTokenService;
|
||||
import ru.micord.ervu.account_applications.websocket.service.WebSocketService;
|
||||
|
||||
@Component
|
||||
public class ErvuJwtAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private final JwtTokenService jwtTokenService;
|
||||
private final WebSocketService webSocketService;
|
||||
|
||||
public ErvuJwtAuthenticationProvider(JwtTokenService jwtTokenService) {
|
||||
public ErvuJwtAuthenticationProvider(JwtTokenService jwtTokenService,
|
||||
WebSocketService webSocketService) {
|
||||
this.jwtTokenService = jwtTokenService;
|
||||
this.webSocketService = webSocketService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -23,6 +27,7 @@ public class ErvuJwtAuthenticationProvider implements AuthenticationProvider {
|
|||
JwtTokenDummy jwtTokenDummy = (JwtTokenDummy) authentication;
|
||||
String jwtToken = jwtTokenDummy.getToken();
|
||||
UserSession userSession = jwtTokenService.getUserSession(jwtToken);
|
||||
webSocketService.connectToSocket();
|
||||
return new JwtTokenAuthentication(userSession, jwtToken);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package ru.micord.ervu.account_applications.websocket;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.client.WebSocketClient;
|
||||
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public WebSocketClient webSocketStompClient() {
|
||||
return new StandardWebSocketClient();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package ru.micord.ervu.account_applications.websocket.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public record ProcessErrorMsg(String message) {
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package ru.micord.ervu.account_applications.websocket.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public record ProcessResponseBody(String type, String userName, @JsonProperty("value") String tempPass,
|
||||
String secretLink, ProcessErrorMsg msg) {
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package ru.micord.ervu.account_applications.websocket.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import ru.micord.ervu.account_applications.websocket.enums.ClassName;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public record ProcessResponseDto(String traceId, String forUser, ClassName className,
|
||||
ProcessResponseBody body) {
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package ru.micord.ervu.account_applications.websocket.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
public enum ClassName {
|
||||
@JsonProperty("update")
|
||||
UPDATE,
|
||||
@JsonProperty("processError")
|
||||
PROCESS_ERROR,
|
||||
@JsonEnumDefaultValue
|
||||
SKIP
|
||||
|
||||
// private String value;
|
||||
//
|
||||
// ClassName(String value) {
|
||||
// this.value = value;
|
||||
// }
|
||||
//
|
||||
// public static ClassName getByValue(String value) {
|
||||
// return Arrays.stream(ClassName.values())
|
||||
// .filter(e -> e.value.equals(value))
|
||||
// .findFirst()
|
||||
// .orElse(ClassName.SKIP);
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package ru.micord.ervu.account_applications.websocket.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
import ru.micord.ervu.account_applications.service.UserApplicationListService;
|
||||
import ru.micord.ervu.account_applications.websocket.dto.ProcessResponseDto;
|
||||
import ru.micord.ervu.account_applications.websocket.service.WebSocketService;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@Component
|
||||
public class ClientSocketHandler extends TextWebSocketHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TextWebSocketHandler.class);
|
||||
|
||||
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final UserApplicationListService applicationService;
|
||||
private final WebSocketService webSocketService;
|
||||
|
||||
public ClientSocketHandler(ObjectMapper objectMapper,
|
||||
UserApplicationListService applicationService,
|
||||
@Lazy WebSocketService webSocketService) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.applicationService = applicationService;
|
||||
this.webSocketService = webSocketService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) {
|
||||
LOGGER.info("established connection {}", session);
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message)
|
||||
throws JsonProcessingException {
|
||||
ProcessResponseDto dto = objectMapper.readValue(message.getPayload().toString(),
|
||||
ProcessResponseDto.class);
|
||||
LOGGER.info("received message, type = {}, sessionId = {}, principal = {}",
|
||||
dto.className(), session.getId(), session.getPrincipal());
|
||||
String traceId = dto.traceId();
|
||||
|
||||
switch (dto.className()) {
|
||||
case UPDATE -> {
|
||||
LOGGER.info("update by traceId = {}", traceId);
|
||||
String tempPass = dto.body().tempPass();
|
||||
|
||||
if (StringUtils.hasText(tempPass)) {
|
||||
applicationService.savePassword(traceId, tempPass);
|
||||
}
|
||||
else {
|
||||
applicationService.saveAcceptedStatus(traceId);
|
||||
}
|
||||
}
|
||||
case PROCESS_ERROR -> {
|
||||
LOGGER.error("error by traceId = {}", traceId);
|
||||
applicationService.saveError(traceId, dto.body().msg().message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||
LOGGER.info("received text message {}", message.getPayload());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable exception) {
|
||||
LOGGER.error("Transport error {}", exception.getMessage());
|
||||
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOGGER.error("Failed to close session on handleTransportError ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
||||
LOGGER.info("Connection closed");
|
||||
|
||||
if (!status.equals(CloseStatus.NORMAL)) {
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOGGER.error("Failed to close session on afterConnectionClosed ", e);
|
||||
}
|
||||
}
|
||||
sessions.remove(session);
|
||||
webSocketService.connectToSocket();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package ru.micord.ervu.account_applications.websocket.service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.WebSocketHttpHeaders;
|
||||
import org.springframework.web.socket.client.WebSocketClient;
|
||||
|
||||
/**
|
||||
* @author gulnaz
|
||||
*/
|
||||
@Service
|
||||
public class WebSocketService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketService.class);
|
||||
|
||||
private final WebSocketClient webSocketClient;
|
||||
private final WebSocketHandler webSocketHandler;
|
||||
|
||||
@Value("${ervu.socket.url:wss://ervu-uat.test.gosuslugi.ru/service/notifier/gateway/notify/notifier.message.send.push}")
|
||||
private String socketUrl;
|
||||
|
||||
public WebSocketService(WebSocketClient webSocketClient,
|
||||
WebSocketHandler webSocketHandler) {
|
||||
this.webSocketClient = webSocketClient;
|
||||
this.webSocketHandler = webSocketHandler;
|
||||
}
|
||||
|
||||
public void connectToSocket() {
|
||||
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
|
||||
headers.set("Content-Type", "application/json");
|
||||
// headers.add("Authorization", "Bearer " + securityContext.getToken());
|
||||
headers.add("Authorization", "Bearer " + getToken());
|
||||
|
||||
try {
|
||||
webSocketClient.doHandshake(webSocketHandler, headers, URI.create(socketUrl)).get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e) {
|
||||
LOGGER.error("Failed to connect socket");
|
||||
}
|
||||
}
|
||||
|
||||
private String getToken() {
|
||||
return
|
||||
"eyJraWQiOiJzc29rZXkxIiwidHlwIjoiSldUIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiI3MDhjMGJkNS05MDk0LTQyZjUtYWQwZS0xZWUyMTBlZTM5MDMiLCJhbXIiOlsiSURQX0xPQ0FMIl0sInJvbGVzIjpbInNlY3VyaXR5X2FkbWluaXN0cmF0b3IiLCLQkdCw0LfQvtCy0LDRjyDRgNC-0LvRjCDQtNC70Y8g0LDQstGC0L7RgNC40LfQsNGG0LjQuCIsItCf0L7Qu9GM0LfQvtCy0LDRgtC10LvRjNGB0LrQsNGPINGA0L7Qu9GMIiwiUzNDbGllbnQiXSwiaXNzIjoiaHR0cHM6Ly9lcnZ1LXVhdC1zc28udGVzdC5nb3N1c2x1Z2kucnUiLCJncm91cHMiOltdLCJkb21haW5faWQiOiI1NTNiOTQ0OS02NDYwLTQ4YzQtODhkNC1mMTgyODNhYmM0YTciLCJhdWQiOiJhcm0iLCJhY2NvdW50SWQiOiI3MDhjMGJkNS05MDk0LTQyZjUtYWQwZS0xZWUyMTBlZTM5MDMiLCJuYmYiOjAsImF6cCI6ImFybSIsImF1dGhfdGltZSI6MCwibmFtZSI6ItCX0LDRgNC40L_QvtCyINCt0LzQuNC70YwiLCJyZWFsbSI6ItCS0L7RgdGM0LzQvtC1INGD0L_RgNCw0LLQu9C10L3QuNC1INCT0Kgg0JLQoSDQoNCkIiwicG9zaXRpb24iOiLQnNC40LrQvtGA0LQg0J_QntCY0JEiLCJleHAiOjE3NDE4MjM4NDgsInNlc3Npb25fc3RhdGUiOiI4M2UyMzdmNS05NzQzLTQ4ZmMtYjY2MS1jN2ZhODc1NjcyNDQiLCJpYXQiOjE3NDE4MDk0NDgsIlVTRVJfSVAiOiIxNzIuMjYuMjcuMTAifQ.em1QK3Tux2WUCxk-ii0I6VApr7KKsKcnWaM7mPfS2T3VEyn9pwZuLo9KQsIaQ1kIf-xsdz3iwuWruyHn0KxUlJQB_s7gAcfLMPy_2XVwydb--XviwvZ9ZRpQbdb_uhoAojhO9_h_UGuQOaKwF3K_g4EfgyWnD9xHyrujLlV9HIoipH6Eixci9jhscelWXv76wP8sbyPyeB9YrKnWTtFyhCvMb3y3FjwSCDs7Hi7JPh0SDQUQ-o8z0h6mOPIuoo53S03AEVr40f3s9nr0APq7HoU3UW3kQfkEI9A060pqO3c2ItnJU5-FE-og0wMVEnEvXeZtHebsSP3IdssJDpKrNg";
|
||||
}
|
||||
}
|
||||
11
pom.xml
11
pom.xml
|
|
@ -16,6 +16,7 @@
|
|||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<enable.version.in.url>false</enable.version.in.url>
|
||||
<spring.version>5.3.39</spring.version>
|
||||
<joda-time.version>2.9.2</joda-time.version>
|
||||
<webbpm-platform.version>3.192.3</webbpm-platform.version>
|
||||
<wbp.overall-timeout>72000</wbp.overall-timeout>
|
||||
|
|
@ -286,6 +287,16 @@
|
|||
<version>${webbpm-platform.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue