Skip to content

Commit 5906e8f

Browse files
committed
* Initial MySensors proof of concept module
Signed-off-by: Piotr Sobiech <[email protected]>
1 parent 86aaf3c commit 5906e8f

File tree

14 files changed

+1244
-6
lines changed

14 files changed

+1244
-6
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ COPY modules/lib/pom.xml modules/lib/
1919
COPY modules/parsers/pom.xml modules/parsers/
2020
COPY modules/tftp/pom.xml modules/tftp/
2121
COPY modules/client/pom.xml modules/client/
22+
COPY modules/mysensors/pom.xml modules/mysensors/
2223
COPY modules/vclu/pom.xml modules/vclu/
2324

2425
COPY assembly/jar-with-dependencies.xml assembly/
2526

2627
# https://issues.apache.org/jira/browse/MDEP-689
2728
#RUN mvn -B -T 4 dependency:go-offline
28-
RUN mvn -B -T 4 -pl '!modules/client' compile -Dorg.slf4j.simpleLogger.defaultLogLevel=ERROR -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.source.skip=true -Dmaven.javadoc.skip=true
29+
RUN mvn -B -T 4 -pl '!modules/client,!modules/mysensors' compile -Dorg.slf4j.simpleLogger.defaultLogLevel=ERROR -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.source.skip=true -Dmaven.javadoc.skip=true
2930

3031
FROM app-deps AS app-build
3132

badges/jacoco.svg

Lines changed: 1 addition & 1 deletion
Loading

