diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/cmd/main.go | 35 | ||||
| -rw-r--r-- | app/internal/create_bot.go | 90 | 
2 files changed, 69 insertions, 56 deletions
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  }  | 
