001package jmri.jmrix.bidib.tcpserver;
002
003import java.io.ByteArrayOutputStream;
004
005import org.bidib.jbidibc.messages.MessageReceiver;
006import org.bidib.jbidibc.messages.utils.ByteUtils;
007import org.bidib.jbidibc.net.serialovertcp.*;
008import org.bidib.jbidibc.serial.SerialMessageEncoder;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * This is the network message handler for both directions.
015 * It receives the raw data from the TCP socket and forwards them
016 * to the message receiver.
017 * 
018 * The send() message is called from the BiDiBMessageReceiver to send
019 * data from tge BiDIB connection back to the TCP client. Data is encoded
020 * with the serial encoder (i.e. add the Magic bytes etc.) and then sent
021 * to the NetBidibPort, which then finally send the messages to all
022 * connected clients.
023 * 
024 * @author Eckart Meyer Copyright (C) 2023
025 *
026 */
027public class TcpServerNetMessageHandler  implements NetMessageHandler {
028    
029    private final MessageReceiver messageReceiverDelegate;
030    
031    public TcpServerNetMessageHandler(MessageReceiver messageReceiverDelegate) {
032        this.messageReceiverDelegate = messageReceiverDelegate;
033    }
034
035    @Override
036    public void receive(final DataPacket packet) {
037        // a data packet was received ... process the envelope and extract the message (or even messages?)
038        log.debug("Received a packet from address: {}, port: {}, data: {}", packet.getAddress(), packet.getPort(),
039                ByteUtils.bytesToHex(packet.getData()));
040
041//        BidibNetAddress current = new BidibNetAddress(packet.getAddress(), packet.getPort());
042//        if (!knownBidibHosts.contains(current)) {
043//
044//            LOGGER.info("Adding new known Bidib host: {}", current);
045//            knownBidibHosts.add(current);
046//        }
047
048        // TODO for the first magic response we need special processing because we need to keep the session key
049
050        // remove the  paket wrapper data and forward to the MessageReceiver
051        ByteArrayOutputStream output = new ByteArrayOutputStream();
052        output.write(packet.getData(), 0, packet.getData().length);
053
054        log.info("Forward received message to messageReceiverDelegate: {}, output: {}", messageReceiverDelegate,
055                ByteUtils.bytesToHex(output));
056        try {
057            messageReceiverDelegate.receive(output);
058        }
059        catch (Exception ex) {
060            log.warn("Process messages failed.", ex);
061            throw new RuntimeException(ex);
062        }
063    }
064    
065    /**
066     * Send serial encoded data (one or more messages) to the to the TCP port
067     * 
068     * @param port
069     *            the port
070     * @param data
071     *            the data
072     */
073    @Override
074    public void send(NetBidibPort port, byte[] data) {
075        log.trace("Send message to port: {}, message: {}", port, ByteUtils.bytesToHex(data));
076        ByteArrayOutputStream output = new ByteArrayOutputStream(100);
077        ByteArrayOutputStream input = new ByteArrayOutputStream(100);
078        //input.write(data, 0, data.length);
079        try {
080            input.write(data);
081            SerialMessageEncoder.encodeMessage(input, output);
082            log.trace("Send, after encoding: {}", ByteUtils.bytesToHex(output));
083            port.send(output.toByteArray(), null, 0); //InetAdress and port are not used in send, so no need to provide them
084        }
085        catch (Exception e) {
086            log.warn("no data sent", e);
087        }
088    }
089    
090    @Override
091    public void acceptClient(String remoteHost) {
092        log.info("Accept client with address: {}", remoteHost);
093    }
094
095    @Override
096    public void cleanup(String remoteHost) {
097        log.info("Cleanup client with address: {}", remoteHost);
098    }
099
100    private final static Logger log = LoggerFactory.getLogger(TcpServerNetMessageHandler.class);
101}