| ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsFrameReader.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsTcpTransport.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ruoyi-device/src/main/java/com/ruoyi/device/bts/ScriptedBtsTcpSimulator.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsFrameReader.java
New file @@ -0,0 +1,56 @@ package com.ruoyi.device.bts; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; final class BtsFrameReader { private static final byte[] FRAME_END = "#\r\n".getBytes(StandardCharsets.UTF_8); private BtsFrameReader() { } static byte[] read(InputStream input, int maxPayloadBytes) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int matched = 0; while (true) { int value = input.read(); if (value < 0) throw new EOFException("BTS connection closed before the frame ended"); if ((byte) value == FRAME_END[matched]) { matched++; if (matched == FRAME_END.length) return buffer.toByteArray(); continue; } if (matched > 0) { for (int i = 0; i < matched; i++) append(buffer, FRAME_END[i], maxPayloadBytes); matched = 0; if ((byte) value == FRAME_END[0]) { matched = 1; continue; } } append(buffer, value, maxPayloadBytes); } } private static void append(ByteArrayOutputStream buffer, int value, int maxPayloadBytes) throws FrameTooLargeException { if (buffer.size() >= maxPayloadBytes) throw new FrameTooLargeException(); buffer.write(value); } static final class FrameTooLargeException extends IOException { private static final long serialVersionUID = 1L; } } ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsTcpTransport.java
@@ -1,6 +1,5 @@ package com.ruoyi.device.bts; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -83,7 +82,7 @@ throw new BtsTransportException(BtsTransportException.Reason.DISCONNECTED, "BTS disconnected before completing a response for " + host + ":" + port, ex); } catch (ResponseTooLargeException ex) catch (BtsFrameReader.FrameTooLargeException ex) { closeSocket(); throw new BtsTransportException(BtsTransportException.Reason.RESPONSE_TOO_LARGE, @@ -118,36 +117,7 @@ private String readFrame(InputStream input) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int matched = 0; while (true) { int value = input.read(); if (value < 0) throw new EOFException("BTS closed the connection before the response frame ended"); if ((byte) value == FRAME_END[matched]) { matched++; if (matched == FRAME_END.length) return decodeUtf8(buffer.toByteArray()); continue; } if (matched > 0) { for (int i = 0; i < matched; i++) appendPayload(buffer, FRAME_END[i]); matched = 0; if ((byte) value == FRAME_END[0]) { matched = 1; continue; } } appendPayload(buffer, value); } } private void appendPayload(ByteArrayOutputStream buffer, int value) throws ResponseTooLargeException { if (buffer.size() >= maxResponseBytes) throw new ResponseTooLargeException(); buffer.write(value); return decodeUtf8(BtsFrameReader.read(input, maxResponseBytes)); } private static String decodeUtf8(byte[] bytes) throws InvalidUtf8Exception @@ -194,11 +164,6 @@ { socket = null; } } private static final class ResponseTooLargeException extends IOException { private static final long serialVersionUID = 1L; } private static final class InvalidUtf8Exception extends IOException ruoyi-device/src/main/java/com/ruoyi/device/bts/ScriptedBtsTcpSimulator.java
@@ -1,6 +1,5 @@ package com.ruoyi.device.bts; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; @@ -116,25 +115,7 @@ private String readFrame(InputStream input) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int matched = 0; while (true) { int value = input.read(); if (value < 0) throw new IOException("Client disconnected"); if ((byte) value == FRAME_END[matched]) { matched++; if (matched == FRAME_END.length) return buffer.toString(StandardCharsets.UTF_8); continue; } if (matched > 0) { buffer.write(FRAME_END, 0, matched); matched = 0; } buffer.write(value); } return new String(BtsFrameReader.read(input, Integer.MAX_VALUE), StandardCharsets.UTF_8); } @Override ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java
@@ -22,4 +22,18 @@ assertEquals(1, simulator.requests().size()); } } @Test void simulatorPreservesRequestEndingWithDelimiterPrefix() throws Exception { try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator(); BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(), Duration.ofSeconds(1), Duration.ofSeconds(1))) { simulator.enqueue("ok"); assertEquals("ok", transport.exchange("payload#")); assertEquals("payload#", simulator.requests().get(0)); } } }