]> git.basschouten.com Git - openhab-addons.git/blob
d67b3edc7e9b878c77ecfc4764ad869c8d66a664
[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.freeboxos.internal.api.rest;
14
15 import java.lang.reflect.Constructor;
16 import java.lang.reflect.InvocationTargetException;
17 import java.net.URI;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import javax.ws.rs.core.UriBuilder;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.http.HttpMethod;
27 import org.openhab.binding.freeboxos.internal.api.ApiHandler;
28 import org.openhab.binding.freeboxos.internal.api.FreeboxException;
29 import org.openhab.binding.freeboxos.internal.api.PermissionException;
30 import org.openhab.binding.freeboxos.internal.api.Response;
31 import org.openhab.binding.freeboxos.internal.api.Response.ErrorCode;
32 import org.openhab.binding.freeboxos.internal.api.rest.LoginManager.Session;
33 import org.openhab.binding.freeboxos.internal.config.FreeboxOsConfiguration;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link FreeboxOsSession} is responsible for sending requests toward a given url and transform the answer in
39  * appropriate dto.
40  *
41  * @author GaĆ«l L'Hopital - Initial contribution
42  */
43 @NonNullByDefault
44 public class FreeboxOsSession {
45     private static final String API_VERSION_PATH = "api_version";
46
47     private final Logger logger = LoggerFactory.getLogger(FreeboxOsSession.class);
48     private final Map<Class<? extends RestManager>, RestManager> restManagers = new HashMap<>();
49     private final ApiHandler apiHandler;
50
51     private @NonNullByDefault({}) UriBuilder uriBuilder;
52     private @Nullable Session session;
53     private String appToken = "";
54
55     public static enum BoxModel {
56         FBXGW_R1_FULL, // Freebox Server (v6) revision 1
57         FBXGW_R2_FULL, // Freebox Server (v6) revision 2
58         FBXGW_R1_MINI, // Freebox Mini revision 1
59         FBXGW_R2_MINI, // Freebox Mini revision 2
60         FBXGW_R1_ONE, // Freebox One revision 1
61         FBXGW_R2_ONE, // Freebox One revision 2
62         FBXGW7_R1_FULL, // Freebox v7 revision 1
63         UNKNOWN;
64     }
65
66     public static record ApiVersion(String apiBaseUrl, @Nullable String apiDomain, String apiVersion, BoxModel boxModel,
67             @Nullable String boxModelName, String deviceName, String deviceType, boolean httpsAvailable, int httpsPort,
68             String uid) {
69
70         /**
71          * @return a string like eg: '/api/v8'
72          */
73         private String baseUrl() {
74             return "%sv%s".formatted(apiBaseUrl, apiVersion.split("\\.")[0]);
75         }
76     }
77
78     public FreeboxOsSession(ApiHandler apiHandler) {
79         this.apiHandler = apiHandler;
80     }
81
82     public void initialize(FreeboxOsConfiguration config) throws FreeboxException, InterruptedException {
83         ApiVersion version = apiHandler.executeUri(config.getUriBuilder(API_VERSION_PATH).build(), HttpMethod.GET,
84                 ApiVersion.class, null, null);
85         this.uriBuilder = config.getUriBuilder(version.baseUrl());
86         getManager(LoginManager.class);
87         getManager(NetShareManager.class);
88         getManager(LanManager.class);
89         getManager(WifiManager.class);
90         getManager(FreeplugManager.class);
91         getManager(AirMediaManager.class);
92     }
93
94     public void openSession(String appToken) throws FreeboxException {
95         Session newSession = getManager(LoginManager.class).openSession(appToken);
96         getManager(WebSocketManager.class).openSession(newSession.sessionToken());
97         session = newSession;
98         this.appToken = appToken;
99     }
100
101     public String grant() throws FreeboxException {
102         return getManager(LoginManager.class).checkGrantStatus();
103     }
104
105     public void closeSession() {
106         Session currentSession = session;
107         if (currentSession != null) {
108             try {
109                 getManager(WebSocketManager.class).closeSession();
110                 getManager(LoginManager.class).closeSession();
111                 session = null;
112             } catch (FreeboxException e) {
113                 logger.warn("Error closing session: {}", e.getMessage());
114             }
115         }
116         appToken = "";
117         restManagers.clear();
118     }
119
120     private synchronized <F, T extends Response<F>> List<F> execute(URI uri, HttpMethod method, Class<T> clazz,
121             boolean retryAuth, int retryCount, @Nullable Object aPayload) throws FreeboxException {
122         try {
123             T response = apiHandler.executeUri(uri, method, clazz, getSessionToken(), aPayload);
124             if (response.getErrorCode() == ErrorCode.INTERNAL_ERROR && retryCount > 0) {
125                 return execute(uri, method, clazz, false, retryCount - 1, aPayload);
126             } else if (retryAuth && response.getErrorCode() == ErrorCode.AUTH_REQUIRED) {
127                 openSession(appToken);
128                 return execute(uri, method, clazz, false, retryCount, aPayload);
129             }
130             if (!response.isSuccess()) {
131                 throw new FreeboxException("Api request failed: %s", response.getMsg());
132             }
133             return response.getResult();
134         } catch (FreeboxException e) {
135             if (ErrorCode.AUTH_REQUIRED.equals(e.getErrorCode())) {
136                 openSession(appToken);
137                 return execute(uri, method, clazz, false, retryCount, aPayload);
138             }
139             throw e;
140         } catch (InterruptedException ignored) {
141             return List.of();
142         }
143     }
144
145     public <F, T extends Response<F>> List<F> execute(URI uri, HttpMethod method, Class<T> clazz,
146             @Nullable Object aPayload) throws FreeboxException {
147         return execute(uri, method, clazz, getSessionToken() != null, 3, aPayload);
148     }
149
150     @SuppressWarnings("unchecked")
151     public synchronized <T extends RestManager> T getManager(Class<T> clazz) throws FreeboxException {
152         RestManager manager = restManagers.get(clazz);
153         if (manager == null) {
154             try {
155                 Constructor<T> managerConstructor = clazz.getConstructor(FreeboxOsSession.class);
156                 manager = addManager(clazz, managerConstructor.newInstance(this));
157             } catch (InvocationTargetException e) {
158                 Throwable cause = e.getCause();
159                 if (cause instanceof PermissionException) {
160                     throw (PermissionException) cause;
161                 }
162                 throw new FreeboxException(e, "Unable to call RestManager constructor for %s", clazz.getName());
163             } catch (ReflectiveOperationException e) {
164                 throw new FreeboxException(e, "Unable to call RestManager constructor for %s", clazz.getName());
165             }
166         }
167         return (T) manager;
168     }
169
170     public <T extends RestManager> T addManager(Class<T> clazz, T manager) {
171         restManagers.put(clazz, manager);
172         return manager;
173     }
174
175     boolean hasPermission(LoginManager.Permission required) {
176         Session currentSession = session;
177         return currentSession != null ? currentSession.hasPermission(required) : false;
178     }
179
180     private @Nullable String getSessionToken() {
181         Session currentSession = session;
182         return currentSession != null ? currentSession.sessionToken() : null;
183     }
184
185     public UriBuilder getUriBuilder() {
186         return uriBuilder.clone();
187     }
188
189     public ApiHandler getApiHandler() {
190         return apiHandler;
191     }
192 }