Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General code cleanup #183

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions bridge/src/main/java/dev/cookiecode/rika2mqtt/bridge/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import dev.cookiecode.rika2mqtt.rika.firenet.exception.UnableToRetrieveRikaFirenetDataException;
import dev.cookiecode.rika2mqtt.rika.firenet.model.StoveId;
import dev.cookiecode.rika2mqtt.rika.firenet.model.StoveStatus;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttService;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttPublicationService;
import dev.cookiecode.rika2mqtt.rika.mqtt.event.MqttCommandEvent;
import jakarta.annotation.PostConstruct;
import java.time.Duration;
Expand All @@ -55,25 +55,29 @@
import org.springframework.stereotype.Component;

/**
* Bridge class responsible for initializing, polling stove status, handling MQTT commands, and
* publishing to MQTT.
*
* @author Sebastien Vermeille
*/
@Component
@RequiredArgsConstructor
@Flogger
public class Bridge {

static final String INITIALIZING_BRIDGE = "Initializing Rika2Mqtt bridge :";
static final String RECEIVED_MQTT_COMMAND_FOR_STOVE_S = "Received mqtt command for stove: %s";
static final String COULD_NOT_PROCESS_THE_RECEIVED_MQTT_COMMAND_S =
"Could not process the received mqtt command: %s";
static final String
COULD_NOT_RETRIEVE_ANY_STOVE_LINKED_WITH_ACCOUNT_S_PLEASE_DOUBLE_CHECK_YOUR_CONFIGURATION =
"Could not retrieve any stove linked with account %s. Please double-check your configuration.";
static final String
WILL_NOW_RETRIEVE_STATUS_FOR_EACH_DECLARED_STOVES_AT_INTERVAL_OF_S_AND_PUBLISH_IT_BACK_TO_MQTT =
"Will now retrieve status for each declared stove(s) at interval of %s and publish it back to mqtt.";
private static final String INITIALIZING_BRIDGE = "Initializing Rika2Mqtt bridge :";
private static final String COULD_NOT_PROCESS_THE_RECEIVED_MQTT_COMMAND_S =
"Could not process the received mqtt command: %s";

private final RikaFirenetService rikaFirenetService;
private final MqttService mqttService;
private final MqttPublicationService mqttPublicationService;

@Value("${rika.email}")
private String rikaEmailAccount;
Expand Down Expand Up @@ -138,11 +142,11 @@ void publishToMqtt() {
try {
status = rikaFirenetService.getStatus(stoveId);
final var jsonStatus = gson.toJson(status);
mqttService.publish(jsonStatus);
mqttPublicationService.publish(jsonStatus);

applicationEventPublisher.publishEvent(
PolledStoveStatusEvent.builder()
.stoveStatus(stoveStatusMapper.toApiStoveStatus(status))
.withStoveStatus(stoveStatusMapper.toApiStoveStatus(status))
.build());

handleStoveErrors(status);
Expand Down Expand Up @@ -177,10 +181,10 @@ private void handleStoveErrors(@NonNull StoveStatus status) {
new ErrorNotification(stoveId, enrichedStoveError.getErrorCode());

final var jsonNotification = gson.toJson(notification);
mqttService.publishNotification(jsonNotification);
mqttPublicationService.publishNotification(jsonNotification);

applicationEventPublisher.publishEvent(
StoveErrorEvent.builder().stoveError(enrichedStoveError).build());
StoveErrorEvent.builder().withStoveError(enrichedStoveError).build());
});
}

