mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Improve 3A+ case, making it easier to take the pi out. Improve the fit of the Z2 case.
Make it possible for a hub to reload a config automatically when it changes without being restarted. Prevent the auto-calibration on first install from being stomped by the app. Allow updating the hub software via the app.
This commit is contained in:
@@ -2,20 +2,31 @@ package com.lanternsoftware.currentmonitor.context;
|
||||
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.CurrentMonitorDao;
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
|
||||
import com.lanternsoftware.rules.RulesEngine;
|
||||
import com.lanternsoftware.util.DateUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class Globals implements ServletContextListener {
|
||||
public static CurrentMonitorDao dao;
|
||||
private static final Map<Integer, Map<Integer, List<HubCommand>>> commands = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||
RulesEngine.instance().start();
|
||||
RulesEngine.instance().schedule(new CommandTask(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,4 +34,38 @@ public class Globals implements ServletContextListener {
|
||||
dao.shutdown();
|
||||
RulesEngine.shutdown();
|
||||
}
|
||||
|
||||
public static HubCommands getCommandsForHub(int _accountId, int _hub) {
|
||||
List<HubCommand> c = null;
|
||||
synchronized (commands) {
|
||||
Map<Integer, List<HubCommand>> hubCommands = commands.get(_accountId);
|
||||
if (hubCommands != null)
|
||||
c = hubCommands.remove(_hub);
|
||||
}
|
||||
if (c != null) {
|
||||
for (HubCommand command : c) {
|
||||
dao.deleteHubCommand(command.getId());
|
||||
}
|
||||
return new HubCommands(c);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class CommandTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
List<HubCommand> c = Globals.dao.getAllHubCommands();
|
||||
Date stale = DateUtils.addMinutes(new Date(), -5);
|
||||
synchronized (commands) {
|
||||
commands.clear();
|
||||
for (HubCommand command : c) {
|
||||
if (DateUtils.isBefore(command.getCreated(), stale))
|
||||
dao.deleteHubCommand(command.getId());
|
||||
else
|
||||
commands.computeIfAbsent(command.getAccountId(), _t -> new HashMap<>()).computeIfAbsent(command.getHub(), _h->new ArrayList<>()).add(command);
|
||||
}
|
||||
}
|
||||
RulesEngine.instance().schedule(new CommandTask(), 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +44,8 @@ public class AuthServlet extends LanternServlet {
|
||||
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, auth.getPassword(), "").execute();
|
||||
if (tokenResponse != null) {
|
||||
GoogleIdToken idToken = tokenResponse.parseIdToken();
|
||||
if (idToken != null) {
|
||||
logger.info("Successfully received google id token");
|
||||
if (idToken != null)
|
||||
authCode = Globals.dao.getAuthCodeForEmail(idToken.getPayload().getEmail(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
|
||||
logger.info("Auth code for google user is valid: " + (authCode != null));
|
||||
}
|
||||
}
|
||||
} catch (Exception _e) {
|
||||
logger.error("Failed to validate google auth code", _e);
|
||||
|
||||
@@ -1,49 +1,19 @@
|
||||
package com.lanternsoftware.currentmonitor.servlet;
|
||||
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.LanternFiles;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.ResourceLoader;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@WebServlet("/command")
|
||||
public class CommandServlet extends SecureServlet {
|
||||
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
File folder = new File(LanternFiles.OPS_PATH + _authCode.getAccountId());
|
||||
List<String> commands = new ArrayList<>();
|
||||
if (folder.exists() && folder.isDirectory()) {
|
||||
for (File command : CollectionUtils.asArrayList(folder.listFiles())) {
|
||||
if (command.isDirectory())
|
||||
continue;
|
||||
String c = command.getName();
|
||||
String extension = NullUtils.after(c, ".");
|
||||
if (NullUtils.isNotEmpty(extension))
|
||||
c = c.replace("." + extension, "");
|
||||
commands.add(c);
|
||||
}
|
||||
}
|
||||
zipBsonResponse(_rep, new DaoEntity("commands", commands));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
DaoEntity payload = getRequestZipBson(_req);
|
||||
if (payload == null)
|
||||
return;
|
||||
String command = DaoSerializer.getString(payload, "command");
|
||||
String path = LanternFiles.OPS_PATH + _authCode.getAccountId() + File.separator + "payload" + File.separator;
|
||||
new File(path).mkdirs();
|
||||
ResourceLoader.writeFile(path+ command + ".txt", DaoSerializer.getString(payload, "payload"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.lanternsoftware.currentmonitor.servlet;
|
||||
|
||||
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -34,6 +36,10 @@ public class ConfigServlet extends SecureServlet {
|
||||
return;
|
||||
}
|
||||
logger.info("Received config for account {}", config.getAccountId());
|
||||
BreakerConfig oldConfig = Globals.dao.getConfig(config.getAccountId());
|
||||
if ((oldConfig == null) || !oldConfig.isIdentical(config))
|
||||
Globals.dao.putHubCommand(new HubCommand(config.getAccountId(), HubConfigCharacteristic.ReloadConfig, null));
|
||||
Globals.dao.putConfig(config);
|
||||
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package com.lanternsoftware.currentmonitor.servlet;
|
||||
|
||||
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
|
||||
import com.lanternsoftware.util.dao.DaoEntity;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -15,6 +20,8 @@ import java.util.List;
|
||||
|
||||
@WebServlet("/power/*")
|
||||
public class PowerServlet extends SecureServlet {
|
||||
private static final Logger logger = LoggerFactory.getLogger(MongoCurrentMonitorDao.class);
|
||||
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
String[] path = path(_req);
|
||||
@@ -32,19 +39,29 @@ public class PowerServlet extends SecureServlet {
|
||||
String[] path = path(_req);
|
||||
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "hub")) {
|
||||
HubPowerMinute m = getRequestPayload(_req, HubPowerMinute.class);
|
||||
if (m == null)
|
||||
return;
|
||||
logger.info("Hub Power from ip {}, account {}, hub {}", _req.getRemoteAddr(), m.getAccountId(), m.getHub());
|
||||
m.setAccountId(_authCode.getAccountId());
|
||||
Globals.dao.putHubPowerMinute(m);
|
||||
return;
|
||||
}
|
||||
if ((path.length > 0) && NullUtils.isEqual(CollectionUtils.get(path, 0), "batch")) {
|
||||
List<BreakerPower> powers = DaoSerializer.getList(getRequestZipBson(_req), "readings", BreakerPower.class);
|
||||
DaoEntity payload = getRequestZipBson(_req);
|
||||
List<BreakerPower> powers = DaoSerializer.getList(payload, "readings", BreakerPower.class);
|
||||
if (!powers.isEmpty()) {
|
||||
CollectionUtils.edit(powers, _p->_p.setAccountId(_authCode.getAccountId()));
|
||||
Globals.dao.getProxy().save(powers);
|
||||
int hub = DaoSerializer.getInteger(payload, "hub");
|
||||
HubCommands commands = Globals.getCommandsForHub(_authCode.getAccountId(), hub);
|
||||
if (commands != null)
|
||||
zipBsonResponse(_rep, commands);
|
||||
}
|
||||
return;
|
||||
}
|
||||
BreakerPower power = getRequestPayload(_req, BreakerPower.class);
|
||||
if (power == null)
|
||||
return;
|
||||
power.setAccountId(_authCode.getAccountId());
|
||||
Globals.dao.putBreakerPower(power);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.lanternsoftware.currentmonitor.servlet;
|
||||
|
||||
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||
import com.lanternsoftware.datamodel.currentmonitor.Account;
|
||||
import com.lanternsoftware.util.CollectionUtils;
|
||||
import com.lanternsoftware.util.NullUtils;
|
||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||
import com.lanternsoftware.util.dao.auth.AuthCode;
|
||||
|
||||
@@ -9,15 +11,21 @@ import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet("/rebuildSummaries")
|
||||
@WebServlet("/rebuildSummaries/*")
|
||||
public class RebuildSummariesServlet extends SecureServlet {
|
||||
@Override
|
||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||
if (_authCode.getAccountId() == 100) {
|
||||
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
|
||||
int id = DaoSerializer.toInteger(sId);
|
||||
if (id != 0)
|
||||
Globals.dao.rebuildSummariesAsync(id);
|
||||
String[] path = path(_req);
|
||||
if (path.length > 0) {
|
||||
Globals.dao.rebuildSummariesAsync(DaoSerializer.toInteger(CollectionUtils.get(path, 0)));
|
||||
}
|
||||
else {
|
||||
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
|
||||
int id = DaoSerializer.toInteger(sId);
|
||||
if (id != 0)
|
||||
Globals.dao.rebuildSummariesAsync(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -2,16 +2,21 @@
|
||||
<configuration>
|
||||
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>/opt/tomcat/logs/log.txt</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>/opt/tomcat/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
||||
<maxFileSize>20MB</maxFileSize>
|
||||
<maxHistory>20</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="com.lanternsoftware" level="DEBUG"/>
|
||||
|
||||
<root level="OFF">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -2,16 +2,21 @@
|
||||
<configuration>
|
||||
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>/opt/tomcat/logs/log.txt</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>/opt/tomcat/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
|
||||
<maxFileSize>20MB</maxFileSize>
|
||||
<maxHistory>20</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="com.lanternsoftware" level="DEBUG"/>
|
||||
|
||||
<root level="OFF">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user