Skip to content

Commit 564a0ad

Browse files
committed
feat(haywardomnilogiclocal): handle compression flag in multi-block responses
1 parent f67d46f commit 564a0ad

2 files changed

Lines changed: 101 additions & 8 deletions

File tree

  • bundles/org.openhab.binding.haywardomnilogiclocal/src
    • main/java/org/openhab/binding/haywardomnilogiclocal/internal/net
    • test/java/org/openhab/binding/haywardomnilogiclocal/internal/net

bundles/org.openhab.binding.haywardomnilogiclocal/src/main/java/org/openhab/binding/haywardomnilogiclocal/internal/net/UdpClient.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,8 @@ public UdpResponse send(UdpRequest request) throws IOException {
7373
buffer.getLong();
7474
buffer.position(16);
7575
int msgType = buffer.getInt();
76-
buffer.get();
77-
int blockCount = Byte.toUnsignedInt(buffer.get());
78-
boolean thisCompressed = buffer.get() != 0;
79-
buffer.get();
76+
int blockCount = Byte.toUnsignedInt(data[21]);
77+
boolean thisCompressed = data[22] == 1;
8078

8179
if (!ackSent && (msgType == MSG_LEAD || msgType == MSG_BLOCK
8280
|| msgType == HaywardMessageType.MSP_TELEMETRY_UPDATE.getMsgInt())) {
@@ -88,6 +86,7 @@ public UdpResponse send(UdpRequest request) throws IOException {
8886
expectedBlocks = blockCount;
8987
compressed = thisCompressed;
9088
} else if (msgType == MSG_BLOCK) {
89+
compressed |= thisCompressed;
9190
blocks.write(data, 24, data.length - 24);
9291
expectedBlocks--;
9392
if (expectedBlocks == 0) {

bundles/org.openhab.binding.haywardomnilogiclocal/src/test/java/org/openhab/binding/haywardomnilogiclocal/internal/net/UdpClientTest.java

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import static org.junit.jupiter.api.Assertions.assertFalse;
55
import static org.junit.jupiter.api.Assertions.assertTrue;
66

7+
import java.io.ByteArrayOutputStream;
78
import java.net.DatagramPacket;
89
import java.net.DatagramSocket;
910
import java.net.InetAddress;
1011
import java.net.SocketTimeoutException;
1112
import java.nio.ByteBuffer;
1213
import java.nio.charset.StandardCharsets;
14+
import java.util.Arrays;
1315
import java.util.concurrent.atomic.AtomicBoolean;
16+
import java.util.zip.DeflaterOutputStream;
1417

1518
import org.eclipse.jdt.annotation.NonNullByDefault;
1619
import org.junit.jupiter.api.Test;
@@ -102,6 +105,86 @@ public void sendShouldIgnoreAckAndProcessSubsequentData() throws Exception {
102105
assertTrue(ackAfterLead.get());
103106
}
104107

108+
@Test
109+
public void sendShouldHandleUncompressedMultiBlockResponse() throws Exception {
110+
final DatagramSocket server = new DatagramSocket(0);
111+
final int port = server.getLocalPort();
112+
final String responseXml = "<Response>OK</Response>";
113+
byte[] xmlBytes = (responseXml + '\0').getBytes(StandardCharsets.UTF_8);
114+
int mid = xmlBytes.length / 2;
115+
byte[] part1 = Arrays.copyOfRange(xmlBytes, 0, mid);
116+
byte[] part2 = Arrays.copyOfRange(xmlBytes, mid, xmlBytes.length);
117+
118+
Thread serverThread = new Thread(() -> {
119+
try {
120+
byte[] buf = new byte[4096];
121+
DatagramPacket requestPacket = new DatagramPacket(buf, buf.length);
122+
server.receive(requestPacket);
123+
int msgId = ByteBuffer.wrap(requestPacket.getData(), 0, requestPacket.getLength()).getInt();
124+
InetAddress clientAddress = requestPacket.getAddress();
125+
int clientPort = requestPacket.getPort();
126+
byte[] lead = createLeadPacket(msgId, 2, false);
127+
server.send(new DatagramPacket(lead, lead.length, clientAddress, clientPort));
128+
byte[] block1 = createBlockPacket(msgId, part1, false);
129+
server.send(new DatagramPacket(block1, block1.length, clientAddress, clientPort));
130+
byte[] block2 = createBlockPacket(msgId, part2, false);
131+
server.send(new DatagramPacket(block2, block2.length, clientAddress, clientPort));
132+
} catch (Exception e) {
133+
// ignore for test
134+
}
135+
});
136+
serverThread.start();
137+
138+
UdpClient client = new UdpClient("127.0.0.1", port);
139+
UdpRequest request = new UdpRequest(HaywardMessageType.GET_TELEMETRY.getMsgInt(), "<Request/>");
140+
UdpResponse response = client.send(request);
141+
142+
serverThread.join();
143+
server.close();
144+
145+
assertEquals(responseXml, response.getXml());
146+
}
147+
148+
@Test
149+
public void sendShouldDecompressMultiBlockResponseWhenFlagSet() throws Exception {
150+
final DatagramSocket server = new DatagramSocket(0);
151+
final int port = server.getLocalPort();
152+
final String responseXml = "<Response>OK</Response>";
153+
byte[] compressed = compress(responseXml);
154+
int mid = compressed.length / 2;
155+
byte[] part1 = Arrays.copyOfRange(compressed, 0, mid);
156+
byte[] part2 = Arrays.copyOfRange(compressed, mid, compressed.length);
157+
158+
Thread serverThread = new Thread(() -> {
159+
try {
160+
byte[] buf = new byte[4096];
161+
DatagramPacket requestPacket = new DatagramPacket(buf, buf.length);
162+
server.receive(requestPacket);
163+
int msgId = ByteBuffer.wrap(requestPacket.getData(), 0, requestPacket.getLength()).getInt();
164+
InetAddress clientAddress = requestPacket.getAddress();
165+
int clientPort = requestPacket.getPort();
166+
byte[] lead = createLeadPacket(msgId, 2, true);
167+
server.send(new DatagramPacket(lead, lead.length, clientAddress, clientPort));
168+
byte[] block1 = createBlockPacket(msgId, part1, true);
169+
server.send(new DatagramPacket(block1, block1.length, clientAddress, clientPort));
170+
byte[] block2 = createBlockPacket(msgId, part2, true);
171+
server.send(new DatagramPacket(block2, block2.length, clientAddress, clientPort));
172+
} catch (Exception e) {
173+
// ignore for test
174+
}
175+
});
176+
serverThread.start();
177+
178+
UdpClient client = new UdpClient("127.0.0.1", port);
179+
UdpRequest request = new UdpRequest(HaywardMessageType.GET_TELEMETRY.getMsgInt(), "<Request/>");
180+
UdpResponse response = client.send(request);
181+
182+
serverThread.join();
183+
server.close();
184+
185+
assertEquals(responseXml, response.getXml());
186+
}
187+
105188
private static byte[] createAckPacket(int messageId) throws Exception {
106189
UdpRequest ack = new UdpRequest(HaywardMessageType.ACK.getMsgInt(), "ACK", messageId);
107190
return ack.toBytes();
@@ -121,20 +204,31 @@ private static byte[] createLeadPacket(int messageId, int blocks, boolean compre
121204
}
122205

123206
private static byte[] createBlockPacket(int messageId, String xml) {
124-
byte[] xmlBytes = (xml + '\0').getBytes(StandardCharsets.UTF_8);
207+
return createBlockPacket(messageId, (xml + '\0').getBytes(StandardCharsets.UTF_8), false);
208+
}
209+
210+
private static byte[] createBlockPacket(int messageId, byte[] data, boolean compressed) {
125211
ByteBuffer header = ByteBuffer.allocate(24);
126212
header.putInt(messageId);
127213
header.putLong(System.currentTimeMillis());
128214
header.put("1.22".getBytes(StandardCharsets.US_ASCII));
129215
header.putInt(HaywardMessageType.MSP_BLOCKMESSAGE.getMsgInt());
130216
header.put((byte) 1);
131217
header.put((byte) 0);
218+
header.put((byte) (compressed ? 1 : 0));
132219
header.put((byte) 0);
133-
header.put((byte) 0);
134-
byte[] packet = new byte[24 + xmlBytes.length];
220+
byte[] packet = new byte[24 + data.length];
135221
System.arraycopy(header.array(), 0, packet, 0, 24);
136-
System.arraycopy(xmlBytes, 0, packet, 24, xmlBytes.length);
222+
System.arraycopy(data, 0, packet, 24, data.length);
137223
return packet;
138224
}
225+
226+
private static byte[] compress(String xml) throws Exception {
227+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
228+
try (DeflaterOutputStream dos = new DeflaterOutputStream(baos)) {
229+
dos.write(xml.getBytes(StandardCharsets.UTF_8));
230+
}
231+
return baos.toByteArray();
232+
}
139233
}
140234

0 commit comments

Comments
 (0)