Expand All @@ -197,7 +201,6 @@ public void onReceiveMqttCommand(@NonNull MqttCommandEvent event) {
} catch (OutdatedRevisionException ex) {
log.atWarning().withCause(ex).log(
COULD_NOT_PROCESS_THE_RECEIVED_MQTT_COMMAND_S, ex.getMessage());
// TODO: implement a retry policy (once at least)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
*/
package dev.cookiecode.rika2mqtt.bridge.configuration;

import static java.time.Duration.ofSeconds;

import java.time.Duration;
import lombok.Data;
import lombok.NonNull;
Expand All @@ -38,5 +40,5 @@
@Validated
public class BridgeConfigProperties {

@NonNull private Duration reportInterval = Duration.ofSeconds(30);
@NonNull private Duration reportInterval = ofSeconds(30);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@
@Component
public class EmailObfuscator {

private static final String AT_SYMBOL = "@";
private static final String MASK = "*****";

public String maskEmailAddress(@NonNull final String email) {
final var mask = "*****";
final int at = email.indexOf("@");
final int at = email.indexOf(AT_SYMBOL);
if (at > 2) {
final int maskLen = Math.min(Math.max(at / 2, 2), 4);
final int start = (at - maskLen) / 2;
return email.substring(0, start)
+ mask.substring(0, maskLen)
+ MASK.substring(0, maskLen)
+ email.substring(start + maskLen);
}
return email;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,24 @@

import static dev.cookiecode.rika2mqtt.bridge.model.NotificationType.ERROR;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;

/**
* Notification send to MQTT as json
*
* @author Sebastien Vermeille
*/
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErrorNotification extends Notification {

private String errorCode;
private final String errorCode;

public ErrorNotification(Long stoveId, String errorCode) {
public ErrorNotification(@NonNull Long stoveId, @NonNull String errorCode) {
super(stoveId, ERROR);
this.errorCode = errorCode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
*/
package dev.cookiecode.rika2mqtt.bridge.model;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

/**
* Notification send to MQTT as json
Expand All @@ -32,6 +34,8 @@
*/
@Getter
@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
public class Notification {
private final Long stoveId;
private final NotificationType type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
package dev.cookiecode.rika2mqtt.bridge;

import com.google.gson.Gson;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttService;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttServiceImpl;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttPublicationService;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttPublicationServiceImpl;
import dev.cookiecode.rika2mqtt.rika.mqtt.configuration.MqttConfigProperties;
import dev.cookiecode.rika2mqtt.rika.mqtt.configuration.MqttConfiguration;
import java.util.UUID;
Expand All @@ -42,11 +42,11 @@
*
* @author Sebastien Vermeille
*/
@SpringBootTest(classes = {MqttServiceImpl.class, MqttConfiguration.class, Gson.class})
@SpringBootTest(classes = {MqttPublicationServiceImpl.class, MqttConfiguration.class, Gson.class})
@ActiveProfiles("test")
class BridgeIntegrationTest extends AbstractBaseIntegrationTest {

@Autowired private MqttService mqttService;
@Autowired private MqttPublicationService mqttPublicationService;

@Autowired private MqttConfigProperties mqttConfigProperties;

Expand All @@ -64,7 +64,7 @@ void publishMqttMessageFromBridgeShouldEffectivelyPublishAMessageToMqtt() {
.assertThatMessageWasPublishedToMqttTopic(
message,
mqttConfigProperties.getTelemetryReportTopicName(),
() -> mqttService.publish(message));
() -> mqttPublicationService.publish(message));
}

@Test
Expand All @@ -78,7 +78,7 @@ void publishErrorMqttMessageFromBridgeShouldEffectivelyPublishAnErrorMessageToMq
.assertThatMessageWasPublishedToMqttTopic(
message,
mqttConfigProperties.getNotificationTopicName(),
() -> mqttService.publishNotification(message));
() -> mqttPublicationService.publishNotification(message));
}

private MqttTestClient getMqttTestClient() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import dev.cookiecode.rika2mqtt.rika.firenet.model.StoveError;
import dev.cookiecode.rika2mqtt.rika.firenet.model.StoveId;
import dev.cookiecode.rika2mqtt.rika.firenet.model.StoveStatus;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttService;
import dev.cookiecode.rika2mqtt.rika.mqtt.MqttPublicationService;
import dev.cookiecode.rika2mqtt.rika.mqtt.event.MqttCommandEvent;
import java.time.Duration;
import java.util.HashMap;
Expand All @@ -67,7 +67,7 @@
class BridgeTest {

@Mock RikaFirenetService rikaFirenetService;
@Mock MqttService mqttService;
@Mock MqttPublicationService mqttPublicationService;
@Mock EmailObfuscator emailObfuscator;
@Mock Gson gson;
@Mock StoveStatusMapper stoveStatusMapper;
Expand Down Expand Up @@ -182,7 +182,7 @@ void publishToMqttShouldInvokeMqttServicePublishForEachStove() throws Exception
bridge.publishToMqtt();

// THEN
verify(mqttService, times(stoves.size())).publish(any());
verify(mqttPublicationService, times(stoves.size())).publish(any());
}

@Test
Expand Down Expand Up @@ -215,6 +215,7 @@ void publishToMqttShouldInvokeMqttServicePublishNotificationForEachStoveHavingAn
.thenReturn(Optional.of(StoveError.builder().statusError(1).statusSubError(12).build()));

final var enrichedError = mock(dev.cookiecode.rika2mqtt.plugins.api.v1.model.StoveError.class);
when(enrichedError.getErrorCode()).thenReturn("42");
when(stoveErrorMapper.toApiStoveError(anyLong(), any())).thenReturn(enrichedError);

when(rikaFirenetService.getStatus(any())).thenReturn(stoveStatus);
Expand All @@ -223,7 +224,7 @@ void publishToMqttShouldInvokeMqttServicePublishNotificationForEachStoveHavingAn
bridge.publishToMqtt();

// THEN
verify(mqttService, times(stoves.size())).publishNotification(any());
verify(mqttPublicationService, times(stoves.size())).publishNotification(any());
}

@Test
Expand All @@ -241,7 +242,7 @@ void publishToMqttShouldNotInvokeMqttServicePublishErrorForEachStoveHavingNoErro
bridge.publishToMqtt();

// THEN
verify(mqttService, never()).publishNotification(any());
verify(mqttPublicationService, never()).publishNotification(any());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,26 @@
*/
package dev.cookiecode.rika2mqtt.rika.mqtt;

import lombok.NonNull;

/**
* Service to publish messages into MQTT broker
*
* @author Sebastien Vermeille
*/
public interface MqttService {
public interface MqttPublicationService {

void publish(String message);
/**
* Publish a standard stove status message
*
* @param message the message to publish
*/
void publish(@NonNull final String message);

void publishNotification(String message);
/**
* Publish a notification message (other mqtt channel)
*
* @param message the message to publish
*/
void publishNotification(@NonNull final String message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package dev.cookiecode.rika2mqtt.rika.mqtt;

import dev.cookiecode.rika2mqtt.rika.mqtt.configuration.MqttConfiguration;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.flogger.Flogger;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -34,7 +35,7 @@
@Service
@RequiredArgsConstructor
@Flogger
public class MqttServiceImpl implements MqttService {
public class MqttPublicationServiceImpl implements MqttPublicationService {

@Qualifier("mqttConfiguration.MqttGateway")
private final MqttConfiguration.MqttGateway mqttGateway;
Expand All @@ -43,14 +44,14 @@ public class MqttServiceImpl implements MqttService {
private final MqttConfiguration.MqttGateway mqttNotificationGateway;

@Override
public void publish(final String message) {
public void publish(@NonNull final String message) {
log.atInfo().log("Publish to mqtt:\n%s", message);
mqttGateway.sendToMqtt(message);
}

@Override
public void publishNotification(String message) {
log.atInfo().log("Publish error to mqtt:\n%s", message);
public void publishNotification(@NonNull final String message) {
log.atInfo().log("Publish notification to mqtt:\n%s", message);
mqttNotificationGateway.sendToMqtt(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
@Flogger
public class MqttConfiguration {

private static final String DELIMITER = ":";
private static final String STOVE_ID = "stoveId";
private final MqttConfigProperties mqttConfigProperties;
private final ApplicationEventPublisher applicationEventPublisher;
private final Gson gson;
Expand All @@ -71,7 +73,7 @@ public MqttPahoClientFactory mqttClientFactory() {
new String[] {
mqttConfigProperties.getUriScheme()
+ mqttConfigProperties.getHost()
+ ":"
+ DELIMITER
+ mqttConfigProperties.getPort()
});
options.setUserName(mqttConfigProperties.getUsername());
Expand Down Expand Up @@ -159,12 +161,13 @@ public MessageHandler mqttInputMessageHandler() {
try {
final var type = new TypeToken<Map<String, String>>() {}.getType();
final Map<String, String> props = gson.fromJson(payload, type);
final var stoveId = Long.parseUnsignedLong(props.get("stoveId"));
final var stoveId = Long.parseUnsignedLong(props.get(STOVE_ID));

// remove stoveId props as it has its own property in the wrapping object
props.remove("stoveId");
props.remove(STOVE_ID);

applicationEventPublisher.publishEvent(new MqttCommandEvent(stoveId, props));
applicationEventPublisher.publishEvent(
MqttCommandEvent.builder().withStoveId(stoveId).withProps(props));
} catch (JsonSyntaxException ex) {
log.atWarning().log(
"Received an invalid json payload via MQTT. Please ensure it follows the format defined in the doc.");
Expand Down
Loading
Loading