websocket de diferentes canales implementado y testeado
Some checks failed
Deploy Spring Boot App / build-and-deploy (push) Has been cancelled

This commit is contained in:
2025-10-29 17:05:00 -04:00
parent 0618c8737b
commit e7de207fbf
5 changed files with 175 additions and 54 deletions

View File

@@ -1,34 +1,119 @@
package com.example.fercoganbackend.component;
// ContadorWebSocketHandler.java
import com.example.fercoganbackend.service.ContadorService;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
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
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
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
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
String roomKey = extraerRoomKey(session);
Set<WebSocketSession> sesiones = sesionesPorLote.get(roomKey);
if (sesiones != null) {
sesiones.remove(session);
if (sesiones.isEmpty()) {
sesionesPorLote.remove(roomKey);
}
}
System.out.println("Conexión cerrada para: " + roomKey + " - " + status);
}
public void broadcast(String message) {
for (WebSocketSession session : sessions) {
@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));
} catch (Exception e) {
e.printStackTrace();
} 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;
}
}

View File

@@ -1,21 +1,24 @@
package com.example.fercoganbackend.configuration;
// WebSocketConfig.java
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
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
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final ContadorWebSocketHandler handler;
public WebSocketConfig(ContadorWebSocketHandler handler) {
this.handler = handler;
private final ContadorWebSocketHandler webSocketHandler;
public WebSocketConfig(ContadorWebSocketHandler webSocketHandler) {
this.webSocketHandler = webSocketHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler, "/ws/contador").setAllowedOrigins("*");
registry.addHandler(webSocketHandler, "/ws/{remate}/{lote}")
.setAllowedOrigins("*");
}
}

View File

@@ -1,6 +1,5 @@
package com.example.fercoganbackend.controller;
// ContadorController.java (REST API)
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
import com.example.fercoganbackend.service.ContadorService;
import org.springframework.web.bind.annotation.*;
@@ -11,20 +10,38 @@ public class ContadorController {
private final ContadorService contadorService;
private final ContadorWebSocketHandler webSocketHandler;
public ContadorController(ContadorService contadorService, ContadorWebSocketHandler webSocketHandler) {
public ContadorController(ContadorService contadorService,
ContadorWebSocketHandler webSocketHandler) {
this.contadorService = contadorService;
this.webSocketHandler = webSocketHandler;
}
@PostMapping("/incrementar")
public int incrementar() {
int nuevoValor = contadorService.incrementar();
webSocketHandler.broadcast(String.valueOf(nuevoValor));
@PostMapping("/incrementar/{remate}/{lote}")
public int incrementar(@PathVariable String remate, @PathVariable String lote) {
String roomKey = remate + "-" + lote;
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;
}
@GetMapping
public int getContador() {
return contadorService.getContador();
@GetMapping("/{remate}/{lote}")
public int getContador(@PathVariable String remate, @PathVariable String lote) {
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;
}
}

View File

@@ -1,33 +1,49 @@
package com.example.fercoganbackend.service;
// ContadorService.java
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class ContadorService {
private final AtomicInteger contador = new AtomicInteger(200);
private boolean sw = true;
private final Map<String, AtomicInteger> contadoresPorLote = new ConcurrentHashMap<>();
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 incremento;
if (valorActual < 300) {
incremento = sw ? 20 : 30;
sw = !sw; // alterna el booleano
} else if (valorActual < 1000) {
incremento = 50;
} else if (valorActual < 2000) {
incremento = 100;
} else {
incremento = 500;
}
int incremento = calcularIncremento(valorActual, sw);
// Alternar el switch para este lote
switchesPorLote.put(roomKey, !sw);
return contador.addAndGet(incremento);
}
public int getContador() {
return contador.get();
}
public int getContador(String roomKey) {
AtomicInteger contador = contadoresPorLote.get(roomKey);
return contador != null ? contador.get() : 200; // Valor por defecto
}
public void setContador(String roomKey, int valor) {
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;
}
}
}

View File

@@ -1,5 +1,5 @@
spring.application.name=fercoganbackend
spring.profiles.active=prod
spring.profiles.active=dev
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update