Skip to content

Commit 15b498b

Browse files
committed
code review changes
Signed-off-by: Christian Kittel <ckittel@gmx.de>
1 parent e4107d8 commit 15b498b

22 files changed

Lines changed: 427 additions & 95 deletions

bundles/org.openhab.binding.ntfy/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This binding provides the following Thing types. The Thing type IDs match the de
2121

2222
| Name | Type | Description | Default | Required | Advanced |
2323
|-------------------|---------|-----------------------------------------|-----------------|----------|----------|
24-
| hostname | text | Hostname or base URL of the ntfy server | [https://ntfy.sh](https://ntfy.sh) | yes | no |
24+
| hostname | text | Base URL of the ntfy server | [https://ntfy.sh](https://ntfy.sh) | yes | no |
2525
| username | text | Optional username for basic auth | N/A | no | no |
2626
| password | text | Optional password for basic auth | N/A | no | no |
2727
| connectionTimeout | integer | WebSocket / HTTP connection timeout ms | 60000 | no | yes |
@@ -38,10 +38,11 @@ Configure the `ntfyConnection` as a bridge to hold shared server and authenticat
3838

3939
### `ntfyTopic` Channels
4040

41-
| Channel | Type | Read/Write | Description |
42-
|-------------|----------|------------|---------------------------------------------|
43-
| lastMessage | String | R | Last received message payload (read-only) |
44-
| messageTime | DateTime | R | Timestamp of the last message (read-only) |
41+
| Channel | Type | Read/Write | Description |
42+
|-----------------|----------|------------|---------------------------------------------|
43+
| lastMessage | String | R | Last received message payload (read-only) |
44+
| lastMessageTime | DateTime | R | Timestamp of the last message (read-only) |
45+
| lastMessageId | String | R | ID of the last message (read-only) |
4546

4647
## Full Example
4748

@@ -94,8 +95,9 @@ Below is a quick reference of the builder-style methods provided by the binding
9495

9596
| Method | Parameters | Description | Ntfy docs |
9697
|--------|------------|-------------|----------|
97-
| withMessage | (String message) | Set the main message text. | [publish](https://docs.ntfy.sh/publish/#message-title) |
98-
| withPriority | (int priority) | Set message priority (0-5). | [priority](https://ntfy.sh/docs/publish/#priority) |
98+
| withMessage | (String message) | Set the main message text. | [publish](https://docs.ntfy.sh/publish) |
99+
| withPriority | (int priority) | Set message priority (1-5). | [priority](https://ntfy.sh/docs/publish/#priority) |
100+
| withTitle | (String title) | Set title. | [title](https://docs.ntfy.sh/publish/#message-title) |
99101
| withTag | (String tag) | Add a tag to the message. | [tags](https://ntfy.sh/docs/publish/#tags) |
100102
| withIcon | (String url) | Set an icon URL for the notification. | [icons](https://ntfy.sh/docs/publish/#icons) |
101103
| withAttachment | (String url, String filename) | Attach a file or resource URL with optional filename. | [attachments](https://docs.ntfy.sh/publish/#attach-file-from-a-url) |

bundles/org.openhab.binding.ntfy/src/main/java/org/openhab/binding/ntfy/internal/NtfyBindingConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ public class NtfyBindingConstants {
3333
// List of all Channel ids
3434
public static final String CHANNEL_NTFY_LASTMESSAGE = "lastMessage";
3535
public static final String CHANNEL_NTFY_LASTMESSAGETIME = "lastMessageTime";
36-
public static final String CHANNEL_NTFY_LASTMESSAGEID = "lastMessageMessageId";
36+
public static final String CHANNEL_NTFY_LASTMESSAGEID = "lastMessageId";
3737
}

bundles/org.openhab.binding.ntfy/src/main/java/org/openhab/binding/ntfy/internal/NtfyConnectionConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class NtfyConnectionConfiguration {
2828

2929
/**
30-
* Hostname of the ntfy server, e.g. "ntfy.sh"
30+
* Hostname of the ntfy server, e.g. "https://ntfy.sh"
3131
*/
3232
public String hostname = "";
3333

bundles/org.openhab.binding.ntfy/src/main/java/org/openhab/binding/ntfy/internal/NtfyConnectionHandler.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.concurrent.TimeUnit;
1919

2020
import org.eclipse.jdt.annotation.NonNullByDefault;
21+
import org.eclipse.jdt.annotation.Nullable;
2122
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
2223
import org.eclipse.jetty.websocket.client.WebSocketClient;
2324
import org.openhab.binding.ntfy.internal.network.NtfyWebSocket;
@@ -31,6 +32,7 @@
3132
import org.openhab.core.thing.binding.BaseBridgeHandler;
3233
import org.openhab.core.thing.util.ThingWebClientUtil;
3334
import org.openhab.core.types.Command;
35+
import org.osgi.service.cm.ConfigurationException;
3436
import org.slf4j.Logger;
3537
import org.slf4j.LoggerFactory;
3638

@@ -93,6 +95,7 @@ public synchronized void createAndRegisterWebSocketClient(Thing thing) {
9395
} catch (Exception e) {
9496
logger.error("Error stopping WebSocketConnection", e);
9597
}
98+
webSocketConnections.remove(thing.getUID());
9699
}
97100

98101
webSocketConnections.put(thing.getUID(), newClient);
@@ -129,10 +132,30 @@ public synchronized boolean startWebSocketConnection(Thing topicThing, NtfyWebSo
129132
client.start();
130133
client.setMaxIdleTimeout(config.connectionTimeout);
131134

135+
@Nullable
136+
String scheme = (new URI(config.hostname)).getScheme();
137+
if (scheme == null || scheme.isEmpty()) {
138+
throw new ConfigurationException("hostname", "URI scheme is missing in hostname" + config.hostname);
139+
}
140+
141+
String webSocketScheme = "wss";
142+
switch (scheme) {
143+
case "http":
144+
webSocketScheme = "ws";
145+
break;
146+
case "https":
147+
webSocketScheme = "wss";
148+
break;
149+
default:
150+
throw new IllegalArgumentException(
151+
"Unsupported URI scheme: " + scheme + " - only http and https are supported");
152+
}
153+
132154
client.connect(ntfyWebSocket,
133-
new URI("wss:"
155+
new URI(webSocketScheme + ":"
134156
+ (new URI(config.hostname + "/" + topicName + "/ws")).getRawSchemeSpecificPart()),
135157
setupRequest());
158+
updateStatus(ThingStatus.ONLINE);
136159
} catch (Exception e) {
137160
logger.error("Error creating WebSocketConnection", e);
138161
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getLocalizedMessage());
@@ -154,6 +177,21 @@ private String getTopicNameFromThing(Thing topicThing) {
154177
*/
155178
public void connectionError(Throwable cause) {
156179
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, cause.getLocalizedMessage());
157-
scheduler.schedule(() -> updateStatus(ThingStatus.ONLINE), 30, TimeUnit.SECONDS);
180+
scheduler.schedule(() -> updateStatus(ThingStatus.UNKNOWN), 30, TimeUnit.SECONDS);
181+
}
182+
183+
@Override
184+
public void dispose() {
185+
super.dispose();
186+
187+
webSocketConnections.values().forEach(client -> {
188+
try {
189+
if (client.isRunning()) {
190+
client.stop();
191+
}
192+
} catch (Exception e) {
193+
logger.error("Error stopping WebSocketConnection", e);
194+
}
195+
});
158196
}
159197
}

bundles/org.openhab.binding.ntfy/src/main/java/org/openhab/binding/ntfy/internal/NtfyTopicHandler.java

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.openhab.binding.ntfy.internal.network.WebSocketConnectionListener;
2929
import org.openhab.core.library.types.DateTimeType;
3030
import org.openhab.core.library.types.StringType;
31+
import org.openhab.core.thing.Bridge;
3132
import org.openhab.core.thing.ChannelUID;
3233
import org.openhab.core.thing.Thing;
3334
import org.openhab.core.thing.ThingStatus;
@@ -48,9 +49,10 @@
4849
public class NtfyTopicHandler extends BaseThingHandler implements WebSocketConnectionListener {
4950

5051
private NtfyWebSocket ntfyWebSocket;
51-
private NtfySender ntfySender;
52+
private @Nullable NtfySender ntfySender;
5253
private boolean isInitializing;
5354
private @Nullable MessageEvent lastMessageEvent;
55+
private HttpClient httpClient;
5456

5557
/**
5658
* Creates a new {@link NtfyTopicHandler} for the provided topic thing.
@@ -61,14 +63,19 @@ public class NtfyTopicHandler extends BaseThingHandler implements WebSocketConne
6163
public NtfyTopicHandler(Thing thing, HttpClient httpClient) {
6264
super(thing);
6365

66+
this.httpClient = httpClient;
6467
this.ntfyWebSocket = new NtfyWebSocket(this);
65-
this.ntfySender = new NtfySender(this.getConfigAs(NtfyTopicConfiguration.class).topicname, httpClient,
66-
this::getBridgeHandler);
6768
}
6869

69-
private NtfyConnectionHandler getBridgeHandler() {
70-
return (NtfyConnectionHandler) (java.util.Objects
71-
.requireNonNull(java.util.Objects.requireNonNull(getBridge()).getHandler()));
70+
private @Nullable NtfyConnectionHandler getBridgeHandler() {
71+
@Nullable
72+
Bridge bridge = getBridge();
73+
74+
if (bridge == null) {
75+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
76+
return null;
77+
}
78+
return (NtfyConnectionHandler) (bridge.getHandler());
7279
}
7380

7481
@Override
@@ -80,12 +87,22 @@ public Collection<Class<? extends ThingHandlerService>> getServices() {
8087
public void thingUpdated(Thing thing) {
8188
super.thingUpdated(thing);
8289

83-
getBridgeHandler().createAndRegisterWebSocketClient(thing);
90+
@Nullable
91+
NtfyConnectionHandler bridgeHandler = getBridgeHandler();
92+
93+
if (bridgeHandler == null) {
94+
return;
95+
}
96+
97+
ntfySender = new NtfySender(this.getConfigAs(NtfyTopicConfiguration.class).topicname, httpClient,
98+
this::getBridgeHandler);
99+
bridgeHandler.createAndRegisterWebSocketClient(thing);
100+
startConnection();
84101
}
85102

86103
@Override
87104
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
88-
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE
105+
if ((bridgeStatusInfo.getStatus() == ThingStatus.ONLINE || bridgeStatusInfo.getStatus() == ThingStatus.UNKNOWN)
89106
&& getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE) {
90107
updateStatus(ThingStatus.UNKNOWN);
91108
initialize();
@@ -112,7 +129,14 @@ public void initialize() {
112129

113130
scheduler.execute(() -> {
114131
try {
115-
getBridgeHandler().createAndRegisterWebSocketClient(thing);
132+
ntfySender = new NtfySender(this.getConfigAs(NtfyTopicConfiguration.class).topicname, httpClient,
133+
this::getBridgeHandler);
134+
@Nullable
135+
NtfyConnectionHandler bridgeHandler = getBridgeHandler();
136+
if (bridgeHandler == null) {
137+
return;
138+
}
139+
bridgeHandler.createAndRegisterWebSocketClient(thing);
116140
startConnection();
117141
} finally {
118142
this.isInitializing = false;
@@ -122,7 +146,12 @@ public void initialize() {
122146

123147
private void startConnection() {
124148
if (getThing().getStatus() != ThingStatus.ONLINE) {
125-
if (!getBridgeHandler().startWebSocketConnection(thing, ntfyWebSocket)) {
149+
@Nullable
150+
NtfyConnectionHandler bridgeHandler = getBridgeHandler();
151+
if (bridgeHandler == null) {
152+
return;
153+
}
154+
if (!bridgeHandler.startWebSocketConnection(thing, ntfyWebSocket)) {
126155
updateStatus(ThingStatus.OFFLINE);
127156
}
128157
}
@@ -135,15 +164,22 @@ public void connectionEstablished() {
135164

136165
@Override
137166
public void connectionLost(String reason) {
167+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
168+
reason.isBlank() ? "WebSocket connection lost" : reason);
138169
}
139170

140171
@Override
141172
public void connectionError(Throwable cause) {
142-
getBridgeHandler().connectionError(cause);
173+
@Nullable
174+
NtfyConnectionHandler bridgeHandler = getBridgeHandler();
175+
if (bridgeHandler == null) {
176+
return;
177+
}
178+
bridgeHandler.connectionError(cause);
143179
}
144180

145181
@Override
146-
public void messageRecieved(BaseEvent event) {
182+
public void messageReceived(BaseEvent event) {
147183
if (event instanceof MessageEvent message) {
148184
this.lastMessageEvent = message;
149185
updateChannels();
@@ -169,19 +205,40 @@ private void updateChannels() {
169205
* @throws URISyntaxException
170206
*/
171207
public String sendMessage(NtfyMessage ntfyMessage) throws URISyntaxException {
208+
final @Nullable NtfySender sender = ntfySender;
209+
if (sender == null) {
210+
return "";
211+
}
212+
172213
@Nullable
173-
MessageEvent sendMessage = ntfySender.sendMessage(ntfyMessage);
214+
MessageEvent sendMessage = sender.sendMessage(ntfyMessage);
174215

175216
if (sendMessage == null) {
176217
return "";
177218
}
178219
return sendMessage.getId();
179220
}
180221

222+
/**
223+
* Uploads a local file to the configured topic via the underlying
224+
* {@link NtfySender#sendFile(String, String, String)} and returns the
225+
* created message id on success.
226+
*
227+
* @param file the filesystem path to the file to upload
228+
* @param filename optional filename to present to recipients (may be null)
229+
* @param sequenceId optional sequence id to associate with the uploaded message
230+
* @return the created message id on success, or an empty string on failure
231+
* @throws URISyntaxException when the constructed request URI is invalid
232+
*/
181233
public String sendFile(String file, @Nullable String filename, @Nullable String sequenceId)
182234
throws URISyntaxException {
235+
final @Nullable NtfySender sender = ntfySender;
236+
if (sender == null) {
237+
return "";
238+
}
239+
183240
@Nullable
184-
MessageEvent sendMessage = ntfySender.sendFile(file, filename, sequenceId);
241+
MessageEvent sendMessage = sender.sendFile(file, filename, sequenceId);
185242

186243
if (sendMessage == null) {
187244
return "";
@@ -197,6 +254,10 @@ public String sendFile(String file, @Nullable String filename, @Nullable String
197254
* @throws URISyntaxException when the underlying request URI could not be constructed
198255
*/
199256
public boolean deleteMessage(String sequenceId) throws URISyntaxException {
200-
return ntfySender.deleteMessage(sequenceId);
257+
final @Nullable NtfySender sender = ntfySender;
258+
if (sender == null) {
259+
return false;
260+
}
261+
return sender.deleteMessage(sequenceId);
201262
}
202263
}

0 commit comments

Comments
 (0)