]> git.basschouten.com Git - openhab-addons.git/blob
d74f2fe1b58773f0965e324a50787459dfbabecb
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.fsinternetradio.internal.radio;
14
15 import java.io.IOException;
16 import java.util.concurrent.TimeUnit;
17
18 import org.eclipse.jetty.client.HttpClient;
19 import org.eclipse.jetty.client.api.ContentResponse;
20 import org.eclipse.jetty.client.api.Request;
21 import org.eclipse.jetty.http.HttpMethod;
22 import org.eclipse.jetty.http.HttpStatus;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * This class holds the http-connection and session information for controlling the radio.
28  *
29  * @author Rainer Ostendorf
30  * @author Patrick Koenemann
31  * @author Svilen Valkanov - replaced Apache HttpClient with Jetty
32  * @author Mihaela Memova - changed the calling of the stopHttpClient() method, fixed the hardcoded URL path, fixed the
33  *         for loop condition part
34  */
35 public class FrontierSiliconRadioConnection {
36
37     private final Logger logger = LoggerFactory.getLogger(FrontierSiliconRadioConnection.class);
38
39     /** Timeout for HTTP requests in ms */
40     private static final int SOCKET_TIMEOUT = 5000;
41
42     /** Hostname of the radio. */
43     private final String hostname;
44
45     /** Port number, usually 80. */
46     private final int port;
47
48     /** Access pin, passed upon login as GET parameter. */
49     private final String pin;
50
51     /** The session ID we get from the radio after logging in. */
52     private String sessionId;
53
54     /** http clients, store cookies, so it is kept in connection class. */
55     private HttpClient httpClient = null;
56
57     /** Flag indicating if we are successfully logged in. */
58     private boolean isLoggedIn = false;
59
60     public FrontierSiliconRadioConnection(String hostname, int port, String pin, HttpClient httpClient) {
61         this.hostname = hostname;
62         this.port = port;
63         this.pin = pin;
64         this.httpClient = httpClient;
65     }
66
67     public boolean isLoggedIn() {
68         return isLoggedIn;
69     }
70
71     /**
72      * Perform login/establish a new session. Uses the PIN number and when successful saves the assigned sessionID for
73      * future requests.
74      *
75      * @return <code>true</code> if login was successful; <code>false</code> otherwise.
76      * @throws IOException if communication with the radio failed, e.g. because the device is not reachable.
77      */
78     public boolean doLogin() throws IOException {
79         isLoggedIn = false; // reset login flag
80
81         final String url = "http://" + hostname + ":" + port + FrontierSiliconRadioConstants.CONNECTION_PATH
82                 + "/CREATE_SESSION?pin=" + pin;
83
84         logger.trace("opening URL: {}", url);
85
86         Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(SOCKET_TIMEOUT,
87                 TimeUnit.MILLISECONDS);
88
89         try {
90             ContentResponse response = request.send();
91             int statusCode = response.getStatus();
92             if (statusCode != HttpStatus.OK_200) {
93                 String reason = response.getReason();
94                 logger.debug("Communication with radio failed: {} {}", statusCode, reason);
95                 if (statusCode == HttpStatus.FORBIDDEN_403) {
96                     throw new IllegalStateException("Radio does not allow connection, maybe wrong pin?");
97                 }
98                 throw new IOException("Communication with radio failed, return code: " + statusCode);
99             }
100
101             final String responseBody = response.getContentAsString();
102             if (!responseBody.isEmpty()) {
103                 logger.trace("login response: {}", responseBody);
104             }
105
106             final FrontierSiliconRadioApiResult result = new FrontierSiliconRadioApiResult(responseBody);
107             if (result.isStatusOk()) {
108                 logger.trace("login successful");
109                 sessionId = result.getSessionId();
110                 isLoggedIn = true;
111                 return true; // login successful :-)
112             }
113
114         } catch (Exception e) {
115             logger.debug("Fatal transport error: {}", e.toString());
116             throw new IOException(e);
117         }
118
119         return false; // login not successful
120     }
121
122     /**
123      * Performs a request to the radio with no further parameters.
124      *
125      * Typically used for polling state info.
126      *
127      * @param REST
128      *            API requestString, e.g. "GET/netRemote.sys.power"
129      * @return request result
130      * @throws IOException if the request failed.
131      */
132     public FrontierSiliconRadioApiResult doRequest(String requestString) throws IOException {
133         return doRequest(requestString, null);
134     }
135
136     /**
137      * Performs a request to the radio with addition parameters.
138      *
139      * Typically used for changing parameters.
140      *
141      * @param REST
142      *            API requestString, e.g. "SET/netRemote.sys.power"
143      * @param params
144      *            , e.g. "value=1"
145      * @return request result
146      * @throws IOException if the request failed.
147      */
148     public FrontierSiliconRadioApiResult doRequest(String requestString, String params) throws IOException {
149         // 3 retries upon failure
150         for (int i = 0; i < 3; i++) {
151             if (!isLoggedIn && !doLogin()) {
152                 continue; // not logged in and login was not successful - try again!
153             }
154
155             final String url = "http://" + hostname + ":" + port + FrontierSiliconRadioConstants.CONNECTION_PATH + "/"
156                     + requestString + "?pin=" + pin + "&sid=" + sessionId
157                     + (params == null || params.trim().length() == 0 ? "" : "&" + params);
158
159             logger.trace("calling url: '{}'", url);
160
161             Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(SOCKET_TIMEOUT,
162                     TimeUnit.MILLISECONDS);
163
164             try {
165                 ContentResponse response = request.send();
166                 final int statusCode = response.getStatus();
167                 if (statusCode != HttpStatus.OK_200) {
168                     /*-
169                      * Issue: https://github.com/eclipse/smarthome/issues/2548
170                      * If the session expired, we might get a 404 here. That's ok, remember that we are not logged-in
171                      * and try again. Print warning only if this happens in the last iteration.
172                      */
173                     if (i >= 2) {
174                         String reason = response.getReason();
175                         logger.warn("Method failed: {}  {}", statusCode, reason);
176                     }
177                     isLoggedIn = false;
178                     continue;
179                 }
180
181                 final String responseBody = response.getContentAsString();
182                 if (!responseBody.isEmpty()) {
183                     logger.trace("got result: {}", responseBody);
184                 } else {
185                     logger.debug("got empty result");
186                     isLoggedIn = false;
187                     continue;
188                 }
189
190                 final FrontierSiliconRadioApiResult result = new FrontierSiliconRadioApiResult(responseBody);
191                 if (result.isStatusOk()) {
192                     return result;
193                 }
194
195                 isLoggedIn = false;
196                 continue; // try again
197             } catch (Exception e) {
198                 logger.error("Fatal transport error: {}", e.toString());
199                 throw new IOException(e);
200             }
201         }
202         isLoggedIn = false; // 3 tries failed. log in again next time, maybe our session went invalid (radio restarted?)
203         return null;
204     }
205 }