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

View File

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

View File

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

View File

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

View File

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

View File

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

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,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;
}
}

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

@@ -0,0 +1,5 @@
package net.miarma.contaminus.common;
public enum OSType {
LINUX, WINDOWS, INVALID_OS;
}

View File

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

View File

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

View File

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

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

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

View File

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

View File

@@ -0,0 +1,7 @@
package net.miarma.contaminus.server;
import io.vertx.core.AbstractVerticle;
public class MqttVerticle extends AbstractVerticle {
}

View 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

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

File diff suppressed because one or more lines are too long

View 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
}
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

View 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>