Refactored many things and removed unnecessary things like IDEA files and stuff
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package net.miarma.contaminus.clase;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
|
||||
public class BroadcastVerticle extends AbstractVerticle {
|
||||
@Override
|
||||
public void start(Promise<Void> promise) {
|
||||
vertx.setPeriodic(2000, _a -> {
|
||||
vertx.eventBus().publish("broadcast.addr", "Ola");
|
||||
});
|
||||
try {
|
||||
promise.complete();
|
||||
} catch (Exception e) {
|
||||
promise.fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.miarma.contaminus.clase;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
|
||||
public class ConsumerVerticle1 extends AbstractVerticle {
|
||||
@Override
|
||||
public void start(Promise<Void> promise) {
|
||||
vertx.eventBus().consumer("broadcast.addr", this::handleMsg);
|
||||
try {
|
||||
promise.complete();
|
||||
} catch (Exception e) {
|
||||
promise.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMsg(Message<String> msg) {
|
||||
Constants.LOGGER.info("Ola Broadcast soy Consumer1");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.miarma.contaminus.clase;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
|
||||
public class ConsumerVerticle2 extends AbstractVerticle {
|
||||
@Override
|
||||
public void start(Promise<Void> promise) {
|
||||
vertx.eventBus().consumer("broadcast.addr", this::handleMsg);
|
||||
try {
|
||||
promise.complete();
|
||||
} catch (Exception e) {
|
||||
promise.fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMsg(Message<String> msg) {
|
||||
Constants.LOGGER.info("Ola Broadcast soy Consumer2");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.miarma.contaminus.clase;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
|
||||
public class MainVerticleClase extends AbstractVerticle {
|
||||
@Override
|
||||
public void start(Promise<Void> promise) {
|
||||
vertx.deployVerticle(new BroadcastVerticle(), result -> {
|
||||
if(result.succeeded()) {
|
||||
Constants.LOGGER.info("📡 BroadcastVerticle desplegado");
|
||||
} else {
|
||||
Constants.LOGGER.error("❌ Error al desplegar BroadcastVerticle", result.cause());
|
||||
}
|
||||
});
|
||||
vertx.deployVerticle(new ConsumerVerticle1(), result -> {
|
||||
if(result.succeeded()) {
|
||||
Constants.LOGGER.info("📡 ConsumerVerticle1 desplegado");
|
||||
} else {
|
||||
Constants.LOGGER.error("❌ Error al desplegar ConsumerVerticle1", result.cause());
|
||||
}
|
||||
});
|
||||
vertx.deployVerticle(new ConsumerVerticle2(), result -> {
|
||||
if(result.succeeded()) {
|
||||
Constants.LOGGER.info("📡 ConsumerVerticle2 desplegado");
|
||||
} else {
|
||||
Constants.LOGGER.error("❌ Error al desplegar ConsumerVerticle2", result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConfigManager {
|
||||
private static ConfigManager instance;
|
||||
private final File configFile;
|
||||
private final Properties config;
|
||||
|
||||
private ConfigManager() {
|
||||
this.configFile = new File(Constants.CONFIG_FILE);
|
||||
this.config = new Properties();
|
||||
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
createFiles();
|
||||
} catch (IOException e) {
|
||||
Constants.LOGGER.error("Error creating configuration files: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
public static synchronized ConfigManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ConfigManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void createFiles() throws IOException {
|
||||
File baseDir = new File(Constants.BASE_DIR);
|
||||
if (!baseDir.exists()) baseDir.mkdirs();
|
||||
|
||||
try (InputStream defaultConfigStream = getClass().getClassLoader().getResourceAsStream("default.properties");
|
||||
FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||
|
||||
if (defaultConfigStream != null) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = defaultConfigStream.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
} else {
|
||||
Constants.LOGGER.error("File not found: default.properties");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
try (FileInputStream fis = new FileInputStream(configFile)) {
|
||||
config.load(fis);
|
||||
} catch (IOException e) {
|
||||
Constants.LOGGER.error("Error loading configuration file: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStringProperty(String key) {
|
||||
return config.getProperty(key);
|
||||
}
|
||||
|
||||
public int getIntProperty(String key) {
|
||||
return Integer.parseInt(config.getProperty(key));
|
||||
}
|
||||
|
||||
public boolean getBooleanProperty(String key) {
|
||||
return Boolean.parseBoolean(config.getProperty(key));
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value) {
|
||||
config.setProperty(key, value);
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
private void saveConfig() {
|
||||
try (FileOutputStream fos = new FileOutputStream(configFile)) {
|
||||
config.store(fos, "Configuration for: " + Constants.APP_NAME);
|
||||
} catch (IOException e) {
|
||||
Constants.LOGGER.error("Error saving configuration file: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import io.vertx.core.impl.logging.Logger;
|
||||
import io.vertx.core.impl.logging.LoggerFactory;
|
||||
|
||||
public class Constants {
|
||||
public static final String APP_NAME = "ContaminUS";
|
||||
public static final String API_PREFIX = "/api/v1";
|
||||
public static final String HOME_DIR = System.getProperty("user.home") + File.separator;
|
||||
public static final String BASE_DIR = HOME_DIR +
|
||||
(SystemInfo.getOS() == OSType.WINDOWS ? ".contaminus" :
|
||||
SystemInfo.getOS() == OSType.LINUX ? ".config" + File.separator +
|
||||
"contaminus" : null);
|
||||
public static final String CONFIG_FILE = BASE_DIR + File.separator + "config.properties";
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(APP_NAME);
|
||||
|
||||
public static final String GET_GROUPS = API_PREFIX + "/groups";
|
||||
public static final String GET_GROUP_BY_ID = API_PREFIX + "/groups/:groupId";
|
||||
public static final String GET_GROUP_DEVICES = API_PREFIX + "/groups/:groupId/devices";
|
||||
public static final String POST_GROUPS = API_PREFIX + "/groups";
|
||||
public static final String PUT_GROUP_BY_ID = API_PREFIX + "/groups/:groupId";
|
||||
|
||||
public static final String GET_DEVICES = API_PREFIX + "/devices";
|
||||
public static final String GET_DEVICE_BY_ID = API_PREFIX + "/devices/:deviceId";
|
||||
public static final String GET_DEVICE_SENSORS = API_PREFIX + "/devices/:deviceId/sensors";
|
||||
public static final String POST_DEVICES = API_PREFIX + "/devices";
|
||||
public static final String PUT_DEVICE_BY_ID = API_PREFIX + "/devices/:deviceId";
|
||||
|
||||
public static final String GET_SENSORS = API_PREFIX + "/sensors";
|
||||
public static final String GET_SENSOR_BY_ID = API_PREFIX + "/sensors/:sensorId";
|
||||
public static final String GET_SENSOR_VALUES = API_PREFIX + "/sensors/:sensorId/values";
|
||||
public static final String POST_SENSORS = API_PREFIX + "/sensors";
|
||||
public static final String PUT_SENSOR_BY_ID = API_PREFIX + "/sensors/:sensorId";
|
||||
|
||||
public static final String GET_ACTUATORS = API_PREFIX + "/actuators";
|
||||
public static final String GET_ACTUATOR_BY_ID = API_PREFIX + "/actuators/:actuatorId";
|
||||
public static final String POST_ACTUATORS = API_PREFIX + "/actuators";
|
||||
public static final String PUT_ACTUATOR_BY_ID = API_PREFIX + "/actuators/:actuatorId";
|
||||
|
||||
public static final String GET_GPS_VALUES = API_PREFIX + "/gps-values";
|
||||
public static final String GET_GPS_VALUE_BY_ID = API_PREFIX + "/gps-values/:valueId";
|
||||
public static final String POST_GPS_VALUES = API_PREFIX + "/gps-values";
|
||||
|
||||
public static final String GET_AIR_VALUES = API_PREFIX + "/air-values";
|
||||
public static final String GET_AIR_VALUE_BY_ID = API_PREFIX + "/air-values/:valueId";
|
||||
public static final String POST_AIR_VALUES = API_PREFIX + "/air-values";
|
||||
|
||||
private Constants() {
|
||||
throw new AssertionError("Utility class cannot be instantiated.");
|
||||
}
|
||||
}
|
||||
25
backend/src/main/java/net/miarma/contaminus/common/Host.java
Normal file
25
backend/src/main/java/net/miarma/contaminus/common/Host.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
public class Host {
|
||||
static ConfigManager configManager = ConfigManager.getInstance();
|
||||
static String host = configManager.getStringProperty("inet.host");
|
||||
static int apiPort = configManager.getIntProperty("api.port");
|
||||
static int webserverPort = configManager.getIntProperty("webserver.port");
|
||||
|
||||
public static String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public static int getApiPort() {
|
||||
return apiPort;
|
||||
}
|
||||
|
||||
public static int getWebserverPort() {
|
||||
return webserverPort;
|
||||
}
|
||||
|
||||
public static String getOrigin() {
|
||||
return "http://" + host + ":" + webserverPort;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime>, JsonDeserializer<LocalDateTime> {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.format(FORMATTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return LocalDateTime.parse(json.getAsString(), FORMATTER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
public enum OSType {
|
||||
LINUX, WINDOWS, INVALID_OS;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.miarma.contaminus.common;
|
||||
|
||||
public class SystemInfo {
|
||||
public static OSType getOS() {
|
||||
String envProperty = System.getProperty("os.name").toLowerCase();
|
||||
if(envProperty.contains("windows")) {
|
||||
return OSType.WINDOWS;
|
||||
} else if(envProperty.contains("linux")) {
|
||||
return OSType.LINUX;
|
||||
} else {
|
||||
return OSType.INVALID_OS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.miarma.contaminus.database;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.jdbcclient.JDBCPool;
|
||||
import net.miarma.contaminus.common.ConfigManager;
|
||||
|
||||
public class DatabaseManager {
|
||||
private final JDBCPool pool;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public DatabaseManager(Vertx vertx) {
|
||||
ConfigManager config = ConfigManager.getInstance();
|
||||
|
||||
JsonObject dbConfig = new JsonObject()
|
||||
.put("url", config.getStringProperty("db.protocol") + "//" +
|
||||
config.getStringProperty("db.host") + ":" +
|
||||
config.getStringProperty("db.port") + "/" +
|
||||
config.getStringProperty("db.name"))
|
||||
.put("user", config.getStringProperty("db.user"))
|
||||
.put("password", config.getStringProperty("db.pwd"))
|
||||
.put("max_pool_size", config.getStringProperty("db.poolSize"));
|
||||
|
||||
pool = JDBCPool.pool(vertx, dbConfig);
|
||||
}
|
||||
|
||||
public JDBCPool getPool() {
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package net.miarma.contaminus.database;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class QueryBuilder {
|
||||
private StringBuilder query;
|
||||
private List<String> conditions;
|
||||
private String sort;
|
||||
private String order;
|
||||
private String limit;
|
||||
|
||||
public QueryBuilder() {
|
||||
this.query = new StringBuilder();
|
||||
this.conditions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static QueryBuilder select(String... columns) {
|
||||
QueryBuilder qb = new QueryBuilder();
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (String column : columns) {
|
||||
joiner.add(column);
|
||||
}
|
||||
qb.query.append("SELECT ").append(joiner).append(" ");
|
||||
return qb;
|
||||
}
|
||||
|
||||
public static QueryBuilder insert(String table, String... columns) {
|
||||
QueryBuilder qb = new QueryBuilder();
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
if (columns.length > 0) {
|
||||
for (String column : columns) {
|
||||
joiner.add(column);
|
||||
}
|
||||
qb.query.append("INSERT INTO ").append(table).append(" (").append(joiner).append(") ");
|
||||
} else {
|
||||
qb.query.append("INSERT INTO ").append(table).append(" ");
|
||||
}
|
||||
|
||||
return qb;
|
||||
}
|
||||
|
||||
public static QueryBuilder update(String table) {
|
||||
QueryBuilder qb = new QueryBuilder();
|
||||
qb.query.append("UPDATE ").append(table).append(" ");
|
||||
return qb;
|
||||
}
|
||||
|
||||
public QueryBuilder set(String column, Object value) {
|
||||
if(value instanceof String) {
|
||||
query.append("SET ").append(column).append(" = '").append(value).append("' ");
|
||||
} else {
|
||||
query.append("SET ").append(column).append(" = ").append(value).append(" ");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder values(Object... values) {
|
||||
StringJoiner joiner = new StringJoiner(", ", "VALUES (", ")");
|
||||
for (Object value : values) {
|
||||
if(value instanceof String) {
|
||||
joiner.add("'" + value + "'");
|
||||
} else if(value == null) {
|
||||
joiner.add("NULL");
|
||||
}
|
||||
else {
|
||||
joiner.add(value.toString());
|
||||
}
|
||||
}
|
||||
this.query.append(joiner).append(" ");
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder from(String table) {
|
||||
query.append("FROM ").append(table).append(" ");
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder where(String conditionsString, Object... values) {
|
||||
conditionsString = conditionsString.replaceAll("\\?", "%s");
|
||||
conditions.add(String.format(conditionsString, values));
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder orderBy(Optional<String> column, Optional<String> order) {
|
||||
if (column.isPresent()) {
|
||||
sort = "ORDER BY " + column.get() + " ";
|
||||
if (order.isPresent()) {
|
||||
sort += order.get().equalsIgnoreCase("asc") ? "ASC" : "DESC" + " ";
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder limit(Optional<Integer> limitParam) {
|
||||
limit = limitParam.isPresent() ? "LIMIT " + limitParam.get() + " " : "";
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
if (!conditions.isEmpty()) {
|
||||
query.append("WHERE ");
|
||||
StringJoiner joiner = new StringJoiner(" AND ");
|
||||
for (String condition : conditions) {
|
||||
joiner.add(condition);
|
||||
}
|
||||
query.append(joiner).append(" ");
|
||||
}
|
||||
if (order != null && !order.isEmpty()) {
|
||||
query.append(order);
|
||||
}
|
||||
if (sort != null && !sort.isEmpty()) {
|
||||
query.append(sort);
|
||||
}
|
||||
if (limit != null && !limit.isEmpty()) {
|
||||
query.append(limit);
|
||||
}
|
||||
return query.toString().trim() + ";";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
package net.miarma.contaminus.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import io.vertx.core.http.HttpMethod;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.RoutingContext;
|
||||
import io.vertx.ext.web.handler.BodyHandler;
|
||||
import io.vertx.ext.web.handler.CorsHandler;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
import net.miarma.contaminus.common.Host;
|
||||
import net.miarma.contaminus.database.QueryBuilder;
|
||||
|
||||
public class ApiVerticle extends AbstractVerticle {
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
Constants.LOGGER.info("🟢 Iniciando ApiVerticle...");
|
||||
Router router = Router.router(vertx);
|
||||
|
||||
Set<HttpMethod> allowedMethods = new HashSet<>(Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT)); // Por ejemplo
|
||||
Set<String> allowedHeaders = new HashSet<>(Arrays.asList("Content-Type", "Authorization"));
|
||||
|
||||
router.route().handler(CorsHandler.create()
|
||||
.addOrigin(Host.getOrigin())
|
||||
.allowCredentials(true)
|
||||
.allowedHeaders(allowedHeaders)
|
||||
.allowedMethods(allowedMethods));
|
||||
router.route().handler(BodyHandler.create());
|
||||
|
||||
// Group Routes
|
||||
router.route(HttpMethod.GET, Constants.GET_GROUPS).handler(this::getGroupsHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_GROUP_BY_ID).handler(this::getGroupByIdHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_GROUP_DEVICES).handler(this::getGroupDevicesHandler);
|
||||
router.route(HttpMethod.POST, Constants.POST_GROUPS).handler(this::postGroupHandler);
|
||||
router.route(HttpMethod.PUT, Constants.PUT_GROUP_BY_ID).handler(this::putGroupByIdHandler);
|
||||
|
||||
// Device Routes
|
||||
router.route(HttpMethod.GET, Constants.GET_DEVICES).handler(this::getDevicesHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_DEVICE_BY_ID).handler(this::getDeviceByIdHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_DEVICE_SENSORS).handler(this::getDeviceSensorsHandler);
|
||||
router.route(HttpMethod.POST, Constants.POST_DEVICES).handler(this::postDeviceHandler);
|
||||
router.route(HttpMethod.PUT, Constants.PUT_DEVICE_BY_ID).handler(this::putDeviceByIdHandler);
|
||||
|
||||
// Sensor Routes
|
||||
router.route(HttpMethod.GET, Constants.GET_SENSORS).handler(this::getSensorsHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_SENSOR_BY_ID).handler(this::getSensorByIdHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_SENSOR_VALUES).handler(this::getSensorValuesHandler);
|
||||
router.route(HttpMethod.POST, Constants.POST_SENSORS).handler(this::postSensorHandler);
|
||||
router.route(HttpMethod.PUT, Constants.PUT_SENSOR_BY_ID).handler(this::putSensorByIdHandler);
|
||||
|
||||
// Actuator Routes
|
||||
router.route(HttpMethod.GET, Constants.GET_ACTUATORS).handler(this::getActuatorsHandler);
|
||||
router.route(HttpMethod.GET, Constants.GET_ACTUATOR_BY_ID).handler(this::getActuatorByIdHandler);
|
||||
router.route(HttpMethod.POST, Constants.POST_ACTUATORS).handler(this::postActuatorHandler);
|
||||
router.route(HttpMethod.PUT, Constants.PUT_ACTUATOR_BY_ID).handler(this::putActuatorByIdHandler);
|
||||
|
||||
vertx.createHttpServer()
|
||||
.requestHandler(router)
|
||||
.listen(
|
||||
Host.getApiPort(),
|
||||
Host.getHost(),
|
||||
result -> {
|
||||
if (result.succeeded()) {
|
||||
Constants.LOGGER.info(String.format(
|
||||
"📡 ApiVerticle desplegado. (http://%s:%d)", Host.getHost(), Host.getApiPort()
|
||||
));
|
||||
startPromise.complete();
|
||||
} else {
|
||||
Constants.LOGGER.error("❌ Error al desplegar ApiVerticle", result.cause());
|
||||
startPromise.fail(result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendQuery(String query, RoutingContext context) {
|
||||
vertx.eventBus().request("db.query", query, req -> {
|
||||
if (req.succeeded()) {
|
||||
Message<Object> msg = req.result();
|
||||
JsonArray jsonArray = new JsonArray(msg.body().toString());
|
||||
context.json(jsonArray);
|
||||
} else {
|
||||
context.fail(500, req.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Group Handlers
|
||||
private void getGroupsHandler(RoutingContext context) {
|
||||
String query = QueryBuilder.select("*").from("groups").build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getGroupByIdHandler(RoutingContext context) {
|
||||
String groupId = context.request().getParam("groupId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("groups")
|
||||
.where("groupId = ?", groupId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getGroupDevicesHandler(RoutingContext context) {
|
||||
String groupId = context.request().getParam("groupId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("devices")
|
||||
.where("groupId = ?", groupId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void postGroupHandler(RoutingContext context) {
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
String groupName = body.getString("groupName");
|
||||
|
||||
String query = QueryBuilder
|
||||
.insert("groups", "groupName")
|
||||
.values(groupName)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void putGroupByIdHandler(RoutingContext context) {
|
||||
String groupId = context.request().getParam("groupId");
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
String groupName = body.getString("groupName");
|
||||
|
||||
String query = QueryBuilder
|
||||
.update("groups")
|
||||
.set("groupName", groupName)
|
||||
.where("groupId = ?", groupId)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
// Device Handlers
|
||||
private void getDevicesHandler(RoutingContext context) {
|
||||
String query = QueryBuilder.select("*").from("devices").build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getDeviceByIdHandler(RoutingContext context) {
|
||||
String deviceId = context.request().getParam("deviceId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("devices")
|
||||
.where("deviceId = ?", deviceId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getDeviceSensorsHandler(RoutingContext context) {
|
||||
String deviceId = context.request().getParam("deviceId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("sensors")
|
||||
.where("deviceId = ?", deviceId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void postDeviceHandler(RoutingContext context) {
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer groupId = body.getInteger("groupId");
|
||||
String deviceName = body.getString("groupName");
|
||||
|
||||
String query = QueryBuilder
|
||||
.insert("devices", "groupId", "deviceName")
|
||||
.values(groupId, deviceName)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void putDeviceByIdHandler(RoutingContext context) {
|
||||
String deviceId = context.request().getParam("deviceId");
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer groupId = body.getInteger("groupId");
|
||||
String deviceName = body.getString("deviceName");
|
||||
|
||||
String query = QueryBuilder
|
||||
.update("devices")
|
||||
.set("groupId", groupId)
|
||||
.set("deviceName", deviceName)
|
||||
.where("deviceId = ?", deviceId)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
// Sensor Handlers
|
||||
private void getSensorsHandler(RoutingContext context) {
|
||||
String query = QueryBuilder.select("*").from("sensors").build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getSensorByIdHandler(RoutingContext context) {
|
||||
String sensorId = context.request().getParam("sensorId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("sensors")
|
||||
.where("sensorId = ?", sensorId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getSensorValuesHandler(RoutingContext context) {
|
||||
String sensorId = context.request().getParam("sensorId");
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("v_sensor_values")
|
||||
.where("sensorId = ?", sensorId)
|
||||
.build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void postSensorHandler(RoutingContext context) {
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer deviceId = body.getInteger("deviceId");
|
||||
String sensorType = body.getString("sensorType");
|
||||
String unit = body.getString("unit");
|
||||
Integer status = body.getInteger("status");
|
||||
|
||||
String query = QueryBuilder
|
||||
.insert("sensors", "deviceId", "sensorType", "unit", "status")
|
||||
.values(deviceId, sensorType, unit, status)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void putSensorByIdHandler(RoutingContext context) {
|
||||
String sensorId = context.request().getParam("sensorId");
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer deviceId = body.getInteger("deviceId");
|
||||
String sensorType = body.getString("sensorType");
|
||||
String unit = body.getString("unit");
|
||||
Integer status = body.getInteger("status");
|
||||
|
||||
String query = QueryBuilder
|
||||
.update("sensors")
|
||||
.set("deviceId", deviceId)
|
||||
.set("sensorType", sensorType)
|
||||
.set("unit", unit)
|
||||
.set("status", status)
|
||||
.where("sensorId = ?", sensorId)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
// Actuator Handlers
|
||||
private void getActuatorsHandler(RoutingContext context) {
|
||||
String query = QueryBuilder.select("*").from("actuators").build();
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void getActuatorByIdHandler(RoutingContext context) {
|
||||
String actuatorId = context.request().getParam("actuatorId");
|
||||
|
||||
String query = QueryBuilder
|
||||
.select("*")
|
||||
.from("actuators")
|
||||
.where("actuatorId = ?", actuatorId)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void postActuatorHandler(RoutingContext context) {
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer deviceId = body.getInteger("deviceId");
|
||||
Integer status = body.getInteger("status");
|
||||
|
||||
String query = QueryBuilder
|
||||
.insert("actuators", "deviceId", "status")
|
||||
.values(deviceId, status)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
private void putActuatorByIdHandler(RoutingContext context) {
|
||||
String actuatorId = context.request().getParam("actuatorId");
|
||||
JsonObject body = context.body().asJsonObject();
|
||||
|
||||
if(body == null) {
|
||||
context.fail(400, new IllegalArgumentException("Bad request"));
|
||||
return;
|
||||
}
|
||||
|
||||
Integer deviceId = body.getInteger("deviceId");
|
||||
Integer status = body.getInteger("status");
|
||||
|
||||
String query = QueryBuilder
|
||||
.update("actuators")
|
||||
.set("deviceId", deviceId)
|
||||
.set("status", status)
|
||||
.where("actuatorId = ?", actuatorId)
|
||||
.build();
|
||||
|
||||
sendQuery(query, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package net.miarma.contaminus.server;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.eventbus.EventBus;
|
||||
import io.vertx.core.eventbus.Message;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.jdbcclient.JDBCPool;
|
||||
import io.vertx.sqlclient.Row;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
import net.miarma.contaminus.common.LocalDateTimeSerializer;
|
||||
import net.miarma.contaminus.database.DatabaseManager;
|
||||
|
||||
public class DatabaseVerticle extends AbstractVerticle {
|
||||
private JDBCPool pool;
|
||||
private EventBus eventBus;
|
||||
private Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
|
||||
.create();;
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
Constants.LOGGER.info("🟢 Iniciando DatabaseVerticle...");
|
||||
|
||||
DatabaseManager dbManager = new DatabaseManager(vertx);
|
||||
pool = dbManager.getPool();
|
||||
eventBus = vertx.eventBus();
|
||||
|
||||
pool.query("SELECT 1")
|
||||
.execute()
|
||||
.onSuccess(_res -> {
|
||||
Constants.LOGGER.info("✅ Database connection ok");
|
||||
Constants.LOGGER.info("📡 DatabaseVerticle desplegado");
|
||||
startPromise.complete();
|
||||
})
|
||||
.onFailure(err -> {
|
||||
Constants.LOGGER.error("❌ Database connection failed");
|
||||
Constants.LOGGER.error("❌ Error al desplegar DatabaseVerticle", err);
|
||||
startPromise.fail(err);
|
||||
});
|
||||
|
||||
eventBus.consumer("db.query", this::handleDatabaseQuery);
|
||||
}
|
||||
|
||||
private void handleDatabaseQuery(Message<String> msg) {
|
||||
String query = msg.body();
|
||||
Constants.LOGGER.info("📥 Query: " + query);
|
||||
|
||||
if(query == null || query.isEmpty()) {
|
||||
msg.fail(400, "Empty query");
|
||||
return;
|
||||
}
|
||||
|
||||
if(query.startsWith("SELECT")) {
|
||||
handleSelectQuery(query, msg);
|
||||
} else if(query.startsWith("INSERT")) {
|
||||
handleInsertQuery(query, msg);
|
||||
} else if(query.startsWith("UPDATE")) {
|
||||
handleUpdateQuery(query, msg);
|
||||
} else {
|
||||
msg.fail(400, "Invalid operation");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSelectQuery(String query, Message<String> msg) {
|
||||
pool.query(query).execute()
|
||||
.onSuccess(res -> {
|
||||
List<Map<String, Object>> rowsList = new ArrayList<>();
|
||||
|
||||
for (Row row : res) {
|
||||
Map<String, Object> rowMap = new HashMap<>();
|
||||
for (int i = 0; i < row.size(); i++) {
|
||||
String columnName = res.columnsNames().get(i);
|
||||
Object columnValue = row.getValue(i);
|
||||
rowMap.put(columnName, columnValue);
|
||||
}
|
||||
rowsList.add(rowMap);
|
||||
}
|
||||
|
||||
String jsonResponse = gson.toJson(rowsList);
|
||||
msg.reply(jsonResponse);
|
||||
})
|
||||
.onFailure(err -> msg.fail(500, err.getMessage()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleInsertQuery(String query, Message<String> msg) {
|
||||
pool.query(query).execute()
|
||||
.onSuccess(_res -> {
|
||||
JsonObject response = new JsonObject();
|
||||
response.put("status", "success");
|
||||
String jsonResponse = gson.toJson(response);
|
||||
msg.reply(jsonResponse);
|
||||
})
|
||||
.onFailure(err -> msg.fail(500, err.getMessage()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleUpdateQuery(String query, Message<String> msg) {
|
||||
pool.query(query).execute()
|
||||
.onSuccess(_res -> {
|
||||
JsonObject response = new JsonObject();
|
||||
response.put("status", "updated");
|
||||
String jsonResponse = gson.toJson(response);
|
||||
msg.reply(jsonResponse);
|
||||
})
|
||||
.onFailure(err -> msg.fail(500, err.getMessage()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.miarma.contaminus.server;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.ext.web.Router;
|
||||
import io.vertx.ext.web.handler.StaticHandler;
|
||||
import net.miarma.contaminus.common.Constants;
|
||||
import net.miarma.contaminus.common.Host;
|
||||
|
||||
public class HttpServerVerticle extends AbstractVerticle {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Constants.LOGGER.info("🟢 Iniciando HttpServerVerticle...");
|
||||
Router router = Router.router(vertx);
|
||||
router.route("/*").handler(StaticHandler.create("webroot").setDefaultContentEncoding("UTF-8"));
|
||||
|
||||
vertx.createHttpServer().requestHandler(router).listen(
|
||||
Host.getWebserverPort(), Host.getHost(), result -> {
|
||||
if (result.succeeded()) {
|
||||
Constants.LOGGER.info(String.format("📡 HttpServerVerticle desplegado. (http://%s:%d)",
|
||||
Host.getHost(), Host.getWebserverPort())
|
||||
);
|
||||
} else {
|
||||
Constants.LOGGER.error("❌ Error al desplegar HttpServerVerticle", result.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.miarma.contaminus.server;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.DeploymentOptions;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.ThreadingModel;
|
||||
|
||||
public class MainVerticle extends AbstractVerticle {
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
final DeploymentOptions options = new DeploymentOptions();
|
||||
options.setThreadingModel(ThreadingModel.WORKER);
|
||||
|
||||
getVertx().deployVerticle(new DatabaseVerticle(), options);
|
||||
getVertx().deployVerticle(new ApiVerticle(), options);
|
||||
getVertx().deployVerticle(new HttpServerVerticle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Promise<Void> stopPromise) throws Exception {
|
||||
getVertx().deploymentIDs()
|
||||
.forEach(v -> getVertx().undeploy(v));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.miarma.contaminus.server;
|
||||
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
|
||||
public class MqttVerticle extends AbstractVerticle {
|
||||
|
||||
}
|
||||
13
backend/src/main/resources/default.properties
Normal file
13
backend/src/main/resources/default.properties
Normal file
@@ -0,0 +1,13 @@
|
||||
# DB Configuration
|
||||
db.protocol=jdbc:mariadb:
|
||||
db.host=localhost
|
||||
db.port=3306
|
||||
db.name=dad
|
||||
db.user=root
|
||||
db.pwd=root
|
||||
dp.poolSize=5
|
||||
|
||||
# Server Configuration
|
||||
inet.host=localhost
|
||||
webserver.port=8080
|
||||
api.port=8081
|
||||
File diff suppressed because one or more lines are too long
601
backend/src/main/resources/webroot/assets/index-B9-ngIAm.js
Normal file
601
backend/src/main/resources/webroot/assets/index-B9-ngIAm.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
17
backend/src/main/resources/webroot/assets/react-vendors-DbHEDQBy.js
vendored
Normal file
17
backend/src/main/resources/webroot/assets/react-vendors-DbHEDQBy.js
vendored
Normal file
File diff suppressed because one or more lines are too long
71
backend/src/main/resources/webroot/config/settings.json
Normal file
71
backend/src/main/resources/webroot/config/settings.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"userConfig": {
|
||||
"city": [
|
||||
37.38283,
|
||||
-5.97317
|
||||
]
|
||||
},
|
||||
"appConfig": {
|
||||
"endpoints": {
|
||||
"baseUrl": "http://localhost:8081/api/v1",
|
||||
"sensors": "sensors",
|
||||
"sensor": "sensors/sensor"
|
||||
},
|
||||
"historyChartConfig": {
|
||||
"chartOptionsDark": {
|
||||
"responsive": true,
|
||||
"maintainAspectRatio": false,
|
||||
"scales": {
|
||||
"x": {
|
||||
"grid": {
|
||||
"color": "rgba(255, 255, 255, 0.1)"
|
||||
},
|
||||
"ticks": {
|
||||
"color": "#E0E0E0"
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
"grid": {
|
||||
"color": "rgba(255, 255, 255, 0.1)"
|
||||
},
|
||||
"ticks": {
|
||||
"color": "#E0E0E0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"legend": {
|
||||
"display": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"chartOptionsLight": {
|
||||
"responsive": true,
|
||||
"maintainAspectRatio": false,
|
||||
"scales": {
|
||||
"x": {
|
||||
"grid": {
|
||||
"color": "rgba(0, 0, 0, 0.1)"
|
||||
},
|
||||
"ticks": {
|
||||
"color": "#333"
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
"grid": {
|
||||
"color": "rgba(0, 0, 0, 0.1)"
|
||||
},
|
||||
"ticks": {
|
||||
"color": "#333"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"legend": {
|
||||
"display": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
backend/src/main/resources/webroot/images/favicon.ico
Normal file
BIN
backend/src/main/resources/webroot/images/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
backend/src/main/resources/webroot/images/logo.png
Normal file
BIN
backend/src/main/resources/webroot/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 412 KiB |
27
backend/src/main/resources/webroot/index.html
Normal file
27
backend/src/main/resources/webroot/index.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta property="og:title" content="ContaminUS" />
|
||||
<meta property="og:description" content="Midiendo la calidad del aire y las calles en Sevilla 🌿🚛" />
|
||||
<meta property="og:image" content="https://contaminus.miarma.net/logo.png" />
|
||||
<meta property="og:url" content="https://contaminus.miarma.net/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:locale" content="es_ES" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="ContaminUS" />
|
||||
<meta name="twitter:description" content="Midiendo la calidad del aire y las calles en Sevilla 🌿🚛" />
|
||||
<meta name="twitter:image" content="https://contaminus.miarma.net/logo.png" />
|
||||
<link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon">
|
||||
<title>ContaminUS</title>
|
||||
<script type="module" crossorigin src="/assets/index-B9-ngIAm.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/react-vendors-DbHEDQBy.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/leaflet-DYDK0jU3.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/chartjs-C6LAl0aW.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DhzIL-fx.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
Reference in New Issue
Block a user