package com.ruoyi.device.bts; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; final class ScriptedBtsTcpSimulator implements AutoCloseable { private static final byte[] FRAME_END = "#\r\n".getBytes(StandardCharsets.UTF_8); private final ServerSocket serverSocket; private final ExecutorService executor = Executors.newSingleThreadExecutor(); private final BlockingQueue responses = new LinkedBlockingQueue<>(); private final List requests = new CopyOnWriteArrayList<>(); ScriptedBtsTcpSimulator() throws IOException { serverSocket = new ServerSocket(0); executor.submit(this::serve); } int port() { return serverSocket.getLocalPort(); } void enqueue(String response) { responses.add(response); } List requests() { return List.copyOf(requests); } private void serve() { try (Socket socket = serverSocket.accept()) { while (!socket.isClosed()) { String request = readFrame(socket.getInputStream()); requests.add(request); String response = responses.poll(5, TimeUnit.SECONDS); if (response == null) throw new IOException("No scripted BTS response available"); socket.getOutputStream().write(response.getBytes(StandardCharsets.UTF_8)); socket.getOutputStream().write(FRAME_END); socket.getOutputStream().flush(); } } catch (Exception ignored) { } } 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); } } @Override public void close() throws Exception { serverSocket.close(); executor.shutdownNow(); executor.awaitTermination(2, TimeUnit.SECONDS); } }