package org.fastcatsearch.transport.common; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.fastcatsearch.common.io.Streamable; import org.fastcatsearch.ir.io.DataInput; import org.fastcatsearch.transport.ChannelBufferStreamInput; import org.fastcatsearch.transport.TransportChannel; import org.fastcatsearch.transport.TransportModule; import org.fastcatsearch.transport.TransportOption; import org.fastcatsearch.transport.vo.StreamableBoolean; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileChannelHandler extends SimpleChannelUpstreamHandler { private static Logger logger = LoggerFactory.getLogger(FileChannelHandler.class); private TransportModule transport; private FileTransportHandler fileHandler; private final Streamable FILE_RECEIVE_DONE = new StreamableBoolean(true); private Map<String, TransportChannel> fileResponseChannelMap; public FileChannelHandler(TransportModule transport, FileTransportHandler fileHandler) { this.transport = transport; this.fileHandler = fileHandler; fileResponseChannelMap = new ConcurrentHashMap<String, TransportChannel>(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object m = e.getMessage(); if (!(m instanceof ChannelBuffer)) { ctx.sendUpstream(e); return; } ChannelBuffer buffer = (ChannelBuffer) m; int readerIndex = buffer.readerIndex(); byte type = buffer.getByte(readerIndex); if (!TransportOption.isTypeFile(type)) { ctx.sendUpstream(e); return; } logger.debug("file received[{}]>> {}", type, e); buffer.readByte();// type을 읽어서 버린다. int dataLength = buffer.readInt(); int markedReaderIndex = buffer.readerIndex(); int expectedIndexReader = markedReaderIndex + dataLength; DataInput wrappedStream = new ChannelBufferStreamInput(buffer, dataLength); long requestId = wrappedStream.readLong(); byte status = wrappedStream.readByte(); try { handleFileTransportRequest(ctx.getChannel(), wrappedStream, requestId); } catch (IOException e1) { logger.error("파일기록중 에러발생", e1); // 파일기록중 에러발생하면, 에러메시지 전송. final TransportChannel transportChannel = new TransportChannel(ctx.getChannel(), requestId); transportChannel.sendResponse(e1); } finally { wrappedStream.close(); } if (buffer.readerIndex() != expectedIndexReader) { if (buffer.readerIndex() < expectedIndexReader) { logger.warn("Message not fully read (request) for [{}] and action [{}], resetting", requestId); } else { logger.warn("Message read past expected size (request) for [{}] and action [{}], resetting", requestId); } buffer.readerIndex(expectedIndexReader); } } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelClosed(ctx, e); } private void handleFileTransportRequest(Channel channel, DataInput input, long requestId) throws IOException { logger.debug("File Handler >> {}, mapsize={}", this, fileResponseChannelMap.size()); // seq(4) + [filepath(string) + filesize(long) + checksumCRC32(long)]+hashfilepath(string) + datalength(vint) + data int seq = input.readInt(); String filePath = null; long fileSize = -1; long checksumCRC32 = 0; if (seq == 0) { filePath = input.readString(); fileSize = input.readLong(); checksumCRC32 = input.readLong(); logger.debug("File Receive seq={}, filesize={}, crc={}, file={}", new Object[] { seq, fileSize, checksumCRC32, filePath }); } String fileKey = input.readString(); TransportChannel transportChannel = fileResponseChannelMap.get(fileKey); if (transportChannel == null) { transportChannel = new TransportChannel(channel, requestId); fileResponseChannelMap.put(fileKey, transportChannel); } boolean isDone = fileHandler.handleFile(seq, filePath, fileSize, checksumCRC32, fileKey, input); if (isDone) { fileResponseChannelMap.remove(fileKey); transportChannel.sendResponse(FILE_RECEIVE_DONE); logger.debug("파일수신 성공결과보냄.>>{}", fileKey); } } }