]> git.basschouten.com Git - openhab-addons.git/blob
e8cd515f0252d2ca1be33a5a0b34d17d7810835c
[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.asuswrt.internal.api;
14
15 import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.JSON_MEMBER_TOKEN;
16 import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
17 import static org.openhab.binding.asuswrt.internal.constants.AsuswrtErrorConstants.*;
18 import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.getValueOrDefault;
19
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.TimeoutException;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.jetty.client.HttpResponse;
26 import org.eclipse.jetty.client.api.ContentResponse;
27 import org.eclipse.jetty.client.api.Request;
28 import org.eclipse.jetty.client.api.Result;
29 import org.eclipse.jetty.client.util.BufferingResponseListener;
30 import org.eclipse.jetty.client.util.StringContentProvider;
31 import org.eclipse.jetty.http.HttpMethod;
32 import org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils;
33 import org.openhab.binding.asuswrt.internal.things.AsuswrtRouter;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.gson.Gson;
38 import com.google.gson.JsonObject;
39
40 /**
41  * The {@link AsuswrtHttpClient} is used for (a)synchronous HTTP requests.
42  *
43  * @author Christian Wild - Initial contribution
44  */
45 @NonNullByDefault
46 public class AsuswrtHttpClient {
47     private final Logger logger = LoggerFactory.getLogger(AsuswrtHttpClient.class);
48     private Gson gson = new Gson();
49     protected AsuswrtRouter router;
50     protected final String uid;
51     public AsuswrtCookie cookieStore = new AsuswrtCookie();
52
53     public AsuswrtHttpClient(AsuswrtRouter router) {
54         this.router = router;
55         uid = router.getUID().toString();
56     }
57
58     /*
59      * HTTP actions
60      */
61
62     /**
63      * Sends a synchronous HTTP request.
64      *
65      * The result will be handled in {@link #handleHttpSuccessResponse(String, String) or
66      * {@link #handleHttpResultError(Throwable)}.
67      *
68      * If the response should be returned use {@link #getSyncRequest(String, String)} instead.
69      *
70      * @param url the URL the request is sent to
71      * @param payload the payload to send
72      * @param command the command to perform
73      */
74     protected void sendSyncRequest(String url, String payload, String command) {
75         ContentResponse response = getSyncRequest(url, payload);
76         if (response != null) {
77             handleHttpSuccessResponse(response.getContentAsString(), command);
78         }
79     }
80
81     /**
82      * Sends a synchronous HTTP request.
83      *
84      * @param url the URL the request is sent to
85      * @param payload the payload to send
86      * @return {@link ContentResponse} of the request
87      */
88     protected @Nullable ContentResponse getSyncRequest(String url, String payload) {
89         logger.trace("({}) sendRequest '{}' to '{}' with cookie '{}'", uid, payload, url, cookieStore.getCookie());
90         Request httpRequest = this.router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString());
91
92         // Set header
93         httpRequest = setHeaders(httpRequest);
94         httpRequest.timeout(HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
95
96         // Add request body
97         httpRequest.content(new StringContentProvider(payload, HTTP_CONTENT_CHARSET), HTTP_CONTENT_TYPE);
98         try {
99             return httpRequest.send();
100         } catch (Exception e) {
101             handleHttpResultError(e);
102         }
103         return null;
104     }
105
106     /**
107      * Sends an asynchronous HTTP request so it does not wait for an answer.
108      *
109      * The result will be handled in {@link #handleHttpSuccessResponse(String, String) or
110      * {@link #handleHttpResultError(Throwable)}.
111      *
112      * @param url the URL to which the request is sent to
113      * @param payload the payload data
114      * @param command command to execute, this will handle ResponseType
115      */
116     protected void sendAsyncRequest(String url, String payload, String command) {
117         logger.trace("({}) sendAsyncRequest to '{}' with cookie '{}'", uid, url, cookieStore.getCookie());
118         try {
119             Request httpRequest = router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString());
120
121             // Set header
122             httpRequest = setHeaders(httpRequest);
123
124             // Add request body
125             httpRequest.content(new StringContentProvider(payload, HTTP_CONTENT_CHARSET), HTTP_CONTENT_TYPE);
126
127             httpRequest.timeout(HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS).send(new BufferingResponseListener() {
128                 @NonNullByDefault({})
129                 @Override
130                 public void onComplete(Result result) {
131                     final HttpResponse response = (HttpResponse) result.getResponse();
132                     if (result.getFailure() != null) {
133                         // Handle result errors
134                         handleHttpResultError(result.getFailure());
135                     } else if (response.getStatus() != 200) {
136                         logger.debug("({}) sendAsyncRequest response error '{}'", uid, response.getStatus());
137                         router.errorHandler.raiseError(ERR_RESPONSE, getContentAsString());
138                     } else {
139                         // Request successful
140                         String rBody = getContentAsString();
141                         logger.trace("({}) requestCompleted '{}'", uid, rBody);
142                         // Handle result
143                         handleHttpSuccessResponse(rBody, command);
144                     }
145                 }
146             });
147         } catch (Exception e) {
148             router.errorHandler.raiseError(e);
149         }
150     }
151
152     /**
153      * Sets HTTP headers.
154      */
155     private Request setHeaders(Request httpRequest) {
156         // Set header
157         httpRequest.header("content-type", HTTP_CONTENT_TYPE);
158         httpRequest.header("user-agent", HTTP_USER_AGENT);
159         if (cookieStore.isValid()) {
160             httpRequest.header("cookie", cookieStore.getCookie());
161         }
162         return httpRequest;
163     }
164
165     /*
166      * Response handling
167      */
168
169     /**
170      * Handles HTTP result failures.
171      *
172      * @param e the exception
173      * @param payload full payload for debugging
174      */
175     protected void handleHttpResultError(Throwable e, String payload) {
176         String errorMessage = getValueOrDefault(e.getMessage(), "");
177
178         if (e instanceof TimeoutException) {
179             logger.debug("({}) sendAsyncRequest timeout'{}'", uid, errorMessage);
180         } else if (e instanceof InterruptedException) {
181             logger.debug("({}) sending request interrupted: {}", uid, e.toString());
182         } else {
183             logger.debug("({}) sendAsyncRequest failed'{}'", uid, errorMessage);
184         }
185     }
186
187     protected void handleHttpResultError(Throwable e) {
188         handleHttpResultError(e, "");
189     }
190
191     /**
192      * Handles a successful HTTP response.
193      *
194      * @param responseBody response body as string
195      * @param command command constant which was sent
196      */
197     protected void handleHttpSuccessResponse(String responseBody, String command) {
198     }
199
200     /**
201      * Sets a cookie from a response.
202      */
203     protected void setCookieFromResponse(ContentResponse response) {
204         cookieStore.resetCookie();
205         if (response.getStatus() == 200) {
206             String rBody = response.getContentAsString();
207             logger.trace("({}) received response '{}'", uid, rBody);
208             try {
209                 /* get json object 'asus_token' */
210                 JsonObject jsonObject = gson.fromJson(rBody, JsonObject.class);
211                 if (jsonObject != null && jsonObject.has(JSON_MEMBER_TOKEN)) {
212                     String token = jsonObject.get(JSON_MEMBER_TOKEN).getAsString();
213                     this.cookieStore.setCookie("asus_token=" + token);
214                 }
215             } catch (Exception e) {
216                 logger.debug("({}) {} on login request '{}'", uid, ERR_RESPONSE, e.getMessage());
217                 router.errorHandler.raiseError(ERR_RESPONSE, e.getMessage());
218             }
219         } else {
220             String reason = AsuswrtUtils.getValueOrDefault(response.getReason(), "");
221             router.errorHandler.raiseError(ERR_RESPONSE, reason);
222         }
223     }
224
225     /**
226      * Gets JSON from a response.
227      */
228     protected JsonObject getJsonFromResponse(ContentResponse response) {
229         return getJsonFromString(response.getContentAsString());
230     }
231
232     /**
233      * Gets JSON from a response.
234      */
235     protected JsonObject getJsonFromString(String responseBody) {
236         try {
237             JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
238             logger.trace("({}) received result: {}", uid, responseBody);
239             /* get error code (0=success) */
240             if (jsonObject != null) {
241                 return jsonObject;
242             }
243         } catch (Exception e) {
244             logger.debug("({}) {} {}", uid, ERR_JSON_FORMAT, responseBody);
245             router.getErrorHandler().raiseError(e);
246         }
247         return new JsonObject();
248     }
249 }