300 lines
6.7 KiB
Go
300 lines
6.7 KiB
Go
package repositories
|
|
|
|
import (
|
|
"backend/models"
|
|
"bytes"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/lib/pq"
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
type NodeRepository struct {
|
|
DB *sqlx.DB
|
|
}
|
|
|
|
func (r *NodeRepository) UpdateNodeLastSeen(nodeId string) error {
|
|
query, _ := os.ReadFile("sql/update_service_status.sql")
|
|
_, err := r.DB.Exec(string(query), nodeId, time.Now().UTC())
|
|
return err
|
|
}
|
|
|
|
func (r *NodeRepository) UpdateServiceStatus(serviceUpdate models.ServiceUpdateRequest) error {
|
|
query, _ := os.ReadFile("sql/update_service_status.sql")
|
|
var (
|
|
serviceIds []int
|
|
statuses []int
|
|
timestamps []time.Time
|
|
)
|
|
|
|
for _, s := range serviceUpdate.Services {
|
|
serviceIds = append(serviceIds, s.ServiceId)
|
|
statuses = append(statuses, int(s.Status.Status))
|
|
timestamps = append(timestamps, s.Status.Timestamp)
|
|
}
|
|
|
|
_, err := r.DB.Exec(string(query), pq.Array(serviceIds), pq.Array(statuses), pq.Array(timestamps))
|
|
return err
|
|
}
|
|
|
|
func (r *NodeRepository) RegisterNode(node models.NodeInfo) (int, error) {
|
|
|
|
log.Printf("Register node id %v, name %v, address %v", node.Id, node.Name, node.Address)
|
|
|
|
query, err := os.ReadFile("sql/register_node.sql")
|
|
if err != nil {
|
|
log.Printf("❌ Erreur de lecture SQL: %v", err)
|
|
return 0, err
|
|
}
|
|
|
|
var id int
|
|
err = r.DB.QueryRow(string(query), node.Name, node.Address, 0, node.Id).Scan(&id)
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return node.Id, nil
|
|
}
|
|
return 0, err
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func (r *NodeRepository) RegisterService(service models.Service, nodeId int) (int, error) {
|
|
|
|
log.Printf("Register service id %v, name %v, nodeId %v with command %v", service.Id, service.Name, nodeId, service.Command)
|
|
|
|
query, err := os.ReadFile("sql/register_service.sql")
|
|
if err != nil {
|
|
log.Printf("❌ Erreur de lecture SQL: %v", err)
|
|
return 0, err
|
|
}
|
|
|
|
var id int
|
|
err = r.DB.QueryRow(string(query), nodeId, service.Name, 0, service.Command, service.Id).Scan(&id)
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return service.Id, nil
|
|
}
|
|
return 0, err
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func (r *NodeRepository) RetriveNodeList() (map[string]models.FullNodeInfo, error) {
|
|
query, err := os.ReadFile("sql/retrieve_node_list.sql")
|
|
|
|
rows, err := r.DB.Query(string(query))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var nodes = make(map[string]models.FullNodeInfo)
|
|
|
|
for rows.Next() {
|
|
log.Printf("new node")
|
|
|
|
var node models.FullNodeInfo
|
|
var servicesData []byte
|
|
|
|
err := rows.Scan(
|
|
&node.Id,
|
|
&node.Name,
|
|
&node.Address,
|
|
&node.Status,
|
|
&node.LastSeen,
|
|
&servicesData,
|
|
)
|
|
if err != nil {
|
|
log.Printf("error on request")
|
|
return nil, err
|
|
}
|
|
|
|
if err := json.Unmarshal(servicesData, &node.Services); err != nil {
|
|
return nil, fmt.Errorf("error decoding services for node %d: %v", node.Id, err)
|
|
}
|
|
|
|
nodes[node.Name] = node
|
|
}
|
|
|
|
return nodes, nil
|
|
}
|
|
|
|
func deleteServiceFromNode(node *models.NodeInfo, serviceId int) error {
|
|
|
|
apiURL := node.Address + "/services"
|
|
|
|
bodyData := map[string]int{
|
|
"service_id": serviceId,
|
|
}
|
|
|
|
jsonData, err := json.Marshal(bodyData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodDelete, apiURL, bytes.NewBuffer(jsonData))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Erreur lors de la création de la requête DELETE : %v", err)
|
|
}
|
|
|
|
client := http.Client{
|
|
Timeout: 10 * time.Second,
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Erreur lors de l'exécution de la requête DELETE : %v", err)
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("Requête DELETE échouée pour %s. Statut : %s", apiURL, resp.Status)
|
|
}
|
|
|
|
log.Printf("Service %d supprimé avec succès. Réponse : %s", serviceId, resp.Status)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *NodeRepository) DeleteService(node models.NodeInfo, serviceId int) error {
|
|
|
|
tx, err := r.DB.Begin()
|
|
|
|
log.Printf("Delete service id %v, on nodeId %v", serviceId, node.Id)
|
|
|
|
query, err := os.ReadFile("sql/delete_service.sql")
|
|
if err != nil {
|
|
log.Printf("❌ Erreur de lecture SQL: %v", err)
|
|
return err
|
|
}
|
|
|
|
_, err = tx.Exec(string(query), node.Id, serviceId)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
|
|
err = deleteServiceFromNode(&node, serviceId)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("échec sur le node, annulation du changement en base de données : %w", err)
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (r *NodeRepository) RetriveNode(nodeId int) (models.NodeInfo, error) {
|
|
|
|
query := "SELECT * FROM nodes WHERE id = $1"
|
|
|
|
var node models.SimpleNodeInfo
|
|
|
|
err := r.DB.Get(&node, query, nodeId)
|
|
|
|
if err != nil {
|
|
return models.NodeInfo{}, err
|
|
}
|
|
|
|
var result models.NodeInfo
|
|
|
|
result.Address = node.Address
|
|
result.Id = node.Id
|
|
result.LastSeen = node.LastSeen.String()
|
|
result.Name = node.Name
|
|
result.Status = node.Status
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (r *NodeRepository) RetriveApiKeyList() ([]models.ApiKey, error) {
|
|
|
|
query := "SELECT id, key_name, key_value FROM node_api_keys"
|
|
|
|
apiKeys := make([]models.ApiKey, 0)
|
|
|
|
err := r.DB.Select(&apiKeys, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return apiKeys, nil
|
|
}
|
|
|
|
func addServiceToNode(node *models.NodeInfo, service *models.Service, nodeApiKey string) error {
|
|
|
|
apiURL := node.Address + "/add"
|
|
|
|
bodyData := map[string]string{
|
|
"name": service.Name,
|
|
"command": service.Command,
|
|
}
|
|
|
|
jsonData, err := json.Marshal(bodyData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("Node api key: %v", nodeApiKey)
|
|
|
|
req, err := http.NewRequest(http.MethodPost, apiURL, bytes.NewBuffer(jsonData))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Node-API-Key", nodeApiKey)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Erreur lors de la création de la requête POST : %v", err)
|
|
}
|
|
|
|
client := http.Client{
|
|
Timeout: 10 * time.Second,
|
|
}
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Erreur lors de l'exécution de la requête POST : %v", err)
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("Requête POST échouée pour %s. Statut : %s", apiURL, resp.Status)
|
|
}
|
|
|
|
log.Printf("Service %v ajouté avec succès. Réponse : %s", service.Name, resp.Status)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *NodeRepository) AddServiceToNode(service *models.Service, node *models.NodeInfo, nodeApiKey string) error {
|
|
|
|
//tx, err := r.DB.Begin()
|
|
|
|
//r.RegisterService(*service, node.Id)
|
|
|
|
log.Printf("add service name %v, on nodeId %v", service.Name, node.Id)
|
|
|
|
err := addServiceToNode(node, service, nodeApiKey)
|
|
if err != nil {
|
|
//tx.Rollback()
|
|
return fmt.Errorf("échec sur le node, annulation du changement en base de données : %w", err)
|
|
}
|
|
|
|
//return tx.Commit()
|
|
return err
|
|
}
|