Skip to content

Commit

Permalink
[neohub] Improved Web-Socket Communications (#16312)
Browse files Browse the repository at this point in the history
* [neohub] Improved WebSocket Communications
* [neohub] session recycled only by handler; not by socket class

---------

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
  • Loading branch information
andrewfg committed Mar 15, 2024
1 parent 271520e commit a2db131
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ public synchronized String sendMessage(final String requestJson) throws IOExcept
IOException caughtException = null;
StringBuilder builder = new StringBuilder();

throttle();
try (Socket socket = new Socket()) {
try (Socket socket = new Socket(); Throttler throttler = new Throttler();) {
int port = config.portNumber > 0 ? config.portNumber : NeoHubBindingConstants.PORT_TCP;
socket.connect(new InetSocketAddress(config.hostName, port), config.socketTimeout * 1000);
socket.setSoTimeout(config.socketTimeout * 1000);
Expand Down Expand Up @@ -76,6 +75,8 @@ public synchronized String sendMessage(final String requestJson) throws IOExcept
} catch (IOException e) {
// catch IOExceptions here, and save them to be re-thrown later
caughtException = e;
} catch (InterruptedException e) {
caughtException = new IOException(e);
}

String responseJson = builder.toString().strip();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.eclipse.jdt.annotation.NonNullByDefault;

Expand All @@ -33,6 +35,7 @@ public abstract class NeoHubSocketBase implements Closeable {
protected final String hubId;

private static final int REQUEST_INTERVAL_MILLISECS = 1000;
private final Lock lock = new ReentrantLock(true);
private Optional<Instant> lastRequestTime = Optional.empty();

public NeoHubSocketBase(NeoHubConfiguration config, String hubId) {
Expand All @@ -51,22 +54,31 @@ public NeoHubSocketBase(NeoHubConfiguration config, String hubId) {
public abstract String sendMessage(final String requestJson) throws IOException, NeoHubException;

/**
* Method for throttling requests to prevent overloading the hub.
* Class for throttling requests to prevent overloading the hub.
* <p>
* The NeoHub can get confused if, while it is uploading data to the cloud, it also receives too many local
* requests, so this method throttles the requests to one per REQUEST_INTERVAL_MILLISECS maximum.
*
* @throws NeoHubException if the wait is interrupted
* @throws InterruptedException if the wait is interrupted
*/
protected synchronized void throttle() throws NeoHubException {
try {
Instant now = Instant.now();
long delay = lastRequestTime
.map(t -> Math.max(0, Duration.between(now, t).toMillis() + REQUEST_INTERVAL_MILLISECS)).orElse(0L);
lastRequestTime = Optional.of(now.plusMillis(delay));
protected class Throttler implements AutoCloseable {

public Throttler() throws InterruptedException {
lock.lock();
long delay;
synchronized (NeoHubSocketBase.this) {
Instant now = Instant.now();
delay = lastRequestTime
.map(t -> Math.max(0, Duration.between(now, t).toMillis() + REQUEST_INTERVAL_MILLISECS))
.orElse(0L);
lastRequestTime = Optional.of(now.plusMillis(delay));
}
Thread.sleep(delay);
} catch (InterruptedException e) {
throw new NeoHubException("Throttle sleep interrupted", e);
}

@Override
public void close() {
lock.unlock();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.neohub.internal;

import javax.net.ssl.X509ExtendedTrustManager;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
import org.openhab.core.io.net.http.TrustAllTrustManager;

/**
* A {@link TlsTrustManagerProvider} implementation to validate the NeoHub web socket self signed certificate.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubTlsTrustManagerProvider implements TlsTrustManagerProvider {

private final String fullHostName;

public NeoHubTlsTrustManagerProvider(NeoHubConfiguration config) {
fullHostName = String.format("%s:%d", config.hostName,
config.portNumber > 0 ? config.portNumber : NeoHubBindingConstants.PORT_WSS);
}

@Override
public String getHostName() {
return fullHostName;
}

@Override
public X509ExtendedTrustManager getTrustManager() {
return TrustAllTrustManager.getInstance();
}
}

0 comments on commit a2db131

Please sign in to comment.