websocket de diferentes canales implementado y testeado
Some checks failed
Deploy Spring Boot App / build-and-deploy (push) Has been cancelled
Some checks failed
Deploy Spring Boot App / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -1,34 +1,119 @@
|
|||||||
package com.example.fercoganbackend.component;
|
package com.example.fercoganbackend.component;
|
||||||
|
|
||||||
// ContadorWebSocketHandler.java
|
import com.example.fercoganbackend.service.ContadorService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.socket.*;
|
import org.springframework.web.socket.*;
|
||||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ContadorWebSocketHandler extends TextWebSocketHandler {
|
public class ContadorWebSocketHandler extends TextWebSocketHandler {
|
||||||
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
|
|
||||||
|
private final Map<String, Set<WebSocketSession>> sesionesPorLote = new ConcurrentHashMap<>();
|
||||||
|
private final ContadorService contadorService;
|
||||||
|
|
||||||
|
public ContadorWebSocketHandler(ContadorService contadorService) {
|
||||||
|
this.contadorService = contadorService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionEstablished(WebSocketSession session) {
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
sessions.add(session);
|
String roomKey = extraerRoomKey(session);
|
||||||
|
|
||||||
|
System.out.println("=== NUEVA CONEXIÓN WEBSOCKET ===");
|
||||||
|
System.out.println("Session ID: " + session.getId());
|
||||||
|
System.out.println("URI: " + session.getUri());
|
||||||
|
System.out.println("Room Key: " + roomKey);
|
||||||
|
System.out.println("Sesiones activas en " + roomKey + ": " +
|
||||||
|
(sesionesPorLote.get(roomKey) != null ? sesionesPorLote.get(roomKey).size() : 0));
|
||||||
|
|
||||||
|
// Agregar sesión a la sala correspondiente
|
||||||
|
sesionesPorLote.computeIfAbsent(roomKey, k -> new CopyOnWriteArraySet<>()).add(session);
|
||||||
|
|
||||||
|
// Enviar valor actual del contador para este lote
|
||||||
|
int valorActual = contadorService.getContador(roomKey);
|
||||||
|
session.sendMessage(new TextMessage(String.valueOf(valorActual)));
|
||||||
|
|
||||||
|
System.out.println("Valor inicial enviado: " + valorActual);
|
||||||
|
System.out.println("=== CONEXIÓN ESTABLECIDA ===");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
||||||
sessions.remove(session);
|
String roomKey = extraerRoomKey(session);
|
||||||
}
|
Set<WebSocketSession> sesiones = sesionesPorLote.get(roomKey);
|
||||||
|
if (sesiones != null) {
|
||||||
public void broadcast(String message) {
|
sesiones.remove(session);
|
||||||
for (WebSocketSession session : sessions) {
|
if (sesiones.isEmpty()) {
|
||||||
try {
|
sesionesPorLote.remove(roomKey);
|
||||||
session.sendMessage(new TextMessage(message));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
System.out.println("Conexión cerrada para: " + roomKey + " - " + status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||||
|
String roomKey = extraerRoomKey(session);
|
||||||
|
String payload = message.getPayload();
|
||||||
|
|
||||||
|
System.out.println("Mensaje recibido de " + roomKey + ": " + payload);
|
||||||
|
|
||||||
|
if ("incrementar".equals(payload)) {
|
||||||
|
int nuevoValor = contadorService.incrementar(roomKey);
|
||||||
|
System.out.println("Incrementando " + roomKey + " a: " + nuevoValor);
|
||||||
|
broadcastToRoom(roomKey, String.valueOf(nuevoValor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast a una sala específica
|
||||||
|
public void broadcastToRoom(String remate, String lote, String message) {
|
||||||
|
String roomKey = generarRoomKey(remate, lote);
|
||||||
|
System.out.println("Broadcast a room: " + roomKey + " - Mensaje: " + message);
|
||||||
|
broadcastToRoom(roomKey, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastToRoom(String roomKey, String message) {
|
||||||
|
Set<WebSocketSession> sesiones = sesionesPorLote.get(roomKey);
|
||||||
|
System.out.println("Buscando sesiones para: " + roomKey);
|
||||||
|
System.out.println("Sesiones encontradas: " + (sesiones != null ? sesiones.size() : 0));
|
||||||
|
|
||||||
|
if (sesiones != null) {
|
||||||
|
for (WebSocketSession session : sesiones) {
|
||||||
|
try {
|
||||||
|
if (session.isOpen()) {
|
||||||
|
System.out.println("Enviando a session: " + session.getId());
|
||||||
|
session.sendMessage(new TextMessage(message));
|
||||||
|
} else {
|
||||||
|
System.out.println("Session cerrada: " + session.getId());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error enviando mensaje a " + session.getId() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No hay sesiones activas para: " + roomKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extraerRoomKey(WebSocketSession session) {
|
||||||
|
String path = session.getUri().getPath();
|
||||||
|
String[] segments = path.split("/");
|
||||||
|
|
||||||
|
// Para /ws/remate1/lote1 los segmentos son: ["", "ws", "remate1", "lote1"]
|
||||||
|
if (segments.length >= 4) {
|
||||||
|
String remate = segments[2]; // índice 2 = remate1
|
||||||
|
String lote = segments[3]; // índice 3 = lote1
|
||||||
|
return generarRoomKey(remate, lote);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "default-default";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generarRoomKey(String remate, String lote) {
|
||||||
|
return remate + "-" + lote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,24 @@
|
|||||||
package com.example.fercoganbackend.configuration;
|
package com.example.fercoganbackend.configuration;
|
||||||
|
|
||||||
// WebSocketConfig.java
|
|
||||||
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
|
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.socket.config.annotation.*;
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSocket
|
@EnableWebSocket
|
||||||
public class WebSocketConfig implements WebSocketConfigurer {
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
private final ContadorWebSocketHandler handler;
|
|
||||||
|
|
||||||
public WebSocketConfig(ContadorWebSocketHandler handler) {
|
private final ContadorWebSocketHandler webSocketHandler;
|
||||||
this.handler = handler;
|
|
||||||
|
public WebSocketConfig(ContadorWebSocketHandler webSocketHandler) {
|
||||||
|
this.webSocketHandler = webSocketHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
registry.addHandler(handler, "/ws/contador").setAllowedOrigins("*");
|
registry.addHandler(webSocketHandler, "/ws/{remate}/{lote}")
|
||||||
|
.setAllowedOrigins("*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.example.fercoganbackend.controller;
|
package com.example.fercoganbackend.controller;
|
||||||
|
|
||||||
// ContadorController.java (REST API)
|
|
||||||
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
|
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
|
||||||
import com.example.fercoganbackend.service.ContadorService;
|
import com.example.fercoganbackend.service.ContadorService;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -11,20 +10,38 @@ public class ContadorController {
|
|||||||
private final ContadorService contadorService;
|
private final ContadorService contadorService;
|
||||||
private final ContadorWebSocketHandler webSocketHandler;
|
private final ContadorWebSocketHandler webSocketHandler;
|
||||||
|
|
||||||
public ContadorController(ContadorService contadorService, ContadorWebSocketHandler webSocketHandler) {
|
public ContadorController(ContadorService contadorService,
|
||||||
|
ContadorWebSocketHandler webSocketHandler) {
|
||||||
this.contadorService = contadorService;
|
this.contadorService = contadorService;
|
||||||
this.webSocketHandler = webSocketHandler;
|
this.webSocketHandler = webSocketHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/incrementar")
|
@PostMapping("/incrementar/{remate}/{lote}")
|
||||||
public int incrementar() {
|
public int incrementar(@PathVariable String remate, @PathVariable String lote) {
|
||||||
int nuevoValor = contadorService.incrementar();
|
String roomKey = remate + "-" + lote;
|
||||||
webSocketHandler.broadcast(String.valueOf(nuevoValor));
|
int nuevoValor = contadorService.incrementar(roomKey);
|
||||||
|
|
||||||
|
System.out.println("=== INCREMENTAR VIA REST ===");
|
||||||
|
System.out.println("Remate: " + remate + ", Lote: " + lote);
|
||||||
|
System.out.println("Room Key: " + roomKey);
|
||||||
|
System.out.println("Nuevo valor: " + nuevoValor);
|
||||||
|
|
||||||
|
webSocketHandler.broadcastToRoom(remate, lote, String.valueOf(nuevoValor));
|
||||||
return nuevoValor;
|
return nuevoValor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping("/{remate}/{lote}")
|
||||||
public int getContador() {
|
public int getContador(@PathVariable String remate, @PathVariable String lote) {
|
||||||
return contadorService.getContador();
|
return contadorService.getContador(remate + "-" + lote);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/reset/{remate}/{lote}")
|
||||||
|
public int resetContador(@PathVariable String remate, @PathVariable String lote,
|
||||||
|
@RequestParam(defaultValue = "200") int valorInicial) {
|
||||||
|
String roomKey = remate + "-" + lote;
|
||||||
|
contadorService.setContador(roomKey, valorInicial);
|
||||||
|
int valor = contadorService.getContador(roomKey);
|
||||||
|
webSocketHandler.broadcastToRoom(remate, lote, String.valueOf(valor));
|
||||||
|
return valor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,33 +1,49 @@
|
|||||||
package com.example.fercoganbackend.service;
|
package com.example.fercoganbackend.service;
|
||||||
|
|
||||||
// ContadorService.java
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ContadorService {
|
public class ContadorService {
|
||||||
private final AtomicInteger contador = new AtomicInteger(200);
|
private final Map<String, AtomicInteger> contadoresPorLote = new ConcurrentHashMap<>();
|
||||||
private boolean sw = true;
|
private final Map<String, Boolean> switchesPorLote = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public int incrementar(String roomKey) {
|
||||||
|
AtomicInteger contador = contadoresPorLote.computeIfAbsent(roomKey,
|
||||||
|
k -> new AtomicInteger(200));
|
||||||
|
boolean sw = switchesPorLote.computeIfAbsent(roomKey, k -> true);
|
||||||
|
|
||||||
public int incrementar() {
|
|
||||||
int valorActual = contador.get();
|
int valorActual = contador.get();
|
||||||
int incremento;
|
int incremento = calcularIncremento(valorActual, sw);
|
||||||
if (valorActual < 300) {
|
|
||||||
incremento = sw ? 20 : 30;
|
// Alternar el switch para este lote
|
||||||
sw = !sw; // alterna el booleano
|
switchesPorLote.put(roomKey, !sw);
|
||||||
} else if (valorActual < 1000) {
|
|
||||||
incremento = 50;
|
|
||||||
} else if (valorActual < 2000) {
|
|
||||||
incremento = 100;
|
|
||||||
} else {
|
|
||||||
incremento = 500;
|
|
||||||
}
|
|
||||||
return contador.addAndGet(incremento);
|
return contador.addAndGet(incremento);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getContador(String roomKey) {
|
||||||
|
AtomicInteger contador = contadoresPorLote.get(roomKey);
|
||||||
|
return contador != null ? contador.get() : 200; // Valor por defecto
|
||||||
|
}
|
||||||
|
|
||||||
public int getContador() {
|
public void setContador(String roomKey, int valor) {
|
||||||
return contador.get();
|
AtomicInteger contador = contadoresPorLote.computeIfAbsent(roomKey,
|
||||||
|
k -> new AtomicInteger(valor));
|
||||||
|
contador.set(valor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calcularIncremento(int valorActual, boolean sw) {
|
||||||
|
if (valorActual < 300) {
|
||||||
|
return sw ? 20 : 30;
|
||||||
|
} else if (valorActual < 1000) {
|
||||||
|
return 50;
|
||||||
|
} else if (valorActual < 2000) {
|
||||||
|
return 100;
|
||||||
|
} else {
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
spring.application.name=fercoganbackend
|
spring.application.name=fercoganbackend
|
||||||
spring.profiles.active=prod
|
spring.profiles.active=dev
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
|
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
|||||||
Reference in New Issue
Block a user