diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index 6293947..5909c9c 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -2,7 +2,9 @@ package com.mediamanager.service.delegate; import com.google.protobuf.ByteString; import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.service.delegate.handler.CloseHandler; import com.mediamanager.service.delegate.handler.EchoHandler; +import com.mediamanager.service.delegate.handler.HeartbeatHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,6 +25,8 @@ public class DelegateActionManager { private void registerHandlers() { handlerRegistry.put("echo",new EchoHandler()); + handlerRegistry.put("heartbeat",new HeartbeatHandler()); + handlerRegistry.put("close", new CloseHandler()); } public void start(){ diff --git a/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java new file mode 100644 index 0000000..de59bf3 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java @@ -0,0 +1,32 @@ +package com.mediamanager.service.delegate.handler; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TestProtocol.CloseCommand; +import com.mediamanager.protocol.TestProtocol.CloseResponse; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.service.delegate.ActionHandler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class CloseHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(CloseHandler.class); + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + + CloseCommand.parseFrom(requestPayload); // Valida + + logger.info("Close command received - connection will close"); + + CloseResponse response = CloseResponse.newBuilder() + .setMessage("Connection closing. Goodbye!") + .build(); + + return TransportProtocol.Response.newBuilder() + .setPayload(ByteString.copyFrom(response.toByteArray())) + .setStatusCode(200) + .putHeaders("Connection", "close"); // ← Marca para fechar + } +} \ No newline at end of file diff --git a/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java index 23463e6..1e7ece9 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java @@ -1,17 +1,39 @@ package com.mediamanager.service.delegate.handler; import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TestProtocol.EchoCommand; // ← Import +import com.mediamanager.protocol.TestProtocol.EchoResponse; // ← Import import com.mediamanager.protocol.TransportProtocol; import com.mediamanager.service.delegate.ActionHandler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class EchoHandler implements ActionHandler { - @Override - public TransportProtocol.Response.Builder handle(ByteString requestPayload) { - String payloadText = requestPayload.toStringUtf8(); - String responseText = "Server received: " + payloadText; + private static final Logger logger = LogManager.getLogger(EchoHandler.class); + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { // ← Pode lançar exceção + + // 1. Parse Protobuf bytes → EchoCommand + EchoCommand command = EchoCommand.parseFrom(requestPayload); + + logger.debug("Echo received: {}", command.getMessage()); + + // 2. Cria EchoResponse (Protobuf) + EchoResponse echoResponse = EchoResponse.newBuilder() + .setMessage(command.getMessage()) + .setServerTimestamp(System.currentTimeMillis()) + .build(); + + // 3. Serializa EchoResponse → bytes + ByteString responsePayload = ByteString.copyFrom(echoResponse.toByteArray()); + + // 4. Retorna Response return TransportProtocol.Response.newBuilder() - .setPayload(ByteString.copyFromUtf8(responseText)) + .setPayload(responsePayload) .setStatusCode(200); + } } diff --git a/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java new file mode 100644 index 0000000..20e3d6d --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java @@ -0,0 +1,36 @@ +package com.mediamanager.service.delegate.handler; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TestProtocol.HeartbeatCommand; +import com.mediamanager.protocol.TestProtocol.HeartbeatResponse; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.service.delegate.ActionHandler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class HeartbeatHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(HeartbeatHandler.class); + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + + HeartbeatCommand command = HeartbeatCommand.parseFrom(requestPayload); + + long serverTime = System.currentTimeMillis(); + + logger.debug("Heartbeat received. Client T1={}, Server T2={}", + command.getClientTimestamp(), serverTime); + + HeartbeatResponse response = HeartbeatResponse.newBuilder() + .setClientTimestamp(command.getClientTimestamp()) // Echo T1 + .setServerTimestamp(serverTime) // T2 + .build(); + + return TransportProtocol.Response.newBuilder() + .setPayload(ByteString.copyFrom(response.toByteArray())) + .setStatusCode(200); + + } +} \ No newline at end of file diff --git a/src/main/java/com/mediamanager/service/ipc/IPCManager.java b/src/main/java/com/mediamanager/service/ipc/IPCManager.java index 17ff8b1..2115066 100644 --- a/src/main/java/com/mediamanager/service/ipc/IPCManager.java +++ b/src/main/java/com/mediamanager/service/ipc/IPCManager.java @@ -185,7 +185,7 @@ public class IPCManager { // Nenhum cliente conectado no momento // Dorme por um curto período antes de verificar novamente // Isso evita consumir CPU desnecessariamente em um loop vazio - Thread.sleep(100); // 100 milissegundos + Thread.sleep(1); // 1 milissegundos } } catch (InterruptedException e) { @@ -223,9 +223,16 @@ public class IPCManager { logger.debug("Client {} handler thread started", clientId); try { - TransportProtocol.Request request = readRequest(channel); + // LOOP: processa múltiplas requests na mesma conexão + while (channel.isOpen()) { + TransportProtocol.Request request = readRequest(channel); + + if (request == null) { + // Cliente desconectou gracefully + logger.info("Client {} disconnected (end of stream)", clientId); + break; + } - if (request != null) { logger.info("Client {} sent request {}", clientId, request.getRequestId()); // Processa usando o DelegateActionManager @@ -233,17 +240,29 @@ public class IPCManager { // Envia resposta de volta writeResponse(channel, response); - logger.info("Client {} response sent", clientId); - } else { - logger.warn("Client {} sent null message", clientId); + + // Verifica se é comando CLOSE + String connectionHeader = response.getHeadersOrDefault("Connection", ""); + if ("close".equals(connectionHeader)) { + logger.info("Client {} requested connection close", clientId); + break; // Sai do loop e fecha + } } + } catch (IOException e) { + if (channel.isOpen()) { + logger.error("IO error handling client {}", clientId, e); + } else { + logger.debug("Client {} connection closed by peer", clientId); + } } catch (Exception e) { - logger.error("Error handling client {}", clientId, e); + logger.error("Unexpected error handling client {}", clientId, e); } finally { try { - channel.close(); + if (channel.isOpen()) { + channel.close(); + } logger.debug("Client {} channel closed", clientId); } catch (IOException e) { logger.error("Error closing client {} channel", clientId, e); diff --git a/src/main/proto/test.proto b/src/main/proto/test.proto new file mode 100644 index 0000000..00330cd --- /dev/null +++ b/src/main/proto/test.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +option java_package = "com.mediamanager.protocol"; +option java_outer_classname = "TestProtocol"; + +package mediamanager.test; + +message EchoCommand { + string message = 1; +} + +message EchoResponse { + string message = 1; + int64 server_timestamp = 2; +} + +message HeartbeatCommand { + int64 client_timestamp = 1; +} + +message HeartbeatResponse { + int64 client_timestamp = 1; + int64 server_timestamp = 2; +} +message CloseCommand { + // Vazio - apenas sinaliza fechamento +} +message CloseResponse { + string message = 1; +} \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 39be1a8..a9f3f84 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -18,17 +18,17 @@ - + - + - +