diff --git a/client/build.gradle b/client/build.gradle index 6ca6cdd4..a644a7f3 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -20,7 +20,6 @@ dependencies { implementation "org.apache.logging.log4j:log4j-core:$log4jVersion" // used for our custom error handler, otherwise not a necessary dependency implementation "org.apache.logging.log4j:log4j-jcl:$log4jVersion" // commons logging bridge. implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4jVersion" - implementation 'com.brsanthu:google-analytics-java:2.0.0' // https://github.com/slackapi/java-slack-sdk/releases implementation 'com.slack.api:slack-api-client:1.29.2' @@ -36,6 +35,7 @@ dependencies { implementation 'info.debatty:java-string-similarity:2.0.0' + // TODO do we need this dependency? implementation group: 'biz.paluch.logging', name: 'logstash-gelf', version: '1.15.0' } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/SlackChatBotActionNode.java b/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/SlackChatBotActionNode.java index faaf2bd7..afe4da67 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/SlackChatBotActionNode.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/SlackChatBotActionNode.java @@ -22,7 +22,7 @@ import me.retrodaredevil.solarthing.util.sync.ResourceManager; import okhttp3.OkHttpClient; -import java.io.File; +import java.nio.file.Path; import java.time.Duration; import java.time.ZoneId; import java.util.Arrays; @@ -51,7 +51,7 @@ public class SlackChatBotActionNode implements ActionNode { private final String channelId; private final Map> permissionMap; private final String sender; - private final File keyDirectory; + private final Path keyDirectory; public SlackChatBotActionNode( String appToken, @@ -59,7 +59,7 @@ public SlackChatBotActionNode( String channelId, Map> permissionMap, String sender, - File keyDirectory + Path keyDirectory ) { this.appToken = appToken; this.authToken = authToken; diff --git a/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/WrappedSlackChatBotActionNode.java b/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/WrappedSlackChatBotActionNode.java index cd45febe..ade51c01 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/WrappedSlackChatBotActionNode.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/actions/chatbot/WrappedSlackChatBotActionNode.java @@ -7,7 +7,7 @@ import me.retrodaredevil.action.node.convenient.SingleActionNode; import me.retrodaredevil.action.node.environment.ActionEnvironment; -import java.io.File; +import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -22,7 +22,7 @@ public WrappedSlackChatBotActionNode( @JsonProperty(value = "channel_id", required = true) String channelId, @JsonProperty(value = "permissions", required = true) Map> permissionMap, @JsonProperty(value = "sender", required = true) String sender, - @JsonProperty(value = "key_directory", required = true) File keyDirectory + @JsonProperty(value = "key_directory", required = true) Path keyDirectory ) { // Wrap the RawActionNode in a SingleActionNode so that only one is active at a time -- the first one created and executed will be the one that is used actionNode = SingleActionNode.create(new SlackChatBotActionNode(appToken, authToken, channelId, permissionMap, sender, keyDirectory)); diff --git a/client/src/main/java/me/retrodaredevil/solarthing/actions/command/AlterManagerActionNode.java b/client/src/main/java/me/retrodaredevil/solarthing/actions/command/AlterManagerActionNode.java index fb0d4978..a82d62ea 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/actions/command/AlterManagerActionNode.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/actions/command/AlterManagerActionNode.java @@ -5,22 +5,27 @@ import me.retrodaredevil.action.node.ActionNode; import me.retrodaredevil.action.node.environment.ActionEnvironment; import me.retrodaredevil.solarthing.AlterPacketsProvider; -import me.retrodaredevil.solarthing.actions.environment.*; +import me.retrodaredevil.solarthing.actions.environment.AlterPacketsEnvironment; +import me.retrodaredevil.solarthing.actions.environment.AuthorizationEnvironment; +import me.retrodaredevil.solarthing.actions.environment.OpenDatabaseCacheEnvironment; +import me.retrodaredevil.solarthing.actions.environment.SolarThingDatabaseEnvironment; +import me.retrodaredevil.solarthing.actions.environment.SourceIdEnvironment; +import me.retrodaredevil.solarthing.actions.environment.TimeZoneEnvironment; import me.retrodaredevil.solarthing.commands.util.CommandManager; import me.retrodaredevil.solarthing.database.SolarThingDatabase; import me.retrodaredevil.solarthing.database.cache.DatabaseCache; -import java.io.File; +import java.nio.file.Path; public class AlterManagerActionNode implements ActionNode { private final String sender; - private final File keyDirectory; + private final Path keyDirectory; private final int fragmentId; public AlterManagerActionNode( @JsonProperty(value = "sender", required = true) String sender, - @JsonProperty(value = "key_directory", required = true) File keyDirectory, + @JsonProperty(value = "key_directory", required = true) Path keyDirectory, @JsonProperty(value = "fragment", required = true) int fragmentId) { this.sender = sender; this.keyDirectory = keyDirectory; diff --git a/client/src/main/java/me/retrodaredevil/solarthing/actions/command/WrappedAlterManagerActionNode.java b/client/src/main/java/me/retrodaredevil/solarthing/actions/command/WrappedAlterManagerActionNode.java index 4d089936..730750ea 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/actions/command/WrappedAlterManagerActionNode.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/actions/command/WrappedAlterManagerActionNode.java @@ -7,7 +7,7 @@ import me.retrodaredevil.action.node.convenient.SingleActionNode; import me.retrodaredevil.action.node.environment.ActionEnvironment; -import java.io.File; +import java.nio.file.Path; /** * Providing a fragment for something in the automation program is not something you would be expecting to see. @@ -20,7 +20,7 @@ public class WrappedAlterManagerActionNode implements ActionNode { public WrappedAlterManagerActionNode( @JsonProperty(value = "sender", required = true) String sender, - @JsonProperty(value = "key_directory", required = true) File keyDirectory, + @JsonProperty(value = "key_directory", required = true) Path keyDirectory, @JsonProperty(value = "fragment", required = true) int fragmentId ) { actionNode = SingleActionNode.create(new AlterManagerActionNode(sender, keyDirectory, fragmentId)); diff --git a/client/src/main/java/me/retrodaredevil/solarthing/analytics/AnalyticsManager.java b/client/src/main/java/me/retrodaredevil/solarthing/analytics/AnalyticsManager.java index 01b0eac1..4a45fe3d 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/analytics/AnalyticsManager.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/analytics/AnalyticsManager.java @@ -1,112 +1,42 @@ package me.retrodaredevil.solarthing.analytics; -import com.brsanthu.googleanalytics.GoogleAnalytics; -import com.brsanthu.googleanalytics.GoogleAnalyticsConfig; -import com.brsanthu.googleanalytics.request.DefaultRequest; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.config.options.ProgramType; -import me.retrodaredevil.solarthing.program.JarUtil; -import me.retrodaredevil.solarthing.util.JacksonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.UUID; - public class AnalyticsManager { - /* - For future self setting this up again: in the View Settings in Google Analytics, you must have "Bot Filtering" turned off. - */ - private static final ObjectMapper MAPPER = JacksonUtil.defaultMapper(); + private static final String ANALYTICS_NOTE = "(Note) For this SolarThing version, analytics are not sent. This will be changed in a future version. If you see this log message, a future version of SolarThing may send analytics data (if you decide to update)."; private static final Logger LOGGER = LoggerFactory.getLogger(AnalyticsManager.class); - private final GoogleAnalytics googleAnalytics; + private final boolean isEnabled; - public AnalyticsManager(boolean isEnabled, Path dataDirectory) { + /** + * Constructs the object. No connections should be created here and no analytics collection should be done just because the constructor was invoked. + * + * @param isEnabled true if analytics are enabled, false otherwise + */ + public AnalyticsManager(boolean isEnabled) { + this.isEnabled = isEnabled; if (isEnabled) { - LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Google Analytics is ENABLED!"); - Path file = dataDirectory.resolve("analytics_data.json"); - AnalyticsData analyticsData = null; - try { - analyticsData = MAPPER.readValue(Files.newInputStream(file), AnalyticsData.class); - } catch (IOException e) { - LOGGER.debug(SolarThingConstants.NO_CONSOLE, "Couldn't read analytics data, but that's OK!", e); - } - if (analyticsData == null) { - analyticsData = new AnalyticsData(UUID.randomUUID()); - LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Generated a new Analytics UUID"); - try { - MAPPER.writeValue(Files.newOutputStream(file), analyticsData); - } catch (IOException e) { - LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "Couldn't save analytics data!", e); - } - } - final String clientId = analyticsData.uuid.toString(); - LOGGER.debug("Using Analytics UUID: " + clientId); - googleAnalytics = GoogleAnalytics.builder() - .withConfig(new GoogleAnalyticsConfig() - .setThreadTimeoutSecs(5) - ) - .withDefaultRequest(new DefaultRequest() - .applicationName("solarthing-program") - .applicationVersion("V-UNKNOWN") - .clientId(clientId) - ) - .withTrackingId("UA-70767765-2") - .build(); + LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Analytics are ENABLED! " + ANALYTICS_NOTE); } else { - // TODO when the --validate argument is present, this is always printed. Think about if we want to let the user know what the actual configuration is - LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Google Analytics is disabled"); - googleAnalytics = null; + LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Analytics are disabled"); } } public void sendStartUp(ProgramType programType) { - if (googleAnalytics != null) { - LOGGER.info("Sending program type to Google Analytics"); - googleAnalytics.screenView() - .screenName(programType.getName()) - .sendAsync(); - googleAnalytics.event() - .eventCategory("startup") - .eventAction(programType.getName()) - .eventLabel(JarUtil.getJarFileName()) // so we know what version they're running - .sendAsync(); + if (isEnabled) { + LOGGER.info("Sending program type to analytics (" + programType + ") " + ANALYTICS_NOTE); } } public void sendMateStatus(String data, int uptimeHours) { - if (googleAnalytics != null) { - LOGGER.info("Sending Mate status to Google Analytics. data=" + data + " uptime hours=" + uptimeHours); - googleAnalytics.event() - .eventCategory("status") - .eventAction("mate") - .eventLabel(data) - .eventValue(uptimeHours) - .sendAsync(); + if (isEnabled) { + LOGGER.info("Sending Mate status to analytics. data=" + data + " uptime hours=" + uptimeHours + " " + ANALYTICS_NOTE); } } public void sendRoverStatus(String data, int uptimeHours) { - if (googleAnalytics != null) { - LOGGER.info("Sending Rover status to Google Analytics. data=" + data + " uptime hours=" + uptimeHours); - googleAnalytics.event() - .eventCategory("status") - .eventAction("rover") - .eventLabel(data) - .eventValue(uptimeHours) - .sendAsync(); - } - } - private static final class AnalyticsData { - @JsonProperty("uuid") - private final UUID uuid; - - @JsonCreator - private AnalyticsData(@JsonProperty(value = "uuid", required = true) UUID uuid) { - this.uuid = uuid; + if (isEnabled) { + LOGGER.info("Sending Rover status to analytics. data=" + data + " uptime hours=" + uptimeHours + " " + ANALYTICS_NOTE); } } } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/databases/implementations/LatestFileDatabaseSettings.java b/client/src/main/java/me/retrodaredevil/solarthing/config/databases/implementations/LatestFileDatabaseSettings.java index 0c988eec..872d6265 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/databases/implementations/LatestFileDatabaseSettings.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/databases/implementations/LatestFileDatabaseSettings.java @@ -7,16 +7,16 @@ import me.retrodaredevil.solarthing.config.databases.DatabaseType; import me.retrodaredevil.solarthing.config.databases.SimpleDatabaseType; -import java.io.File; +import java.nio.file.Path; @JsonTypeName("latest") public final class LatestFileDatabaseSettings implements DatabaseSettings { public static final DatabaseType TYPE = new SimpleDatabaseType("latest"); - private final File file; + private final Path file; @JsonCreator - public LatestFileDatabaseSettings(@JsonProperty(value = "file", required = true) File file) { + public LatestFileDatabaseSettings(@JsonProperty(value = "file", required = true) Path file) { this.file = file; } @@ -25,7 +25,7 @@ public String toString() { return "Latest " + file; } - public File getFile(){ + public Path getFile(){ return file; } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/io/modbus/DummyRoverModbusSlave.java b/client/src/main/java/me/retrodaredevil/solarthing/config/io/modbus/DummyRoverModbusSlave.java index 67c8b1e4..50e36689 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/io/modbus/DummyRoverModbusSlave.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/io/modbus/DummyRoverModbusSlave.java @@ -9,28 +9,28 @@ import me.retrodaredevil.solarthing.solar.renogy.rover.modbus.LocalRoverModbusSlave; import me.retrodaredevil.solarthing.util.JacksonUtil; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; @JsonTypeName("rover") public class DummyRoverModbusSlave implements DummyModbusSlave { private static final ObjectMapper MAPPER = JacksonUtil.defaultMapper(); - private final File file; + private final Path file; @JsonCreator - public DummyRoverModbusSlave(@JsonProperty("file") File file) { + public DummyRoverModbusSlave(@JsonProperty("file") Path file) { this.file = file; } @Override public ModbusSlave createModbusSlave() { - final FileInputStream fileInputStream; + final InputStream fileInputStream; try { - fileInputStream = new FileInputStream(file); - } catch (FileNotFoundException e) { + fileInputStream = Files.newInputStream(file); + } catch (IOException e) { throw new RuntimeException("The dummy file was not found!", e); } final RoverStatusPacket roverStatusPacket; diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/options/ActionsOption.java b/client/src/main/java/me/retrodaredevil/solarthing/config/options/ActionsOption.java index 5f2c8e5a..e6c7a868 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/options/ActionsOption.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/options/ActionsOption.java @@ -1,17 +1,10 @@ package me.retrodaredevil.solarthing.config.options; -import java.io.File; -import java.util.List; - /** * Represents some sort of {@link ProgramOptions} that can contain actions that would usually * be executed each "iteration". */ public interface ActionsOption extends ProgramOptions { - /** - * A legacy configuration option that currently is still supported, but will be removed in a future version - */ - List getActionNodeFiles(); /** * This will not be null, but may be {@link ActionConfig#EMPTY} by default. diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/options/AutomationProgramOptions.java b/client/src/main/java/me/retrodaredevil/solarthing/config/options/AutomationProgramOptions.java index c337764d..acf87e7d 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/options/AutomationProgramOptions.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/options/AutomationProgramOptions.java @@ -1,12 +1,14 @@ package me.retrodaredevil.solarthing.config.options; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.JsonTypeName; +import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.annotations.JsonExplicit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.File; import java.time.Duration; -import java.util.Collections; import java.util.List; import static java.util.Objects.requireNonNull; @@ -15,8 +17,8 @@ @JsonTypeName("automation") @JsonExplicit public class AutomationProgramOptions extends DatabaseTimeZoneOptionBase implements ActionsOption { - @JsonProperty("actions") - private List actionNodeFiles = Collections.emptyList(); + private static final Logger LOGGER = LoggerFactory.getLogger(AutomationProgramOptions.class); + @JsonProperty("action_config") private ActionConfig actionConfig = ActionConfig.EMPTY; @@ -28,11 +30,6 @@ public ProgramType getProgramType() { return ProgramType.AUTOMATION; } - @Override - public List getActionNodeFiles() { - return requireNonNull(actionNodeFiles, "You cannot supply a null value here!"); - } - @Override public ActionConfig getActionConfig() { return requireNonNull(actionConfig); @@ -41,4 +38,11 @@ public ActionConfig getActionConfig() { public long getPeriodMillis() { return Duration.parse(periodDurationString).toMillis(); } + + @JsonSetter("actions") + private void setActionNodeFiles(List actionNodeFiles) { + LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Deprecated) Please use action_config configuration instead of actions!"); + // TODO use a different exception here + throw new RuntimeException("Migration required! You must now use action_config instead of actions to configure actions!"); + } } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/options/PacketHandlingOptionBase.java b/client/src/main/java/me/retrodaredevil/solarthing/config/options/PacketHandlingOptionBase.java index 56a827c6..f98c65bc 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/options/PacketHandlingOptionBase.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/options/PacketHandlingOptionBase.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonSetter; import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.annotations.NotNull; import me.retrodaredevil.solarthing.annotations.Nullable; @@ -10,9 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -46,8 +45,6 @@ abstract class PacketHandlingOptionBase extends TimeZoneOptionBase implements Pa @JsonProperty(AnalyticsOption.PROPERTY_NAME) private boolean isAnalyticsEnabled = AnalyticsOption.DEFAULT_IS_ANALYTICS_ENABLED; - @JsonProperty("actions") - private List actionNodeFiles = new ArrayList<>(); @JsonProperty("action_config") private ActionConfig actionConfig = ActionConfig.EMPTY; @@ -112,9 +109,11 @@ public final boolean isAnalyticsOptionEnabled() { return isAnalyticsEnabled; } - @Override - public final List getActionNodeFiles() { - return requireNonNull(actionNodeFiles, "You cannot use a null value for the actions property! Use an empty array or leave it undefined."); + @JsonSetter("actions") + private void setActionNodeFiles(List actionNodeFiles) { + LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Deprecated) Please use action_config configuration instead of actions!"); + // TODO use a different exception here + throw new RuntimeException("Migration required! You must now use action_config instead of actions to configure actions!"); } @Override diff --git a/client/src/main/java/me/retrodaredevil/solarthing/config/request/W1TemperatureDataRequester.java b/client/src/main/java/me/retrodaredevil/solarthing/config/request/W1TemperatureDataRequester.java index ca9d8aff..30bb6560 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/config/request/W1TemperatureDataRequester.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/config/request/W1TemperatureDataRequester.java @@ -5,16 +5,16 @@ import com.fasterxml.jackson.annotation.JsonTypeName; import me.retrodaredevil.solarthing.misc.weather.W1TemperatureListUpdater; -import java.io.File; +import java.nio.file.Path; @JsonTypeName("w1-temperature") public class W1TemperatureDataRequester implements DataRequester { - private final File directory; + private final Path directory; private final int dataId; @JsonCreator public W1TemperatureDataRequester( - @JsonProperty(value = "directory", required = true) File directory, + @JsonProperty(value = "directory", required = true) Path directory, @JsonProperty(value = "data_id", required = true) int dataId ) { this.directory = directory; diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java b/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java index bcd952b4..9985a46d 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java @@ -2,12 +2,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import me.retrodaredevil.action.node.ActionNode; -import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.actions.CommonActionUtil; import me.retrodaredevil.solarthing.actions.chatbot.WrappedSlackChatBotActionNode; import me.retrodaredevil.solarthing.actions.command.ExecutingCommandFeedbackActionNode; import me.retrodaredevil.solarthing.actions.command.FlagActionNode; import me.retrodaredevil.solarthing.actions.command.WrappedAlterManagerActionNode; +import me.retrodaredevil.solarthing.actions.config.ActionReference; import me.retrodaredevil.solarthing.actions.homeassistant.HomeAssistantActionNode; import me.retrodaredevil.solarthing.actions.mate.MateCommandActionNode; import me.retrodaredevil.solarthing.actions.mate.MateCommandWaitActionNode; @@ -21,8 +21,6 @@ import me.retrodaredevil.solarthing.actions.tracer.TracerLoadActionNode; import me.retrodaredevil.solarthing.actions.tracer.modbus.TracerModbusActionNode; import me.retrodaredevil.solarthing.annotations.UtilityClass; -import me.retrodaredevil.solarthing.actions.config.ActionFormat; -import me.retrodaredevil.solarthing.actions.config.ActionReference; import me.retrodaredevil.solarthing.config.options.ActionConfig; import me.retrodaredevil.solarthing.config.options.ActionsOption; import me.retrodaredevil.solarthing.config.options.CommandOption; @@ -31,7 +29,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -87,17 +84,7 @@ public static Map createCommandNameToActionNodeMap(CommandOp public static List createActionNodeEntries(ActionsOption options) throws IOException { List actionNodeEntries = new ArrayList<>(); - for (File file : options.getActionNodeFiles()) { - // We hardcode RAW_JSON here because getActionNodeFiles() is a legacy configuration, - // so this for loop can be removed eventually in the future - ActionNode actionNode = CommonActionUtil.readActionReference(CONFIG_MAPPER, new ActionReference(file.toPath(), ActionFormat.RAW_JSON)); - actionNodeEntries.add(new ActionNodeEntry(actionNode, false)); - } - if (!actionNodeEntries.isEmpty()) { - LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "(Deprecated) Please use action_config configuration instead of actions!"); - } - ActionConfig actionConfig = options.getActionConfig(); - for (ActionConfig.Entry entry : actionConfig.getEntries()) { + for (ActionConfig.Entry entry : options.getActionConfig().getEntries()) { ActionNode actionNode = CommonActionUtil.readActionReference(CONFIG_MAPPER, entry.getActionReference()); boolean runOnce = entry.isRunOnce(); actionNodeEntries.add(new ActionNodeEntry(actionNode, runOnce)); diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/OutbackMateMain.java b/client/src/main/java/me/retrodaredevil/solarthing/program/OutbackMateMain.java index 4e8e1552..9d3784cd 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/OutbackMateMain.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/OutbackMateMain.java @@ -33,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.file.Path; import java.time.Duration; import java.util.*; import java.util.stream.Collectors; @@ -47,10 +46,9 @@ public class OutbackMateMain { private static final Collection ALLOWED_COMMANDS = EnumSet.of(MateCommand.AUX_OFF, MateCommand.AUX_ON, MateCommand.USE, MateCommand.DROP); @SuppressWarnings("SameReturnValue") - public static int connectMate(MateProgramOptions options, Path dataDirectory, boolean isValidate) throws Exception { + public static int connectMate(MateProgramOptions options, boolean isValidate) throws Exception { LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Beginning mate program"); - AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled(), dataDirectory); - analyticsManager.sendStartUp(ProgramType.MATE); + AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled()); LOGGER.debug("IO Bundle File: " + options.getIOBundleFilePath()); IOConfig ioConfig = ConfigUtil.parseIOConfig(options.getIOBundleFilePath(), OutbackConstants.MATE_CONFIG); try(ReloadableIOBundle ioBundle = new ReloadableIOBundle(ioConfig::createIOBundle)) { @@ -107,6 +105,7 @@ public static int connectMate(MateProgramOptions options, Path dataDirectory, bo if (isValidate) { return 0; } + analyticsManager.sendStartUp(ProgramType.MATE); return SolarMain.initReader( requireNonNull(ioBundle.getInputStream()), ioBundle::reload, diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/RequestMain.java b/client/src/main/java/me/retrodaredevil/solarthing/program/RequestMain.java index 15d4eef1..79cc51b2 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/RequestMain.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/RequestMain.java @@ -21,7 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -33,10 +32,9 @@ public class RequestMain { private static final Logger LOGGER = LoggerFactory.getLogger(RequestMain.class); - public static int startRequestProgram(RequestProgramOptions options, Path dataDirectory, boolean isValidate) throws Exception { + public static int startRequestProgram(RequestProgramOptions options, boolean isValidate) throws Exception { LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Beginning request program"); - AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled() && !isValidate, dataDirectory); - analyticsManager.sendStartUp(ProgramType.REQUEST); + AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled()); return startRequestProgram(options, analyticsManager, options.getPeriod(), options.getMinimumWait(), isValidate); } @@ -74,6 +72,7 @@ private static int startRequestProgram(RequestProgramOptions options, AnalyticsM if (isValidate) { return 0; } + analyticsManager.sendStartUp(ProgramType.REQUEST); return doRequest(new PacketListReceiverMultiplexer(packetListReceiverList), period, minimumWait); } private static int doRequest(PacketListReceiver packetListReceiver, Duration period, Duration minimumWait) { diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/SolarMain.java b/client/src/main/java/me/retrodaredevil/solarthing/program/SolarMain.java index 984bf8a3..6d58fa3a 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/SolarMain.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/SolarMain.java @@ -9,12 +9,12 @@ import me.retrodaredevil.couchdbjava.response.ErrorResponse; import me.retrodaredevil.solarthing.SolarThingConstants; import me.retrodaredevil.solarthing.annotations.UtilityClass; +import me.retrodaredevil.solarthing.config.ConfigException; import me.retrodaredevil.solarthing.config.ConfigUtil; import me.retrodaredevil.solarthing.config.databases.DatabaseConfig; import me.retrodaredevil.solarthing.config.databases.DatabaseSettings; import me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings; import me.retrodaredevil.solarthing.config.options.*; -import me.retrodaredevil.solarthing.config.ConfigException; import me.retrodaredevil.solarthing.packets.Packet; import me.retrodaredevil.solarthing.packets.collection.HourIntervalPacketCollectionIdGenerator; import me.retrodaredevil.solarthing.packets.collection.PacketCollectionIdGenerator; @@ -33,7 +33,6 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.util.List; @@ -124,24 +123,18 @@ public static int doMainCommand(CommandOptions commandOptions, Path baseConfigFi return SolarThingConstants.EXIT_CODE_INVALID_CONFIG; } - // TODO consider allowing customization of .data path - Path dataDirectory = Path.of(".data"); - try { - Files.createDirectories(dataDirectory); - } catch (IOException e) { - LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Fatal)Unable to create data directory! dataDirectory=" + dataDirectory + " absolute=" + dataDirectory.toAbsolutePath()); - return SolarThingConstants.EXIT_CODE_CRASH; - } + // Note we used to have the creation of the .data directory here. We may consider adding it back in the future should we need it + final ProgramType programType = options.getProgramType(); try { if(programType == ProgramType.MATE) { - return OutbackMateMain.connectMate((MateProgramOptions) options, dataDirectory, commandOptions.isValidate()); + return OutbackMateMain.connectMate((MateProgramOptions) options, commandOptions.isValidate()); } else if(programType == ProgramType.ROVER_SETUP){ return RoverMain.connectRoverSetup((RoverSetupProgramOptions) options, commandOptions.isValidate()); } else if(programType == ProgramType.PVOUTPUT_UPLOAD){ - return PVOutputUploadMain.startPVOutputUpload((PVOutputUploadProgramOptions) options, commandOptions, dataDirectory, commandOptions.isValidate()); + return PVOutputUploadMain.startPVOutputUpload((PVOutputUploadProgramOptions) options, commandOptions, commandOptions.isValidate()); } else if(programType == ProgramType.REQUEST) { - return RequestMain.startRequestProgram((RequestProgramOptions) options, dataDirectory, commandOptions.isValidate()); + return RequestMain.startRequestProgram((RequestProgramOptions) options, commandOptions.isValidate()); } else if(programType == ProgramType.AUTOMATION) { return AutomationMain.startAutomation((AutomationProgramOptions) options, commandOptions.isValidate()); } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/pvoutput/PVOutputUploadMain.java b/client/src/main/java/me/retrodaredevil/solarthing/program/pvoutput/PVOutputUploadMain.java index 98ad68a0..e85d3412 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/pvoutput/PVOutputUploadMain.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/pvoutput/PVOutputUploadMain.java @@ -43,7 +43,6 @@ import retrofit2.Retrofit; import java.io.IOException; -import java.nio.file.Path; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; @@ -63,8 +62,8 @@ public class PVOutputUploadMain { // TODO Make this an action for the automation program - @SuppressWarnings({"SameReturnValue", "deprecation"}) - public static int startPVOutputUpload(PVOutputUploadProgramOptions options, CommandOptions commandOptions, Path dataDirectory, boolean isValidate){ + @SuppressWarnings({"SameReturnValue"}) + public static int startPVOutputUpload(PVOutputUploadProgramOptions options, CommandOptions commandOptions, boolean isValidate){ LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Starting PV Output upload program"); ZoneId zoneId = options.getZoneId(); @@ -114,12 +113,12 @@ public static int startPVOutputUpload(PVOutputUploadProgramOptions options, Comm LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Fatal)You need to define both from and to, or define neither to do the normal PVOutput program!"); return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS; } - AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled() && !isValidate, dataDirectory); - analyticsManager.sendStartUp(ProgramType.PVOUTPUT_UPLOAD); + AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled()); if (isValidate) { return 0; } + analyticsManager.sendStartUp(ProgramType.PVOUTPUT_UPLOAD); return startRealTimeProgram(options, database, handler, service, options.getZoneId()); } @SuppressWarnings("CatchAndPrintStackTrace") diff --git a/common/src/main/java/me/retrodaredevil/solarthing/actions/command/SendEncryptedActionNode.java b/common/src/main/java/me/retrodaredevil/solarthing/actions/command/SendEncryptedActionNode.java index f775cb27..b6faec22 100644 --- a/common/src/main/java/me/retrodaredevil/solarthing/actions/command/SendEncryptedActionNode.java +++ b/common/src/main/java/me/retrodaredevil/solarthing/actions/command/SendEncryptedActionNode.java @@ -20,7 +20,7 @@ import me.retrodaredevil.solarthing.packets.collection.PacketCollectionIdGenerator; import me.retrodaredevil.solarthing.packets.instance.InstanceTargetPackets; -import java.io.File; +import java.nio.file.Path; import java.time.ZoneId; import java.util.List; import java.util.concurrent.Executors; @@ -52,7 +52,7 @@ public SendEncryptedActionNode( @JsonCreator public static SendEncryptedActionNode create( - @JsonProperty(value = "directory", required = true) File keyDirectory, + @JsonProperty(value = "directory", required = true) Path keyDirectory, @JsonProperty(value = "sender", required = true) String sender, @JsonProperty(value = "targets", required = true) List fragmentIdTargets, @JsonProperty(value = "data", required = true) CommandOpenProvider data diff --git a/core/src/main/java/me/retrodaredevil/solarthing/commands/util/CommandManager.java b/core/src/main/java/me/retrodaredevil/solarthing/commands/util/CommandManager.java index bd47b945..cdcb3b20 100644 --- a/core/src/main/java/me/retrodaredevil/solarthing/commands/util/CommandManager.java +++ b/core/src/main/java/me/retrodaredevil/solarthing/commands/util/CommandManager.java @@ -13,16 +13,20 @@ import me.retrodaredevil.solarthing.packets.instance.InstanceSourcePackets; import me.retrodaredevil.solarthing.packets.instance.InstanceTargetPacket; import me.retrodaredevil.solarthing.packets.security.ImmutableLargeIntegrityPacket; -import me.retrodaredevil.solarthing.packets.security.crypto.*; +import me.retrodaredevil.solarthing.packets.security.crypto.Encrypt; +import me.retrodaredevil.solarthing.packets.security.crypto.EncryptException; +import me.retrodaredevil.solarthing.packets.security.crypto.HashUtil; +import me.retrodaredevil.solarthing.packets.security.crypto.InvalidKeyException; +import me.retrodaredevil.solarthing.packets.security.crypto.KeyUtil; import me.retrodaredevil.solarthing.util.JacksonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.crypto.Cipher; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.security.KeyPair; import java.security.PrivateKey; @@ -44,7 +48,7 @@ public class CommandManager { private final Supplier keyPairSupplier; private final String sender; - public CommandManager(File keyDirectory, String sender) { + public CommandManager(Path keyDirectory, String sender) { this(() -> getKeyPairFromDirectory(keyDirectory), sender); } public CommandManager(Supplier keyPairSupplier, String sender) { @@ -59,13 +63,13 @@ public KeyPair getKeyPair() { return keyPairSupplier.get(); } - public static KeyPair getKeyPairFromDirectory(File keyDirectory) { - File publicKeyFile = new File(keyDirectory, ".publickey"); - File privateKeyFile = new File(keyDirectory, ".privatekey"); + public static KeyPair getKeyPairFromDirectory(Path keyDirectory) { + Path publicKeyFile = keyDirectory.resolve(".publickey"); + Path privateKeyFile = keyDirectory.resolve(".privatekey"); KeyPair keyPair; try { - PublicKey publicKey = KeyUtil.decodePublicKey(Files.readAllBytes(publicKeyFile.toPath())); - PrivateKey privateKey = KeyUtil.decodePrivateKey(Files.readAllBytes(privateKeyFile.toPath())); + PublicKey publicKey = KeyUtil.decodePublicKey(Files.readAllBytes(publicKeyFile)); + PrivateKey privateKey = KeyUtil.decodePrivateKey(Files.readAllBytes(privateKeyFile)); keyPair = new KeyPair(publicKey, privateKey); } catch (IOException | InvalidKeyException e) { if (e instanceof NoSuchFileException) { @@ -75,14 +79,14 @@ public static KeyPair getKeyPairFromDirectory(File keyDirectory) { } keyPair = KeyUtil.generateKeyPair(); try { - //noinspection ResultOfMethodCallIgnored - keyDirectory.mkdirs(); // we don't care what the result of this is, we'll catch the exception if something goes wrong - Files.write(publicKeyFile.toPath(), keyPair.getPublic().getEncoded(), StandardOpenOption.CREATE); - Files.write(privateKeyFile.toPath(), keyPair.getPrivate().getEncoded(), StandardOpenOption.CREATE); + Files.createDirectories(keyDirectory); + Files.write(publicKeyFile, keyPair.getPublic().getEncoded(), StandardOpenOption.CREATE); + Files.write(privateKeyFile, keyPair.getPrivate().getEncoded(), StandardOpenOption.CREATE); } catch (IOException ioException) { // TODO use more specific exception here throw new RuntimeException("Error writing keys", ioException); } + LOGGER.info("Generated new key pair in directory: " + keyDirectory + ". Public key below:\n" + KeyUtil.encodePublicKey(keyPair.getPublic())); } return requireNonNull(keyPair); } diff --git a/core/src/main/java/me/retrodaredevil/solarthing/misc/weather/W1TemperatureListUpdater.java b/core/src/main/java/me/retrodaredevil/solarthing/misc/weather/W1TemperatureListUpdater.java index 2e9be130..1d7eb8c6 100644 --- a/core/src/main/java/me/retrodaredevil/solarthing/misc/weather/W1TemperatureListUpdater.java +++ b/core/src/main/java/me/retrodaredevil/solarthing/misc/weather/W1TemperatureListUpdater.java @@ -8,11 +8,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; public class W1TemperatureListUpdater implements PacketListReceiver { @@ -22,17 +22,17 @@ public class W1TemperatureListUpdater implements PacketListReceiver { /** Allow this many degrees celsius to be read below and above the min and max temperature respectively */ private static final float LENIENT_TEMP_CELSIUS = 20.0f; - private final File slaveFile; - private final File nameFile; + private final Path slaveFile; + private final Path nameFile; private final int dataId; - public W1TemperatureListUpdater(File directory, int dataId) { - slaveFile = new File(directory, "w1_slave"); - nameFile = new File(directory, "name"); + public W1TemperatureListUpdater(Path directory, int dataId) { + slaveFile = directory.resolve("w1_slave"); + nameFile = directory.resolve("name"); this.dataId = dataId; - if (!directory.isDirectory()) { + if (!Files.isDirectory(directory)) { LOGGER.warn(SolarThingConstants.SUMMARY_MARKER, "file: " + directory + " is not a directory! Program will continue. (Maybe it will connect later)"); } } @@ -52,7 +52,7 @@ public void receive(List packets) { } final List lines; try { - lines = Files.readAllLines(slaveFile.toPath(), StandardCharsets.UTF_8); + lines = Files.readAllLines(slaveFile, StandardCharsets.UTF_8); } catch (IOException e) { LOGGER.error("Could not read slave file for name=" + name, e); return; @@ -107,7 +107,7 @@ public void receive(List packets) { packets.add(new CelsiusTemperaturePacket(dataId, new W1Source(name), temperatureCelsius)); LOGGER.debug("Read temperature " + temperatureCelsius + "C from " + name + " in " + TimeUtil.nanosToSecondsString(timeTakenNanos) + " seconds"); } - private static String readContents(File file) throws IOException { - return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + private static String readContents(Path file) throws IOException { + return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); } } diff --git a/core/src/main/java/me/retrodaredevil/solarthing/packets/handling/implementations/FileWritePacketHandler.java b/core/src/main/java/me/retrodaredevil/solarthing/packets/handling/implementations/FileWritePacketHandler.java index 0685ee99..97c9fe12 100644 --- a/core/src/main/java/me/retrodaredevil/solarthing/packets/handling/implementations/FileWritePacketHandler.java +++ b/core/src/main/java/me/retrodaredevil/solarthing/packets/handling/implementations/FileWritePacketHandler.java @@ -4,18 +4,18 @@ import me.retrodaredevil.solarthing.packets.handling.PacketHandleException; import me.retrodaredevil.solarthing.packets.handling.PacketHandler; -import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardOpenOption; public class FileWritePacketHandler implements PacketHandler { - private final File file; + private final Path file; private final StringPacketHandler stringPacketHandler; private final boolean append; - public FileWritePacketHandler(File file, StringPacketHandler stringPacketHandler, boolean append) { + public FileWritePacketHandler(Path file, StringPacketHandler stringPacketHandler, boolean append) { this.file = file; this.stringPacketHandler = stringPacketHandler; this.append = append; @@ -25,7 +25,7 @@ public FileWritePacketHandler(File file, StringPacketHandler stringPacketHandler public void handle(PacketCollection packetCollection) throws PacketHandleException { String string = stringPacketHandler.getString(packetCollection); try { - Files.write(file.toPath(), string.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.WRITE, (append ? StandardOpenOption.APPEND : StandardOpenOption.TRUNCATE_EXISTING)); + Files.write(file, string.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.WRITE, (append ? StandardOpenOption.APPEND : StandardOpenOption.TRUNCATE_EXISTING)); } catch (IOException e) { throw new PacketHandleException(e); } diff --git a/core/src/test/java/me/retrodaredevil/solarthing/PacketTestUtil.java b/core/src/test/java/me/retrodaredevil/solarthing/PacketTestUtil.java index 56a8768f..9092e2ce 100644 --- a/core/src/test/java/me/retrodaredevil/solarthing/PacketTestUtil.java +++ b/core/src/test/java/me/retrodaredevil/solarthing/PacketTestUtil.java @@ -2,16 +2,23 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import me.retrodaredevil.solarthing.packets.Packet; import me.retrodaredevil.solarthing.util.JacksonUtil; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Function; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class PacketTestUtil { private PacketTestUtil() { throw new UnsupportedOperationException(); } - public static final File SOLARTHING_ROOT = new File(".."); + public static final Path SOLARTHING_ROOT = Paths.get(".."); public static void testJson(T originalPacket, Class packetClass) throws JsonProcessingException { testJson(originalPacket, packetClass, false); @@ -27,4 +34,23 @@ public static void testJson(T originalPacket, Class packetClass, boolean assertEquals(originalPacket, output, "equals() comparison failed for originalPacket=" + originalPacket); } } + public static void testDirectory(Path directory, Class readUsingClass, Function requirement) { + assertTrue(Files.isDirectory(directory)); + + ObjectMapper mapper = JacksonUtil.defaultMapper(); + + try (Stream files = Files.list(directory)) { + files.forEach(file -> { + T packet; + try { + packet = mapper.readValue(Files.newInputStream(file), readUsingClass); + } catch (IOException e) { + throw new RuntimeException(e); + } + assertTrue(requirement.apply(packet)); + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/src/test/java/me/retrodaredevil/solarthing/solar/outback/OutbackPacketsTest.java b/core/src/test/java/me/retrodaredevil/solarthing/solar/outback/OutbackPacketsTest.java index 3fde6e89..f6ac3ab8 100644 --- a/core/src/test/java/me/retrodaredevil/solarthing/solar/outback/OutbackPacketsTest.java +++ b/core/src/test/java/me/retrodaredevil/solarthing/solar/outback/OutbackPacketsTest.java @@ -1,7 +1,6 @@ package me.retrodaredevil.solarthing.solar.outback; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import me.retrodaredevil.solarthing.PacketTestUtil; import me.retrodaredevil.solarthing.solar.SolarStatusPacket; import me.retrodaredevil.solarthing.solar.event.SolarEventPacket; @@ -16,24 +15,26 @@ import me.retrodaredevil.solarthing.solar.outback.mx.AuxMode; import me.retrodaredevil.solarthing.solar.outback.mx.ChargerMode; import me.retrodaredevil.solarthing.solar.outback.mx.MXStatusPacket; -import me.retrodaredevil.solarthing.solar.outback.mx.event.*; +import me.retrodaredevil.solarthing.solar.outback.mx.event.ImmutableMXAuxModeChangePacket; +import me.retrodaredevil.solarthing.solar.outback.mx.event.ImmutableMXChargerModeChangePacket; +import me.retrodaredevil.solarthing.solar.outback.mx.event.ImmutableMXErrorModeChangePacket; +import me.retrodaredevil.solarthing.solar.outback.mx.event.MXAuxModeChangePacket; +import me.retrodaredevil.solarthing.solar.outback.mx.event.MXChargerModeChangePacket; +import me.retrodaredevil.solarthing.solar.outback.mx.event.MXErrorModeChangePacket; import me.retrodaredevil.solarthing.util.CheckSumException; import me.retrodaredevil.solarthing.util.IgnoreCheckSum; -import me.retrodaredevil.solarthing.util.JacksonUtil; import me.retrodaredevil.solarthing.util.ParsePacketAsciiDecimalDigitException; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; +import java.nio.file.Path; import java.util.Collections; -import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class OutbackPacketsTest { - private static final File DIRECTORY_FX = new File(PacketTestUtil.SOLARTHING_ROOT, "testing/packets/fx"); - private static final File DIRECTORY_MX = new File(PacketTestUtil.SOLARTHING_ROOT, "testing/packets/mx"); + private static final Path DIRECTORY_FX = PacketTestUtil.SOLARTHING_ROOT.resolve("testing/packets/fx"); + private static final Path DIRECTORY_MX = PacketTestUtil.SOLARTHING_ROOT.resolve("testing/packets/mx"); @Test void test() throws JsonProcessingException, ParsePacketAsciiDecimalDigitException, CheckSumException { @@ -93,20 +94,8 @@ void test() throws JsonProcessingException, ParsePacketAsciiDecimalDigitExceptio } @Test - void testExistingPackets() throws IOException { - assertTrue(DIRECTORY_FX.isDirectory()); - assertTrue(DIRECTORY_MX.isDirectory()); - - ObjectMapper mapper = JacksonUtil.defaultMapper(); - - for (File file : requireNonNull(DIRECTORY_FX.listFiles())) { - SolarStatusPacket packet = mapper.readValue(file, SolarStatusPacket.class); - assertTrue(packet instanceof FXStatusPacket); - } - - for (File file : requireNonNull(DIRECTORY_MX.listFiles())) { - SolarStatusPacket packet = mapper.readValue(file, SolarStatusPacket.class); - assertTrue(packet instanceof MXStatusPacket); - } + void testExistingPackets() { + PacketTestUtil.testDirectory(DIRECTORY_FX, SolarStatusPacket.class, packet -> packet instanceof FXStatusPacket); + PacketTestUtil.testDirectory(DIRECTORY_MX, SolarStatusPacket.class, packet -> packet instanceof MXStatusPacket); } } diff --git a/core/src/test/java/me/retrodaredevil/solarthing/solar/renogy/RenogyTest.java b/core/src/test/java/me/retrodaredevil/solarthing/solar/renogy/RenogyTest.java index 74b5776c..9a0c2d75 100644 --- a/core/src/test/java/me/retrodaredevil/solarthing/solar/renogy/RenogyTest.java +++ b/core/src/test/java/me/retrodaredevil/solarthing/solar/renogy/RenogyTest.java @@ -13,15 +13,13 @@ import me.retrodaredevil.solarthing.util.JacksonUtil; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; -import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.*; final class RenogyTest { - private static final File DIRECTORY_ROVER = new File(PacketTestUtil.SOLARTHING_ROOT, "testing/packets/rover"); + private static final Path DIRECTORY_ROVER = PacketTestUtil.SOLARTHING_ROOT.resolve("testing/packets/rover"); @Test void temperatureConvertTest(){ @@ -179,15 +177,8 @@ void testEventPackets() throws JsonProcessingException { @Test - void testRoverExisting() throws IOException { - assertTrue(DIRECTORY_ROVER.isDirectory()); - - ObjectMapper mapper = JacksonUtil.defaultMapper(); - - for (File file : requireNonNull(DIRECTORY_ROVER.listFiles())) { - SolarStatusPacket packet = mapper.readValue(file, SolarStatusPacket.class); - assertTrue(packet instanceof RoverStatusPacket, "Got packet: " + packet); - } + void testRoverExisting() { + PacketTestUtil.testDirectory(DIRECTORY_ROVER, SolarStatusPacket.class, packet -> packet instanceof RoverStatusPacket); } } diff --git a/core/src/test/java/me/retrodaredevil/solarthing/solar/tracer/TracerTest.java b/core/src/test/java/me/retrodaredevil/solarthing/solar/tracer/TracerTest.java index b811f537..0c5f6d5e 100644 --- a/core/src/test/java/me/retrodaredevil/solarthing/solar/tracer/TracerTest.java +++ b/core/src/test/java/me/retrodaredevil/solarthing/solar/tracer/TracerTest.java @@ -9,15 +9,12 @@ import me.retrodaredevil.solarthing.util.JacksonUtil; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; +import java.nio.file.Path; -import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; public class TracerTest { - private static final File DIRECTORY_TRACER = new File(PacketTestUtil.SOLARTHING_ROOT, "testing/packets/tracer"); + private static final Path DIRECTORY_TRACER = PacketTestUtil.SOLARTHING_ROOT.resolve("testing/packets/tracer"); @Test void test() throws JsonProcessingException { @@ -73,14 +70,7 @@ void testTracerEvents() throws JsonProcessingException { } @Test - void testTracerExisting() throws IOException { - assertTrue(DIRECTORY_TRACER.isDirectory()); - - ObjectMapper mapper = JacksonUtil.defaultMapper(); - - for (File file : requireNonNull(DIRECTORY_TRACER.listFiles())) { - SolarStatusPacket packet = mapper.readValue(file, SolarStatusPacket.class); - assertTrue(packet instanceof TracerStatusPacket, "Got packet: " + packet); - } + void testTracerExisting() { + PacketTestUtil.testDirectory(DIRECTORY_TRACER, SolarStatusPacket.class, packet -> packet instanceof TracerStatusPacket); } } diff --git a/program/create_custom.sh b/program/create_custom.sh index dfc879e9..c1955c3b 100755 --- a/program/create_custom.sh +++ b/program/create_custom.sh @@ -1,5 +1,7 @@ #!/usr/bin/env sh +echo "Hey! This script is deprecated" + BASEDIR=$(dirname "$0") cd "$BASEDIR" || exit 1 if [ "$#" -eq 0 ]; then diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/CommonProvider.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/CommonProvider.java index 1422c219..869cf488 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/CommonProvider.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/CommonProvider.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import me.retrodaredevil.solarthing.annotations.Nullable; import me.retrodaredevil.solarthing.config.CommonConfigUtil; +import me.retrodaredevil.solarthing.config.databases.DatabaseConfig; import me.retrodaredevil.solarthing.config.databases.DatabaseSettings; import me.retrodaredevil.solarthing.config.databases.implementations.CouchDbDatabaseSettings; import me.retrodaredevil.solarthing.packets.collection.DefaultInstanceOptions; import me.retrodaredevil.solarthing.packets.instance.InstanceSourcePacket; -import me.retrodaredevil.solarthing.config.databases.DatabaseConfig; import me.retrodaredevil.solarthing.util.JacksonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +16,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import java.io.File; import java.nio.file.Path; import java.util.Objects; @@ -58,7 +57,7 @@ public void init() { defaultInstanceOptions = DefaultInstanceOptions.create(getDefaultSourceId(), getDefaultFragmentId()); LOGGER.debug("Using defaultInstanceOptions=" + defaultInstanceOptions); LOGGER.debug("Database file: " + databaseFile.toAbsolutePath()); - LOGGER.debug("Working directory: " + new File(".").getAbsolutePath()); + LOGGER.debug("Working directory: " + Path.of(".").toAbsolutePath()); ObjectMapper objectMapper = JacksonUtil.defaultMapper(); objectMapper.getSubtypeResolver().registerSubtypes( diff --git a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/OutputSchemaMain.java b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/OutputSchemaMain.java index bc524b6e..3ffb0157 100644 --- a/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/OutputSchemaMain.java +++ b/server/src/main/java/me/retrodaredevil/solarthing/rest/graphql/OutputSchemaMain.java @@ -13,15 +13,15 @@ import me.retrodaredevil.solarthing.rest.graphql.solcast.SolcastConfig; import me.retrodaredevil.solarthing.util.JacksonUtil; -import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; public class OutputSchemaMain { private OutputSchemaMain() { throw new UnsupportedOperationException(); } public static void main(String[] args) { - File outputFile = new File(args[0]); + Path outputFile = Path.of(args[0]); CouchDbDatabaseSettings couchDbDatabaseSettings = new CouchDbDatabaseSettings( new CouchPropertiesBuilder("http", "localhost", 5984, null, null).build(), @@ -42,7 +42,7 @@ public static void main(String[] args) { ).print(schema); try { - Files.writeString(outputFile.toPath(), schemaString); + Files.writeString(outputFile, schemaString); } catch (IOException e) { throw new RuntimeException(e); }