Skip to content

Commit

Permalink
[hydrawise] Handle API auth changes (openhab#16221)
Browse files Browse the repository at this point in the history
* Handles a new condition where the service rejects a request as unauthorized, but really we just need to refresh our token after 60 seconds.

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
  • Loading branch information
digitaldan authored Jan 7, 2024
1 parent 90480d0 commit c8d2d4b
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ public void onFailure(@Nullable Response response, @Nullable Throwable failure)
} catch (ExecutionException e) {
// Hydrawise returns back a 40x status, but without a valid Realm , so jetty throws an exception,
// this allows us to catch this in a callback and handle accordingly
logger.debug("ExecutionException", e);
logger.debug("ExecutionException {} {}", responseCode.get(), responseMessage);
switch (responseCode.get()) {
case 401:
case 403:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
* Minimum amount of time we can poll for updates
*/
private static final int MIN_REFRESH_SECONDS = 30;
private static final int TOKEN_REFRESH_SECONDS = 60;
private static final String BASE_URL = "https://app.hydrawise.com/api/v2/";
private static final String AUTH_URL = BASE_URL + "oauth/access-token";
private static final String CLIENT_SECRET = "zn3CrjglwNV1";
Expand All @@ -74,6 +75,7 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
private @Nullable OAuthClientService oAuthService;
private @Nullable HydrawiseGraphQLClient apiClient;
private @Nullable ScheduledFuture<?> pollFuture;
private @Nullable ScheduledFuture<?> tokenFuture;
private @Nullable Customer lastData;
private int refresh;

Expand Down Expand Up @@ -102,6 +104,7 @@ public void initialize() {
public void dispose() {
logger.debug("Handler disposed.");
clearPolling();
clearTokenRefresh();
OAuthClientService oAuthService = this.oAuthService;
if (oAuthService != null) {
oAuthService.removeAccessTokenRefreshListener(this);
Expand Down Expand Up @@ -184,20 +187,40 @@ private synchronized void initPolling(int initalDelay, int refresh) {
pollFuture = scheduler.scheduleWithFixedDelay(this::poll, initalDelay, refresh, TimeUnit.SECONDS);
}

/**
* The API will randomly reject a request with a 401 not authorized, waiting a min and refreshing the token usually
* fixes it
*/
private synchronized void retryToken() {
clearTokenRefresh();
tokenFuture = scheduler.schedule(() -> {
try {
OAuthClientService oAuthService = this.oAuthService;
if (oAuthService != null) {
oAuthService.refreshToken();
initPolling(0, MIN_REFRESH_SECONDS);
}
} catch (OAuthException | IOException | OAuthResponseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
}
}, TOKEN_REFRESH_SECONDS, TimeUnit.SECONDS);
}

/**
* Stops/clears this thing's polling future
*/
private void clearPolling() {
ScheduledFuture<?> localFuture = pollFuture;
if (isFutureValid(localFuture)) {
if (localFuture != null) {
localFuture.cancel(false);
}
}
clearFuture(pollFuture);
}

private boolean isFutureValid(@Nullable ScheduledFuture<?> future) {
return future != null && !future.isCancelled();
private void clearTokenRefresh() {
clearFuture(tokenFuture);
}

private void clearFuture(@Nullable final ScheduledFuture<?> future) {
if (future != null) {
future.cancel(true);
}
}

private void poll() {
Expand Down Expand Up @@ -232,8 +255,10 @@ private void poll(boolean retry) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
} catch (HydrawiseAuthenticationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
logger.debug("Token has been rejected, will try to refresh token in {} secs: {}", TOKEN_REFRESH_SECONDS,
e.getLocalizedMessage());
clearPolling();
retryToken();
}
}
}

0 comments on commit c8d2d4b

Please sign in to comment.