code_runner/cmd/service_agent/s_agent.go

223 lines
5.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"code_runner/config"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"github.com/google/uuid"
"github.com/streadway/amqp"
)
// State - раннер может находится в нескольких состояниях в зависимости
// от исполняемого языка программирования.
// State - интерфейс состояния
type State interface {
Handle(context *Context)
}
// ConcretStatePy - конкретное состояние A
type ConcretStatePy struct{}
func (a *ConcretStatePy) Handle(context *Context) {
fmt.Println("ConcretStatePy: Обработка запроса и изменение состояния на ConcretStateGo")
context.SetState(&ConcretStateGo{})
}
// ConcretStateGo - конкретное состояние B
type ConcretStateGo struct{}
func (b *ConcretStateGo) Handle(context *Context) {
fmt.Println("ConcretStateGo: Обработка запроса и изменение состояния на ConcretStatePy")
context.SetState(&ConcretStatePy{})
}
// Context - контекст, который хранит текущее состояние
type Context struct {
state State
}
// NewContext - конструктор для Context
func NewContext() *Context {
return &Context{
state: &ConcretStatePy{}, // Начальное состояние
}
}
// SetState - устанавливает новое состояние
func (c *Context) SetState(state State) {
c.state = state
}
// Request - выполняет запрос, делегируя его текущему состоянию
func (c *Context) Request() {
fmt.Println("Context: Запрос")
c.state.Handle(c)
}
func main() {
amqpServerURL := config.AmqpServerURL
// os.Getenv("AMQP_SERVER_URL")
fmt.Print(amqpServerURL)
if amqpServerURL == "" {
panic("Дискриптор для RabbitMQ не указан!")
}
connectRabbitMQ, err := amqp.Dial(amqpServerURL)
if err != nil {
panic(err)
}
defer connectRabbitMQ.Close()
channelRabbitMQ, err := connectRabbitMQ.Channel()
if err != nil {
panic(err)
}
defer channelRabbitMQ.Close()
_, err = channelRabbitMQ.QueueDeclare(
config.TaskQueueCallbackName,
true,
false,
false,
false,
nil,
)
if err != nil {
panic(err)
}
messages, err := channelRabbitMQ.Consume(
config.TaskQueueName,
"",
true,
false,
false,
false,
nil,
)
if err != nil {
log.Println(err)
}
log.Println("Successfully connected to RabbitMQ")
log.Println("Waiting for messages")
forever := make(chan bool)
go func() {
for message := range messages {
var codeObj config.MessageCode
err := json.Unmarshal([]byte(message.Body), &codeObj)
if err != nil {
log.Printf("Error unmarshaling message: %v", err)
continue
}
log.Print(codeObj)
//todo: в зависимости от типа tp_lang вызываем Runner.
// context := NewContext()
uid := uuid.New()
fileName := uid.String() + ".py"
dirName := "code"
// Создаем директорию, если её нет
if err := os.MkdirAll(dirName, 0755); err != nil {
log.Printf("Error creating directory: %v", err)
continue
}
if err := makeFile(dirName, fileName, codeObj.Code); err != nil {
// if err := makeFile(dirName, fileName, codeObj.Unit_test); err != nil {
log.Printf("Error creating file: %v", err)
continue
}
success, runMessage := runCode(dirName, fileName)
// Удаляем файл в любом случае
if err := deleteFile(dirName, fileName); err != nil {
log.Printf("Error deleting file: %v", err)
}
response := config.SuccessResponse{
Success: success,
Message: runMessage,
Queue: config.TaskQueueCallbackName,
}
jsonBody, err := json.Marshal(response)
if err != nil {
log.Printf("Error marshaling response: %v", err)
continue
}
err = channelRabbitMQ.Publish(
"",
config.TaskQueueCallbackName,
false,
false,
amqp.Publishing{
ContentType: "application/json",
Body: jsonBody,
},
)
if err != nil {
log.Printf("Error publishing message: %v", err)
}
}
}()
<-forever
}
func makeFile(dirName string, fileName string, base64String string) error {
decodedBytes, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
return fmt.Errorf("base64 decode error: %v", err)
}
fullPath := filepath.Join(dirName, fileName)
err = os.WriteFile(fullPath, decodedBytes, 0644)
if err != nil {
return fmt.Errorf("write file error: %v", err)
}
return nil
}
func deleteFile(dirName string, fileName string) error {
fullPath := filepath.Join(dirName, fileName)
err := os.Remove(fullPath)
if err != nil {
return fmt.Errorf("remove file error: %v", err)
}
return nil
}
func runCode(dirName string, fileName string) (bool, string) {
fullPath := filepath.Join(dirName, fileName)
// cmd := exec.Command("python", "-m", "unittest", fullPath)
cmd := exec.Command("python3", fullPath)
output, err := cmd.CombinedOutput()
if err != nil {
return false, fmt.Sprintf("%s\nError: %v", output, err)
}
return true, string(output)
}