diff --git a/.air.bot.toml b/.air.bot.toml new file mode 100644 index 0000000..d3cd58f --- /dev/null +++ b/.air.bot.toml @@ -0,0 +1,8 @@ +root = "." +tmp_dir = "tmp_bot" + +[build] + cmd = "go build -o ./tmp_bot/main ./cmd/bot/main.go" + bin = "./tmp_bot/main" + delay = 1000 + diff --git a/.air.web.toml b/.air.web.toml new file mode 100644 index 0000000..0438733 --- /dev/null +++ b/.air.web.toml @@ -0,0 +1,8 @@ +root = "." +tmp_dir = "tmp_web" + +[build] + cmd = "go build -o ./tmp_web/main ./cmd/web/main.go" + bin = "./tmp_web/main" + delay = 1000 + diff --git a/Dockerfile.bot b/Dockerfile.bot new file mode 100644 index 0000000..c530297 --- /dev/null +++ b/Dockerfile.bot @@ -0,0 +1,26 @@ +FROM golang:1.21.4 + +ARG DOCKER_ENV=production # Set default build-time value, not persisted in the container +ENV DOCKER_ENV=${DOCKER_ENV} # Set runtime environment variable inside the container + +WORKDIR /code + +RUN echo "Building with DOCKER_ENV=${DOCKER_ENV}" + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go mod tidy && \ + if [ "$DOCKER_ENV" = "local" ]; then \ + echo "Local environment detected, installing Air..."; \ + go install github.com/cosmtrek/air@v1.49.0; \ + fi + +CMD if [ "$DOCKER_ENV" = "local" ]; then \ + echo "Local environment detected, running Air..." && \ + air -c .air.bot.toml; \ + else \ + echo "Production environment detected, building and running bot..."; \ + go build -o bot ./cmd/bot/main.go && ./bot; \ + fi diff --git a/Dockerfile.web b/Dockerfile.web new file mode 100644 index 0000000..784d7bc --- /dev/null +++ b/Dockerfile.web @@ -0,0 +1,26 @@ +FROM golang:1.21.4 + +ARG DOCKER_ENV=production # Set default build-time value, not persisted in the container +ENV DOCKER_ENV=${DOCKER_ENV} # Set runtime environment variable inside the container + +WORKDIR /code + +RUN echo "Building with DOCKER_ENV=${DOCKER_ENV}" + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go mod tidy && \ + if [ "$DOCKER_ENV" = "local" ]; then \ + echo "Local environment detected, installing Air..."; \ + go install github.com/cosmtrek/air@v1.49.0; \ + fi + +CMD if [ "$DOCKER_ENV" = "local" ]; then \ + echo "Local environment detected, running Air..." && \ + air -c .air.web.toml; \ + else \ + echo "Production environment detected, building and running web..."; \ + go build -o web ./cmd/web/main.go && ./web; \ + fi diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3e42ac3 --- /dev/null +++ b/Makefile @@ -0,0 +1,220 @@ +## +# Makefile to help manage docker-compose services +# + + # Include environment files + include .env + export + +# Variables +THIS_FILE := $(lastword $(MAKEFILE_LIST)) +DOCKER := $(shell which docker) +DOCKER_COMPOSE := $(shell which docker-compose) + +IMAGE_DEFAULT := web +CONTAINER_DEFAULT := web + +SHELL_CMD := /bin/bash + +# Docker compose files +DOCKER_COMPOSE_FILES := -f docker-compose.yml +ifeq ($(DOCKER_ENV),local) + DOCKER_COMPOSE_FILES := -f docker-compose.yml +endif +ifeq ($(DOCKER_ENV),production) + DOCKER_COMPOSE_FILES := -f docker-compose.yml +endif + +# Services +SERVICES_DEFAULT := bot web +ifeq ($(DOCKER_ENV),local) + SERVICES_DEFAULT := bot web +endif +ifeq ($(DOCKER_ENV),production) + SERVICES_DEFAULT := bot web +endif +SERVICE_DEFAULT := bot + +container ?= $(CONTAINER_DEFAULT) +image ?= $(IMAGE_DEFAULT) +service ?= +services ?= $(SERVICES_DEFAULT) + +.DEFAULT_GOAL := help + + +## +# help +# +help: +ifeq ($(CONTAINER_DEFAULT),) + $(warning WARNING: CONTAINER_DEFAULT is not set. Please edit makefile) +endif + @echo + @echo "Make targets:" + @echo + @cat $(THIS_FILE) | \ + sed -n -E 's/^([^.][^: ]+)\s*:(([^=#]*##\s*(.*[^[:space:]])\s*)|[^=].*)$$/ \1 \4/p' | \ + sort -u | \ + expand -t15 + @echo + @echo + @echo "Target arguments:" + @echo + @echo " " "service" "\t" "Target service for docker-compose actions (default=all-services)" + @echo " " " " "\t" " - make start" + @echo " " " " "\t" " - make start service=app" + @echo " " "services" "\t" "Target services for docker-compose actions (default=all-services, space separated)" + @echo " " " " "\t" " - make stop services='app db'" + @echo " " "container""\t" "Target container for docker actions (default='$(CONTAINER_DEFAULT)')" + @echo " " " " "\t" " - make bash container=$(container)" + @echo " " "image" "\t" "Target image for interactive shell (default='$(IMAGE_DEFAULT)')" + @echo " " " " "\t" " - make it image=$(image)" + + +## +# services +# +services: ## Lists services + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) ps --services + + +## +# start +# +all: dev ## See 'dev' +start: dev ## See 'dev' +dev: ## Start containers for development [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) up -d $(services) + $(MAKE) logs + + +## +# stop +# +stop: ## Stop containers [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) stop $(services) + + +## +# restart +# +restart: ## Restart containers [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) restart $(services) + + +## +# down +# +down: ## Removes containers (preserves images and volumes) + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down + + +## +# build +# +build: ## Builds service images [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) build --build-arg DOCKER_ENV=${DOCKER_ENV} $(services) + + +## +# rebuild +# +rebuild: ## Build containers without cache [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) build --build-arg DOCKER_ENV=${DOCKER_ENV} --no-cache $(services) + + +## +# ps +# +status: ps ## See 'ps' +ps: ## Show status of containers [service|services] + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) ps $(services) + + +## +# interact +# +interact: it ## See `it' +it: ## Run a new container in interactive mode. Needs image name [image] +ifeq ($(image),) + $(error ERROR: 'image' is not set. Please provide 'image=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Starting interactive shell ($(SHELL_CMD)) in image container '$(image)'" + @$(DOCKER) run -it --entrypoint "$(SHELL_CMD)" $(image) + + +## +# bash +# +sh: bash ## See 'bash' +shell: bash ## See 'bash' +bash: ## Brings up a shell in default (or specified) container [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Starting shell ($(SHELL_CMD)) in container '$(container)'" + @$(DOCKER) exec -it "$(container)" "$(SHELL_CMD)" + + +## +# attach +# +at: attach ## See 'attach' +attach: ## Attach to a running container [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Attaching to '$(container)'" + @$(DOCKER) attach $(container) + + +## +# log +# +log: ## Shows log from a specific container (in 'follow' mode) [container] +ifeq ($(container),) + $(error ERROR: 'container' is not set. Please provide 'container=' argument or edit makefile and set CONTAINER_DEFAULT) +endif + @echo + @echo "Log in $(container)" + @$(DOCKER) logs -f $(container) + + +## +# logs +# +logs: ## Shows output of running containers (in 'follow' mode) [service|services] + @echo + @echo "Logs in $(services)" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) logs -f $(services) + + +## +# rmimages +# +rmimages: ## Remove images + @echo + @echo "Remove local images" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down --rmi local + + +## +# clean +# +clean: ## Remove containers, images and volumes + @echo + @echo "Remove containers, images and volumes" + @$(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) down --volumes --rmi all + + + +%: + @: + + +.PHONY: % + diff --git a/README.md b/README.md index fed4cbc..07f4a50 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,46 @@ -# Proyecto HeatingEvent +# Proyecto Heating Monitor -Este proyecto gestiona eventos relacionados con el encendido y apagado de sistemas de calefacción, ofreciendo tres funcionalidades principales: una aplicación web, un bot de Telegram y un comando para importar datos desde un archivo CSV a la base de datos. +Este proyecto gestiona eventos relacionados con el encendido y apagado de sistemas de calefacción, ofreciendo tres funcionalidades principales: + +- Una aplicación web +- Un bot de Telegram +- Un comando para importar datos desde un archivo CSV a la base de datos. + +## Configuración + +1. Crear archivo .env + Copia el archivo .env.sample a .env y configura las variables de entorno necesarias: + +```sh +$ cp .env.sample .env +``` + +Luego edita el archivo .env con los valores correspondientes: + +```ini +# Telegram Bot Configuration +TELEGRAM_TOKEN=xxx:yyy +TELEGRAM_CHATID=123123123 +# Web Server Configuration +WEB_PORT=9900 +``` + +2. Base de Datos + El proyecto utiliza una base de datos `SQLite` para almacenar los eventos de calefacción. La configuración de la base de datos se gestiona automáticamente a través del código en el archivo `internal/config/db.go`. Asegúrate de que el archivo de la base de datos se encuentra en la ubicación correcta para que la conexión funcione correctamente. + +## Docker + +Este proyecto puede ejecutarse fácilmente con Docker. Se han configurado dos entornos: `local` y `production`. En el entorno `local`, se utiliza `Air` para recargar automáticamente el código durante el desarrollo, mientras que en `production` se compila el binario y se ejecuta directamente. Asegúrate de tener Docker y Docker compose instalados en tu sistema. + +El `Makefile` ha sido configurado para facilitar la construcción y ejecución de Docker con el argumento `--build-arg`, que pasará la variable de entorno `DOCKER_ENV` para que determine el mismo. Dicha variable se lee del archivo `.env`: + +`--build-arg DOCKER_ENV=${DOCKER_ENV}`: Utiliza esta variable para determinar el entorno de ejecución (`local` o `production`), lo que afecta tanto la construcción de los binarios como el comportamiento del contenedor. + +```sh +$ make build +$ make rebuild +$ make start +``` ## Comandos disponibles @@ -9,6 +49,7 @@ Este proyecto gestiona eventos relacionados con el encendido y apagado de sistem Este comando inicia un servidor web que permite visualizar los eventos de calefacción a través de una interfaz web. #### Uso: + ```bash $ go run cmd/web/main.go ``` @@ -18,9 +59,11 @@ $ go run cmd/web/main.go - WEB_PORT: Puerto en el que se ejecuta el servidor web. Puedes configurarlo en el archivo `.env`. ### 2. Comando Bot + Este comando inicia un bot de Telegram que permite interactuar con el sistema de calefacción a través de mensajes. #### Uso: + ```sh $ go run cmd/bot/main.go ``` @@ -35,6 +78,7 @@ $ go run cmd/bot/main.go Este comando importa los datos de un archivo CSV (con formato específico) a la base de datos SQLite, creando eventos de encendido y apagado en función de la información proporcionada en el archivo. #### Uso: + ``` $ go run cmd/import/main.go -f /ruta/al/archivo.csv -f, --file: Especifica la ruta del archivo CSV a importar. @@ -42,26 +86,7 @@ $ go run cmd/import/main.go -f /ruta/al/archivo.csv (útil para verificar la información antes de insertarla). ``` -#### Configuración - -1. Crear archivo .env -Copia el archivo .env.sample a .env y configura las variables de entorno necesarias: -```sh -$ cp .env.sample .env -``` -Luego edita el archivo .env con los valores correspondientes: -```ini -# Telegram Bot Configuration -TELEGRAM_TOKEN=xxx:yyy -TELEGRAM_CHATID=123123123 -# Web Server Configuration -WEB_PORT=9900 -``` - -2. Base de Datos -El proyecto utiliza una base de datos SQLite para almacenar los eventos de calefacción. La configuración de la base de datos se gestiona automáticamente a través del código en el archivo `internal/config/db.go`. Asegúrate de que el archivo de la base de datos se encuentra en la ubicación correcta para que la conexión funcione correctamente. - -### Dependencias +## Dependencias Este proyecto utiliza varias dependencias de Go. Asegúrate de tenerlas instaladas y configuradas correctamente: @@ -69,7 +94,7 @@ Este proyecto utiliza varias dependencias de Go. Asegúrate de tenerlas instalad $ go mod tidy ``` -### Estructura del Proyecto +## Estructura del Proyecto ```sh . @@ -84,7 +109,7 @@ $ go mod tidy └── README.md # Este archivo ``` -### Contribución +## Contribución Si deseas contribuir a este proyecto, por favor sigue estos pasos: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..508499f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +name: "heating-monitor" +version: "3.8" + +services: + bot: + container_name: bot + hostname: bot + env_file: + - ./.env + build: + context: . + dockerfile: Dockerfile.bot + volumes: + - ./:/code/ + stdin_open: true + tty: true + restart: always + + web: + container_name: web + hostname: web + env_file: + - ./.env + build: + context: . + dockerfile: Dockerfile.web + volumes: + - ./:/code/ + stdin_open: true + tty: true + ports: + - ${WEB_PORT}:${WEB_PORT} + restart: always diff --git a/env.sample b/env.sample index 5dcf6a3..0328bd1 100644 --- a/env.sample +++ b/env.sample @@ -1,10 +1,13 @@ +# Docker +DOCKER_ENV=local +PROJECT_NAME=heating-monitor + # Telegram TELEGRAM_TOKEN=aaaa:bbbb TELEGRAM_CHATID=123123 # Web WEB_PORT=9900 - PROGRAM_AUTHOR="oscarmlage" PROGRAM_LINK="https://oscarmlage.com" PROGRAM_AVATAR="https://mastodon.bofhers.es/system/accounts/avatars/108/369/580/175/949/602/original/01f8e5e7fcc34119.jpg"