modules/common/src/main/java/pl/psobiech/opengr8on/util/FileUtil.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ public final class FileUtil {
6363

6464
private static final TemporaryFileTracker FILE_TRACKER = new TemporaryFileTracker();
6565

66-
public static final String CR = Character.toString(0x0D);
66+
public static final byte CR_CODE_POINT = 0x0D;
6767

68-
public static final String LF = Character.toString(0x0A);
68+
public static final String CR = Character.toString(CR_CODE_POINT);
69+
70+
public static final byte LF_CODE_POINT = 0x0A;
71+
72+
public static final String LF = Character.toString(LF_CODE_POINT);
6973

7074
public static final String CRLF = CR + LF;
7175

modules/common/src/main/java/pl/psobiech/opengr8on/util/SocketUtil.java

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020

2121
import java.io.Closeable;
2222
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.OutputStream;
2325
import java.net.DatagramPacket;
2426
import java.net.DatagramSocket;
2527
import java.net.Inet4Address;
2628
import java.net.InetAddress;
2729
import java.net.InetSocketAddress;
30+
import java.net.Socket;
2831
import java.net.SocketException;
2932
import java.net.SocketTimeoutException;
3033
import java.time.Duration;
@@ -39,7 +42,7 @@
3942
import pl.psobiech.opengr8on.exceptions.UnexpectedException;
4043

4144
/**
42-
* Common socket operations. Currently only UDP.
45+
* Common socket operations.
4346
*/
4447
public class SocketUtil {
4548
/**
@@ -59,6 +62,12 @@ private SocketUtil() {
5962
// NOP
6063
}
6164

65+
public static TCPClientSocket tcpClient(InetAddress address, int port) {
66+
return new TCPClientSocket(
67+
address, port
68+
);
69+
}
70+
6271
public static UDPSocket udpListener(InetAddress address, int port) {
6372
return new UDPSocket(
6473
address, port, false
@@ -71,6 +80,150 @@ public static UDPSocket udpRandomPort(InetAddress address) {
7180
);
7281
}
7382

83+
/**
84+
* TCP socket wrapper
85+
*/
86+
public static class TCPClientSocket implements Closeable {
87+
/**
88+
* Local network address
89+
*/
90+
private final InetAddress address;
91+
92+
/**
93+
* Local port
94+
*/
95+
private final int port;
96+
97+
/**
98+
* Socket access lock
99+
*/
100+
private final ReentrantLock socketLock = new ReentrantLock();
101+
102+
/**
103+
* Raw network socket
104+
*/
105+
private Socket socket;
106+
107+
/**
108+
* @param address local address to bind on
109+
* @param port port to listen on
110+
*/
111+
public TCPClientSocket(InetAddress address, int port) {
112+
this.address = address;
113+
this.port = port;
114+
}
115+
116+
public void send(byte[] buffer) throws IOException {
117+
ensureConnected();
118+
119+
try {
120+
final OutputStream outputStream = socket.getOutputStream();
121+
outputStream.write(buffer);
122+
outputStream.flush();
123+
} catch (SocketException e) {
124+
// TODO: proper retry / broken pipe handling
125+
disconnect();
126+
ensureConnected();
127+
128+
try {
129+
final OutputStream outputStream = socket.getOutputStream();
130+
outputStream.write(buffer);
131+
outputStream.flush();
132+
} catch (Exception e2) {
133+
throw e;
134+
}
135+
}
136+
}
137+
138+
/**
139+
* Disconnects the socket
140+
*/
141+
public void disconnect() {
142+
socketLock.lock();
143+
try {
144+
// normal connect does not work for broken connections, we need to recreate socket
145+
close();
146+
open();
147+
} finally {
148+
socketLock.unlock();
149+
}
150+
}
151+
152+
/**
153+
* Open the socket
154+
*/
155+
public void open() {
156+
socketLock.lock();
157+
try {
158+
this.socket = new Socket();
159+
this.socket.setTcpNoDelay(true);
160+
this.socket.setKeepAlive(true);
161+
this.socket.setSoTimeout(DEFAULT_TIMEOUT_MILLISECONDS);
162+
} catch (SocketException e) {
163+
if (UncheckedInterruptedException.wasSocketInterrupted(e)) {
164+
throw new UncheckedInterruptedException(e);
165+
}
166+
167+
throw new UnexpectedException(e);
168+
} finally {
169+
socketLock.unlock();
170+
}
171+
}
172+
173+
/**
174+
* @return current local address
175+
*/
176+
public InetAddress getLocalAddress() {
177+
socketLock.lock();
178+
try {
179+
return socket.getLocalAddress();
180+
} finally {
181+
socketLock.unlock();
182+
}
183+
}
184+
185+
public InputStream getInputStream() throws IOException {
186+
socketLock.lock();
187+
try {
188+
ensureConnected();
189+
190+
return socket.getInputStream();
191+
} finally {
192+
socketLock.unlock();
193+
}
194+
}
195+
196+
private void ensureConnected() throws IOException {
197+
socketLock.lock();
198+
try {
199+
if (!socket.isConnected()) {
200+
connect();
201+
}
202+
} finally {
203+
socketLock.unlock();
204+
}
205+
}
206+
207+
public void connect() throws IOException {
208+
socketLock.lock();
209+
try {
210+
this.socket.connect(new InetSocketAddress(address, port), DEFAULT_TIMEOUT_MILLISECONDS);
211+
} finally {
212+
socketLock.unlock();
213+
}
214+
}
215+
216+
@Override
217+
public void close() {
218+
socketLock.lock();
219+
try {
220+
IOUtil.closeQuietly(this.socket);
221+
} finally {
222+
socketLock.unlock();
223+
}
224+
}
225+
}
226+
74227
/**
75228
* UDP socket wrapper
76229
*/
@@ -128,7 +281,11 @@ public void open() {
128281
this.socket = new DatagramSocket(new InetSocketAddress(address, port));
129282
this.socket.setBroadcast(broadcast);
130283
this.socket.setSoTimeout(DEFAULT_TIMEOUT_MILLISECONDS);
131-
} catch (IOException e) {
284+
} catch (SocketException e) {
285+
if (UncheckedInterruptedException.wasSocketInterrupted(e)) {
286+
throw new UncheckedInterruptedException(e);
287+
}
288+
132289
throw new UnexpectedException(e);
133290
} finally {
134291
socketLock.unlock();

modules/mysensors/pom.xml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ OpenGr8on, open source extensions to systems based on Grenton devices
4+
~ Copyright (C) 2023 Piotr Sobiech
5+
~
6+
~ This program is free software: you can redistribute it and/or modify
7+
~ it under the terms of the GNU Affero General Public License as
8+
~ published by the Free Software Foundation, either version 3 of the
9+
~ License, or (at your option) any later version.
10+
~
11+
~ This program is distributed in the hope that it will be useful,
12+
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
~ GNU Affero General Public License for more details.
15+
~
16+
~ You should have received a copy of the GNU Affero General Public License
17+
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
-->
19+
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
25+
<parent>
26+
<groupId>pl.psobiech.opengr8on</groupId>
27+
<artifactId>parent</artifactId>
28+
<version>0.5.0-SNAPSHOT</version>
29+
30+
<relativePath>../parent</relativePath>
31+
</parent>
32+
33+
<artifactId>mysensors</artifactId>
34+
35+
<dependencies>
36+
<dependency>
37+
<groupId>pl.psobiech.opengr8on</groupId>
38+
<artifactId>common</artifactId>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>org.apache.commons</groupId>
43+
<artifactId>commons-collections4</artifactId>
44+
<version>4.4</version>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>ch.qos.logback</groupId>
49+
<artifactId>logback-classic</artifactId>
50+
<scope>test</scope>
51+
</dependency>
52+
</dependencies>
53+
54+
<build>
55+
<resources>
56+
<resource>
57+
<directory>${basedir}/src/main/resources</directory>
58+
<filtering>false</filtering>
59+
</resource>
60+
<resource>
61+
<directory>../</directory>
62+
<targetPath>META-INF</targetPath>
63+
<includes>
64+
<include>LICENSE.txt</include>
65+
<include>THIRD-PARTY.txt</include>
66+
</includes>
67+
</resource>
68+
</resources>
69+
</build>
70+
</project>

0 commit comments

Comments
 (0)