diff options
| author | soler_j <soler_j@etna-alternance.net> | 2025-04-29 03:57:44 +0200 |
|---|---|---|
| committer | soler_j <soler_j@etna-alternance.net> | 2025-04-29 03:57:44 +0200 |
| commit | 6ccd5f23c68bf6d8eb212e4c0cb3b887fff993a8 (patch) | |
| tree | 04ce0804bb914764751c5c5fc278282267368760 | |
| parent | e3a3437f65b4470b8042a37ccd48f399b250a77b (diff) | |
Implement multiple code changes for optimization and refactoring
| -rw-r--r-- | Dockerfile | 19 | ||||
| -rw-r--r-- | app/cmd/main.go | 132 | ||||
| -rwxr-xr-x | app/discord-bot | bin | 0 -> 425120 bytes | |||
| -rw-r--r-- | app/internal/create_bot.go | 53 | ||||
| -rw-r--r-- | devenv.nix | 2 |
5 files changed, 134 insertions, 72 deletions
@@ -55,17 +55,24 @@ FROM ubuntu:24.04 WORKDIR /app # Install runtime deps -RUN apt-get update && apt-get install -y libssl3 zlib1g libopus0 && apt-get clean - +RUN apt-get update && apt-get install -y \ + libssl3 \ + zlib1g \ + libopus0 \ + libsodium23 \ + libzmq5 \ + && apt-get clean # Copie des binaires -COPY --from=go-builder /api ./api -COPY --from=cpp-builder /src/build/discord-bot ./bot/build/discord-bot +COPY --from=go-builder /api/app ./app +COPY --from=cpp-builder /src/build/discord-bot ./discord-bot COPY --from=cpp-builder /usr/local/lib/ /usr/local/lib/ # Make sure executables are runnable -RUN chmod +x ./api/app ./bot/build/discord-bot +RUN chmod +x ./app ./discord-bot # Pour être sûr que libdpp.so soit trouvée ENV LD_LIBRARY_PATH=/usr/local/lib -ENTRYPOINT ["./api/app"] +EXPOSE 2030 + +ENTRYPOINT ["./app"] diff --git a/app/cmd/main.go b/app/cmd/main.go index 87212ef..7d8ffa0 100644 --- a/app/cmd/main.go +++ b/app/cmd/main.go @@ -12,25 +12,30 @@ import ( zmq "github.com/pebbe/zmq4" ) +var botList = make(map[string]*internal.Bot) + func init() { - // Initialize the application + // Initialisation de l'application } func main() { + // Créer un ServeMux mux := http.NewServeMux() - // Start the application - mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { + + // Route principale + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, World!")) }) - botToken := "XXXXXXXXXXXX" // Replace with your bot token + // 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) @@ -42,58 +47,97 @@ func main() { log.Fatalf("[SERVER] Failed to bind dealer: %v", err) } - bot := &internal.Bot{ - BotToken: botToken, - } + // 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") - bot, err = internal.Start(bot, dealer) - if err != nil { - log.Fatalf("[SERVER] Error starting bot: %v", err) - } - // Handle the bot connection - data, err := json.Marshal(map[string]interface{}{ - "command": "update", - "data": map[string]interface{}{ - "ping": map[string]string{ - "response": "pong ((userName))", - }, - }, + bot := &internal.Bot{ + BotToken: botToken, + } + bot, err := internal.Start(bot, dealer) + if err != nil { + log.Printf("[SERVER] Error starting bot: %v", err) + http.Error(w, "Error starting bot", http.StatusInternalServerError) + return + } + botList[botToken] = bot + log.Printf("[SERVER] Bot started successfully") + w.WriteHeader(http.StatusOK) + w.Write([]byte("Bot started successfully")) }) - if err != nil { - log.Fatalf("[SERVER] Error marshaling JSON: %v", err) - } - go bot.SendMessage(string(data)) - - dataX, err := json.Marshal(map[string]interface{}{ - "command": "update", - "data": map[string]interface{}{ - "ping": map[string]string{ - "response": "pong ((userName)) avec une modif !", - }, - }, + + // 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") + + bot, ok := botList[botToken] + if !ok { + http.Error(w, "Bot not found", http.StatusNotFound) + return + } + if err := bot.Stop(); err != nil { + log.Printf("[SERVER] Error stopping bot: %v", err) + http.Error(w, "Error stopping bot", http.StatusInternalServerError) + return + } + delete(botList, botToken) + log.Printf("[SERVER] Bot stopped successfully") + w.WriteHeader(http.StatusOK) + w.Write([]byte("Bot stopped successfully")) }) - if err != nil { - log.Fatalf("[SERVER] Error marshaling JSON: %v", err) - } - go bot.SendMessage(string(dataX)) - // Handle if signal is received + // 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") + bot, ok := botList[botToken] + if !ok { + http.Error(w, "Bot not found", http.StatusNotFound) + return + } + body := make(map[string]interface{}) + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + log.Printf("[SERVER] Error decoding JSON: %v", err) + http.Error(w, "Invalid JSON", http.StatusBadRequest) + return + } + data, err := json.Marshal(body) + if err != nil { + log.Printf("[SERVER] Error marshaling JSON: %v", err) + http.Error(w, "Error marshaling JSON", http.StatusInternalServerError) + return + } + if err := bot.SendMessage(string(data)); err != nil { + log.Printf("[SERVER] Error sending message: %v", err) + http.Error(w, "Error sending message", http.StatusInternalServerError) + return + } + log.Printf("[SERVER] Bot updated successfully") + w.WriteHeader(http.StatusOK) + w.Write([]byte("Bot updated successfully")) + }) + + // Gestion des signaux pour l'arrêt propre signals := make(chan os.Signal, 1) signal.Notify(signals, os.Interrupt) signal.Notify(signals, syscall.SIGTERM) go func() { sig := <-signals log.Printf("Received signal: %s", sig) - // let's kill the bot - if bot.Cmd != nil { - if err := bot.Cmd.Process.Kill(); err != nil { - log.Printf("[SERVER] Error killing bot process: %v", err) - } else { - log.Printf("[SERVER] Bot process killed successfully") + // Arrêter tous les bots en cours + for _, bot := range botList { + if err := bot.Stop(); err != nil { + log.Printf("[SERVER] Error stopping bot: %v", err) } + delete(botList, bot.BotToken) } - // let's remove the socket + // Quitter l'application os.Exit(0) }() - panic(http.ListenAndServe(":2030", mux)) + + // Démarrer le serveur HTTP + log.Printf("[SERVER] Starting server on :2030") + log.Fatal(http.ListenAndServe(":2030", mux)) } diff --git a/app/discord-bot b/app/discord-bot Binary files differnew file mode 100755 index 0000000..61a01e1 --- /dev/null +++ b/app/discord-bot diff --git a/app/internal/create_bot.go b/app/internal/create_bot.go index 4bbe5ae..0f47818 100644 --- a/app/internal/create_bot.go +++ b/app/internal/create_bot.go @@ -16,12 +16,13 @@ type Bot struct { processID int 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) { // Configuration du bot - cmd := exec.Command("../bot/build/discord-bot", b.BotToken) + cmd := exec.Command("./discord-bot", b.BotToken) cmd.SysProcAttr = &syscall.SysProcAttr{ Setpgid: true, // Permet de kill le processus enfant si nécessaire } @@ -36,18 +37,27 @@ func Start(b *Bot, dealer *zmq.Socket) (*Bot, error) { b.Cmd = cmd b.processID = cmd.Process.Pid b.dealer = dealer - // 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 + 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 + } } - } + }() + return b, nil } @@ -56,6 +66,7 @@ func (b *Bot) Stop() error { if err := syscall.Kill(-b.processID, syscall.SIGTERM); err != nil { return fmt.Errorf("[SERVER] failed to stop bot: %w", err) } + log.Printf("[SERVER] Bot %s stopped successfully", b.BotToken) } return nil } @@ -64,22 +75,20 @@ func (b *Bot) SendMessage(message string) error { if b.dealer == nil { return fmt.Errorf("[SERVER] sender socket is not initialized") } + + // Attendre que le bot soit prêt si ce n'est pas déjà fait if !b.read { - // Let's read the message before sending - msg, err := b.dealer.Recv(0) - if err != nil { - return fmt.Errorf("[SERVER] failed to receive message: %w", err) - } - log.Printf("[SERVER] received message: %s", msg) - b.read = true // Fix ici ! + log.Printf("[SERVER] Waiting for bot %s to be ready...", b.BotToken) + <-b.readyChan // Attendre que le bot soit prêt } + // Envoi du message _, err := b.dealer.Send(message, 0) if err != nil { - return fmt.Errorf("[SERVER] failed to send message: %w", err) + return fmt.Errorf("[SERVER] failed to send message to bot %s: %w", b.BotToken, err) } - log.Printf("[SERVER] sent message: %s", message) + log.Printf("[SERVER] Sent message to bot %s: %s", b.BotToken, message) - b.read = false + b.read = false // Réinitialiser l'état de lecture après l'envoi return nil } @@ -48,6 +48,8 @@ ''; scripts.start.exec = '' + build + mv bot/build/discord-bot ./app cd app go run cmd/main.go ''; |
