1
0

Refactored many things and removed unnecessary things like IDEA files and stuff

This commit is contained in:
Jose
2025-03-11 19:35:38 +01:00
parent b597aca295
commit 3ba205e176
56 changed files with 580 additions and 443 deletions

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

13
.idea/compiler.xml generated
View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="contaminus" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

14
.idea/misc.xml generated
View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/backend/vertx/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" project-jdk-name="23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/ContaminUS.iml" filepath="$PROJECT_DIR$/ContaminUS.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ContaminUS</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/bin" />
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="23" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -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.");
}
}

View File

@@ -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);
}
}

View File

@@ -42,6 +42,21 @@ public class QueryBuilder {
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) {
@@ -83,7 +98,7 @@ public class QueryBuilder {
limit = limitParam.isPresent() ? "LIMIT " + limitParam.get() + " " : "";
return this;
}
public String build() {
if (!conditions.isEmpty()) {
query.append("WHERE ");
@@ -104,4 +119,6 @@ public class QueryBuilder {
}
return query.toString().trim() + ";";
}
}
}

View File

@@ -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);
}
}

View File

@@ -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()));
}
}

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 412 KiB

After

Width:  |  Height:  |  Size: 412 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 412 KiB

After

Width:  |  Height:  |  Size: 412 KiB

View File

@@ -1,22 +0,0 @@
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);
private Constants() {
throw new AssertionError("Utility class cannot be instantiated.");
}
}

View File

@@ -1,83 +0,0 @@
package net.miarma.contaminus.database.models;
import java.sql.Timestamp;
public class Sensor {
private int id;
private String sensorType;
private float value;
private float lat;
private float lon;
private Timestamp timestamp;
public Sensor() {}
public Sensor(int id, String sensorType, float value, float lat, float lon, Timestamp timestamp) {
this.id = id;
this.sensorType = sensorType;
this.value = value;
this.lat = lat;
this.lon = lon;
this.timestamp = timestamp;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSensorType() {
return sensorType;
}
public void setSensorType(String sensorType) {
this.sensorType = sensorType;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
public float getLat() {
return lat;
}
public void setLat(float lat) {
this.lat = lat;
}
public float getLon() {
return lon;
}
public void setLon(float lon) {
this.lon = lon;
}
public Timestamp getTimestamp() {
return timestamp;
}
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
return "Sensor{" +
"id=" + id +
", sensorType='" + sensorType + '\'' +
", value=" + value +
", lat=" + lat +
", lon=" + lon +
", timestamp=" + timestamp +
'}';
}
}

View File

@@ -1,157 +0,0 @@
package net.miarma.contaminus.server;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
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());
router.get(Constants.API_PREFIX + "/devices").blockingHandler(this::getAllDevices);
router.get(Constants.API_PREFIX + "/devices/:id").blockingHandler(this::getDeviceById);
router.post(Constants.API_PREFIX + "/devices").blockingHandler(this::insertSensor);
router.get(Constants.API_PREFIX + "/status").handler(ctx -> ctx.json(new JsonObject().put("status", "OK")));
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 getAllDevices(RoutingContext context) {
Optional<String> sort = Optional.ofNullable(context.request().getParam("_sort"));
Optional<String> order = Optional.ofNullable(context.request().getParam("_order"));
Optional<Integer> limit = Optional.ofNullable(context.request().getParam("_limit"))
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null;
}
});
String query = QueryBuilder
.select("*")
.from("v_DevicesMeasures")
.orderBy(sort, order)
.limit(limit)
.build();
vertx.eventBus().request("db.query", query, req -> {
if (req.succeeded()) {
Message<Object> result = req.result();
JsonArray jsonArray = (JsonArray) result.body();
context.json(jsonArray);
} else {
context.fail(500, req.cause());
}
});
}
private void getDeviceById(RoutingContext context) {
Optional<String> sort = Optional.ofNullable(context.request().getParam("_sort"));
Optional<String> order = Optional.ofNullable(context.request().getParam("_order"));
Optional<Integer> limit = Optional.ofNullable(context.request().getParam("_limit"))
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null;
}
});
String id = context.request().getParam("id");
String query = QueryBuilder
.select("*")
.from("v_DevicesMeasures")
.where("deviceId = ?", id)
.orderBy(sort, order)
.limit(limit)
.build();
vertx.eventBus().request("db.query", query, req -> {
if (req.succeeded()) {
Message<Object> result = req.result();
JsonArray jsonArray = (JsonArray) result.body();
context.json(jsonArray);
} else {
context.fail(500, req.cause());
}
});
}
private void insertSensor(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.fail(400, new IllegalArgumentException("Body is missing or invalid"));
return;
}
Integer deviceId = body.getInteger("deviceId");
String sensorType = body.getString("sensorType");
Float lat = body.getFloat("lat");
Float lon = body.getFloat("lon");
Float value = body.getFloat("value");
if (sensorType == null || lat == null || lon == null || value == null) {
context.fail(400, new IllegalArgumentException("Missing required fields"));
return;
}
String query = QueryBuilder
.insert("measures", "deviceId", "sensorType", "lat", "lon", "value")
.values(deviceId, sensorType, lat, lon, value)
.build();
vertx.eventBus().request("db.query", query, req -> {
if (req.succeeded()) {
context.json(new JsonObject().put("result", "OK"));
} else {
context.fail(500, req.cause());
}
});
}
}

View File

@@ -1,83 +0,0 @@
package net.miarma.contaminus.server;
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.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.database.DatabaseManager;
public class DatabaseVerticle extends AbstractVerticle {
private JDBCPool pool;
private EventBus eventBus;
@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);
}
@SuppressWarnings("unused")
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")) {
pool.query(query).execute()
.onSuccess(res -> {
RowSet<Row> rows = res;
JsonArray jsonArray = new JsonArray();
for (Row row : rows) {
jsonArray.add(new JsonObject()
.put("deviceId", row.getInteger("deviceId"))
.put("deviceName", row.getString("deviceName"))
.put("measureId", row.getInteger("measureId"))
.put("sensorType", row.getString("sensorType"))
.put("lat", row.getFloat("lat"))
.put("lon", row.getFloat("lon"))
.put("value", row.getFloat("value"))
.put("timestamp", row.getLocalDateTime("timestamp").toString())
);
}
msg.reply(jsonArray);
})
.onFailure(err -> msg.fail(500, err.getMessage()));
} else if(query.startsWith("INSERT")) {
pool.query(msg.body()).execute()
.onSuccess(_res -> msg.reply(new JsonObject().put("status", "success")))
.onFailure(err -> msg.fail(500, err.getMessage()));
} else {
msg.fail(400, "Invalid operation");
}
}
}

6
package-lock.json generated
View File

@@ -1,6 +0,0 @@
{
"name": "ContaminUS",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}