summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoler_j <soler_j@etna-alternance.net>2025-04-29 04:32:29 +0200
committersoler_j <soler_j@etna-alternance.net>2025-04-29 04:32:29 +0200
commitc50017aebd44fa692438514514bccada2f309115 (patch)
treeb15a570fb377683259c6c7449880608953190448
parent6ccd5f23c68bf6d8eb212e4c0cb3b887fff993a8 (diff)
Refactor bot initialization and ZeroMQ integration: remove unused dealer socket, pass unique port to bot, and enhance message handling.
-rw-r--r--.gitignore1
-rw-r--r--app/cmd/main.go35
-rw-r--r--app/internal/create_bot.go90
-rw-r--r--bot/src/main.cpp9
4 files changed, 76 insertions, 59 deletions
diff --git a/.gitignore b/.gitignore
index ce2a59d..e123953 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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);