diff options
| author | soler_j <soler_j@etna-alternance.net> | 2025-04-29 04:32:29 +0200 |
|---|---|---|
| committer | soler_j <soler_j@etna-alternance.net> | 2025-04-29 04:32:29 +0200 |
| commit | c50017aebd44fa692438514514bccada2f309115 (patch) | |
| tree | b15a570fb377683259c6c7449880608953190448 | |
| parent | 6ccd5f23c68bf6d8eb212e4c0cb3b887fff993a8 (diff) | |
Refactor bot initialization and ZeroMQ integration: remove unused dealer socket, pass unique port to bot, and enhance message handling.
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | app/cmd/main.go | 35 | ||||
| -rw-r--r-- | app/internal/create_bot.go | 90 | ||||
| -rw-r--r-- | bot/src/main.cpp | 9 |
4 files changed, 76 insertions, 59 deletions
@@ -40,3 +40,4 @@ devenv.local.nix # pre-commit .pre-commit-config.yaml build +discord-bot diff --git a/app/cmd/main.go b/app/cmd/main.go index 7d8ffa0..49e645f 100644 --- a/app/cmd/main.go +++ b/app/cmd/main.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "fmt" "log" "net/http" "os" @@ -9,7 +10,6 @@ import ( "syscall" "github.com/ketsuna-org/bot-creator-api/internal" - zmq "github.com/pebbe/zmq4" ) var botList = make(map[string]*internal.Bot) @@ -28,34 +28,19 @@ func main() { w.Write([]byte("Hello, World!")) }) - // Contexte ZeroMQ - ctx, err := zmq.NewContext() - if err != nil { - log.Fatalf("[SERVER] Failed to create context: %v", err) - } - defer ctx.Term() - - // Socket dealer ZeroMQ - dealer, err := ctx.NewSocket(zmq.REP) - if err != nil { - log.Fatalf("[SERVER] Failed to create dealer: %v", err) - } - defer dealer.Close() - - err = dealer.Bind("tcp://*:5555") - if err != nil { - log.Fatalf("[SERVER] Failed to bind dealer: %v", err) - } - // Route POST /create/{bot_token} mux.HandleFunc("POST /create/{bot_token}", func(w http.ResponseWriter, r *http.Request) { // Extraire le token du bot de l'URL - botToken := r.URL.Query().Get("bot_token") + botToken := r.PathValue("bot_token") + + // we need to retrieve the amount of bots running bot := &internal.Bot{ - BotToken: botToken, + BotToken: botToken, + ProcessID: fmt.Sprint(len(botList) + 5555), // or any unique identifier } - bot, err := internal.Start(bot, dealer) + + bot, err := internal.Start(bot) if err != nil { log.Printf("[SERVER] Error starting bot: %v", err) http.Error(w, "Error starting bot", http.StatusInternalServerError) @@ -70,7 +55,7 @@ func main() { // Route POST /stop/{bot_token} mux.HandleFunc("POST /stop/{bot_token}", func(w http.ResponseWriter, r *http.Request) { // Extraire le token du bot de l'URL - botToken := r.URL.Query().Get("bot_token") + botToken := r.PathValue("bot_token") bot, ok := botList[botToken] if !ok { @@ -91,7 +76,7 @@ func main() { // Route POST /update/{bot_token} mux.HandleFunc("POST /update/{bot_token}", func(w http.ResponseWriter, r *http.Request) { // Extraire le token du bot de l'URL - botToken := r.URL.Query().Get("bot_token") + botToken := r.PathValue("bot_token") bot, ok := botList[botToken] if !ok { http.Error(w, "Bot not found", http.StatusNotFound) diff --git a/app/internal/create_bot.go b/app/internal/create_bot.go index 0f47818..667ac0a 100644 --- a/app/internal/create_bot.go +++ b/app/internal/create_bot.go @@ -13,18 +13,39 @@ import ( type Bot struct { BotToken string `json:"bot_token"` Cmd *exec.Cmd // Ajouter une référence à la commande - processID int + ProcessID string dealer *zmq.Socket // Stocker le PGID (Process Group ID) read bool readyChan chan bool // Canal pour indiquer que le bot est prêt } -func Start(b *Bot, dealer *zmq.Socket) (*Bot, error) { +func Start(b *Bot) (*Bot, error) { + if b.readyChan == nil { + b.readyChan = make(chan bool) + } + + // Create a new ZeroMQ socket specifically for this bot + ctx, err := zmq.NewContext() + if err != nil { + return nil, fmt.Errorf("[SERVER] failed to create context: %w", err) + } + + // Each bot gets its own dealer socket + dealer, err := ctx.NewSocket(zmq.REP) + if err != nil { + return nil, fmt.Errorf("[SERVER] failed to create dealer: %w", err) + } + + // Binding the socket to a specific address (may need to adjust the address based on your needs) + err = dealer.Bind(fmt.Sprintf("tcp://localhost:%s", b.ProcessID)) + if err != nil { + return nil, fmt.Errorf("[SERVER] failed to bind dealer: %w", err) + } // Configuration du bot - cmd := exec.Command("./discord-bot", b.BotToken) + cmd := exec.Command("./discord-bot", b.BotToken, b.ProcessID) // Passer le port unique cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, // Permet de kill le processus enfant si nécessaire + Setpgid: true, // Permet de tuer le processus enfant si nécessaire } // Redirection des sorties pour le débogage @@ -35,35 +56,26 @@ func Start(b *Bot, dealer *zmq.Socket) (*Bot, error) { return nil, fmt.Errorf("failed to start bot: %w", err) } b.Cmd = cmd - b.processID = cmd.Process.Pid b.dealer = dealer - b.readyChan = make(chan bool) - - // Goroutine pour écouter les messages du bot - go func() { - // Boucle de réception des messages du bot via ZeroMQ - for { - msg, err := dealer.Recv(0) - if err != nil { - log.Printf("[SERVER] Failed to receive message from bot %s: %v", b.BotToken, err) - continue // Continue à recevoir les messages même si une erreur se produit - } - - if msg == "ready" { - log.Printf("[SERVER] Bot %s is ready", b.BotToken) - b.read = true - b.readyChan <- true // Indiquer que le bot est prêt - break - } - } - }() + // Here we will receive messages from the bot in a separate goroutine + for { + msg, err := dealer.Recv(0) + if err != nil { + return nil, fmt.Errorf("[SERVER] failed to receive message: %w", err) + } + if msg == "ready" { + log.Printf("[SERVER] Bot is ready") + b.read = true + break + } + } return b, nil } func (b *Bot) Stop() error { - if b.Cmd != nil && b.processID != 0 { - if err := syscall.Kill(-b.processID, syscall.SIGTERM); err != nil { + if b.Cmd != nil && b.Cmd.Process.Pid != 0 { + if err := syscall.Kill(-b.Cmd.Process.Pid, syscall.SIGTERM); err != nil { return fmt.Errorf("[SERVER] failed to stop bot: %w", err) } log.Printf("[SERVER] Bot %s stopped successfully", b.BotToken) @@ -76,19 +88,35 @@ func (b *Bot) SendMessage(message string) error { return fmt.Errorf("[SERVER] sender socket is not initialized") } - // Attendre que le bot soit prêt si ce n'est pas déjà fait + // Wait for the bot to be ready if it's not already if !b.read { log.Printf("[SERVER] Waiting for bot %s to be ready...", b.BotToken) - <-b.readyChan // Attendre que le bot soit prêt + // this mean we should read the recv channel + msg, err := b.dealer.Recv(0) + if err != nil { + return fmt.Errorf("[SERVER] failed to receive message: %w", err) + } + log.Printf("[SERVER] Received message from bot %s: %s", b.BotToken, msg) + b.read = true + } + + // Check if the bot process is still running + if err := b.Cmd.Process.Signal(syscall.Signal(0)); err != nil { + return fmt.Errorf("[SERVER] bot process is not running: %w", err) + } + + // Check if the message is empty + if message == "" { + return fmt.Errorf("[SERVER] message is empty") } - // Envoi du message + // Send the message _, err := b.dealer.Send(message, 0) if err != nil { return fmt.Errorf("[SERVER] failed to send message to bot %s: %w", b.BotToken, err) } log.Printf("[SERVER] Sent message to bot %s: %s", b.BotToken, message) - b.read = false // Réinitialiser l'état de lecture après l'envoi + b.read = false // Reset read state after sending the message return nil } diff --git a/bot/src/main.cpp b/bot/src/main.cpp index 853e829..ccb3cba 100644 --- a/bot/src/main.cpp +++ b/bot/src/main.cpp @@ -7,10 +7,13 @@ int main(int argc, char *argv[]) { if (argc > 1) { std::string token = argv[1]; + std::string port = argv[2]; setenv("BOT_TOKEN", token.c_str(), 1); + setenv("PORT", port.c_str(), 1); } const std::string BOT_TOKEN = getenv("BOT_TOKEN"); + const std::string PORT = getenv("PORT"); dpp::cluster bot(BOT_TOKEN); std::unique_ptr<nlohmann::json> json_data = std::make_unique<nlohmann::json>(); @@ -36,13 +39,13 @@ int main(int argc, char *argv[]) { event.reply(app::update_string(response, key_values)); }); - bot.on_ready([&bot, &json_data](const dpp::ready_t &event) { + bot.on_ready([&bot, &json_data, &PORT](const dpp::ready_t &event) { if (dpp::run_once<struct register_bot_commands>()) { // Lancer la boucle ZMQ dans un thread séparé - std::thread zmq_thread([&json_data]() { + std::thread zmq_thread([&json_data, &PORT]() { zmq::context_t ctx; zmq::socket_t responder(ctx, zmq::socket_type::req); - responder.connect("tcp://localhost:5555"); + responder.connect("tcp://localhost:" + PORT); zmq::message_t ready_msg(5); memcpy(ready_msg.data(), "ready", 5); responder.send(ready_msg, zmq::send_flags::none); |
