2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.samsungtv.internal.protocol;
15 import java.io.IOException;
17 import java.nio.ByteBuffer;
18 import java.util.Optional;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.TimeUnit;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.eclipse.jetty.websocket.api.Session;
25 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
26 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * Websocket base class
33 * @author Arjan Mels - Initial contribution
34 * @author Nick Waterton - refactoring
37 class WebSocketBase extends WebSocketAdapter {
38 private final Logger logger = LoggerFactory.getLogger(WebSocketBase.class);
39 final RemoteControllerWebSocket remoteControllerWebSocket;
40 final int bufferSize = 1048576; // 1 Mb
42 private Optional<Future<?>> sessionFuture = Optional.empty();
44 private String host = "";
45 private String className = "";
46 private Optional<URI> uri = Optional.empty();
47 private int count = 0;
50 * @param remoteControllerWebSocket
52 WebSocketBase(RemoteControllerWebSocket remoteControllerWebSocket) {
53 this.remoteControllerWebSocket = remoteControllerWebSocket;
54 this.host = remoteControllerWebSocket.host;
55 this.className = this.getClass().getSimpleName();
59 public void onWebSocketClose(int statusCode, @Nullable String reason) {
60 logger.debug("{}: {} connection closed: {} - {}", host, className, statusCode, reason);
61 super.onWebSocketClose(statusCode, reason);
62 if (statusCode == 1001) {
66 if (statusCode == 1006) {
73 public void onWebSocketError(@Nullable Throwable error) {
74 logger.debug("{}: {} connection error {}", host, className, error != null ? error.getMessage() : "");
75 super.onWebSocketError(error);
80 if (sessionFuture.isPresent() && count++ < 4) {
83 logger.debug("{}: Reconnecting : {} try: {}", host, className, count);
84 remoteControllerWebSocket.callback.handler.getScheduler().schedule(() -> {
86 }, 2000, TimeUnit.MILLISECONDS);
88 } catch (RemoteControllerException e) {
89 logger.warn("{} Reconnect Failed {} : {}", host, className, e.getMessage());
98 void connect(URI uri) throws RemoteControllerException {
100 if (isConnected() || sessionFuture.map(sf -> !sf.isDone()).orElse(false)) {
101 logger.trace("{}: {} already connecting or connected", host, className);
104 logger.debug("{}: {} connecting to: {}", host, className, uri);
105 this.uri = Optional.of(uri);
107 sessionFuture = Optional.of(remoteControllerWebSocket.client.connect(this, uri));
108 } catch (IOException | IllegalStateException e) {
109 throw new RemoteControllerException(e);
114 public void onWebSocketConnect(@Nullable Session session) {
115 logger.debug("{}: {} connection established: {}", host, className,
116 session != null ? session.getRemoteAddress().getHostString() : "");
117 if (session != null) {
118 final WebSocketPolicy currentPolicy = session.getPolicy();
119 currentPolicy.setInputBufferSize(bufferSize);
120 currentPolicy.setMaxTextMessageSize(bufferSize);
121 currentPolicy.setMaxBinaryMessageSize(bufferSize);
122 logger.trace("{}: {} Buffer Size set to {} Mb", host, className,
123 Math.round((bufferSize / 1048576.0) * 100.0) / 100.0);
124 // avoid 5 minute idle timeout
125 remoteControllerWebSocket.callback.handler.getScheduler().scheduleWithFixedDelay(() -> {
127 String data = "Ping";
128 ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
129 session.getRemote().sendPing(payload);
130 } catch (IOException e) {
131 logger.warn("{} problem starting periodic Ping {} : {}", host, className, e.getMessage());
133 }, 4, 4, TimeUnit.MINUTES);
135 super.onWebSocketConnect(session);
140 this.sessionFuture.ifPresent(sf -> {
142 logger.trace("{}: Cancelling session Future: {}", host, sf);
146 sessionFuture = Optional.empty();
147 Optional.ofNullable(getSession()).ifPresent(s -> {
148 logger.debug("{}: {} Connection close requested", host, className);
153 void sendCommand(String cmd) {
156 getRemote().sendString(cmd);
157 logger.trace("{}: {}: sendCommand: {}", host, className, cmd);
159 logger.warn("{}: {} not connected: {}", host, className, cmd);
161 } catch (IOException e) {
162 logger.warn("{}: {}: cannot send command: {}", host, className, e.getMessage());
167 public void onWebSocketText(@Nullable String str) {
168 logger.trace("{}: {}: onWebSocketText: {}", host, className, str);
172 public void onWebSocketBinary(byte @Nullable [] arr, int pos, int len) {
173 logger.trace("{}: {}: onWebSocketBinary: offset: {}, len: {}", host, className, pos, len);