new: microservice

This commit is contained in:
vitaliy 2025-06-18 00:00:08 +03:00
parent efa0c3aea2
commit 1001bb813a
5 changed files with 347 additions and 7 deletions

View File

@ -0,0 +1,15 @@
{
"id_task": "01975b05-647e-7ed5-abdd-f412a8a4882b",
"tp_runner": "python",
"code": "CmRlZiBoZWxsb193b3JsZCgpOgogICAgcHJpbnQoIkhlbGxvLCBXb3JsZCEiKQogICAg",
"test": "CmltcG9ydCB1bml0dGVzdAppbXBvcnQgaW8KaW1wb3J0IHN5cwpmcm9tIGNvbnRleHRsaWIgaW1wb3J0IHJlZGlyZWN0X3N0ZG91dApmcm9tIG1haW4gaW1wb3J0IGhlbGxvX3dvcmxkCgpjbGFzcyBUZXN0SGVsbG9Xb3JsZCh1bml0dGVzdC5UZXN0Q2FzZSk6CgogICAgZGVmIHRlc3RfaGVsbG9fd29ybGRfb3V0cHV0KHNlbGYpOgogICAgICAgICIiIgogICAgICAgIFRlc3QgdGhhdCBoZWxsb193b3JsZCgpIHByaW50cyAiSGVsbG8sIFdvcmxkISIgdG8gc3Rkb3V0LgogICAgICAgICIiIgogICAgICAgIGYgPSBpby5TdHJpbmdJTygpCiAgICAgICAgd2l0aCByZWRpcmVjdF9zdGRvdXQoZik6CiAgICAgICAgICAgIGhlbGxvX3dvcmxkKCkKICAgICAgICBzZWxmLmFzc2VydEVxdWFsKGYuZ2V0dmFsdWUoKSwgIkhlbGxvLCBXb3JsZCFcbiIpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgdW5pdHRlc3QubWFpbigpCiAgICA="
}
10 000 per sec
Redis 120G
key - 01975b05-647e-7ed5-abdd-f412a8a4882b
value - json
10 000
PostgreSQL

View File

@ -0,0 +1,165 @@
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"github.com/streadway/amqp"
)
func main() {
type Code struct {
IDTask string `json:"id_task"`
TpRunner string `json:"tp_runner"`
Code string `json:"code"`
Test string `json:"test"`
}
// Define RabbitMQ server URL.
amqpServerURL := os.Getenv("AMQP_SERVER_URL")
if amqpServerURL == "" {
amqpServerURL = "amqp://guest:guest@localhost:5672/" // Default URL if not set
}
// Create a new RabbitMQ connection.
connectRabbitMQ, err := amqp.Dial(amqpServerURL)
if err != nil {
panic(err)
}
defer connectRabbitMQ.Close()
// Opening a channel to our RabbitMQ instance over
// the connection we have already established.
channelRabbitMQ, err := connectRabbitMQ.Channel()
if err != nil {
panic(err)
}
defer channelRabbitMQ.Close()
// Subscribing to QueueService1 for getting messages.
messages, err := channelRabbitMQ.Consume(
"QueueService1", // queue name
"", // consumer
true, // auto-ack
false, // exclusive
false, // no local
false, // no wait
nil, // arguments
)
if err != nil {
log.Println(err)
}
// Build a welcome message.
log.Println("Successfully connected to RabbitMQ")
log.Println("Waiting for messages")
// Make a channel to receive messages into infinite loop.
forever := make(chan bool)
go func() {
for message := range messages {
// For example, show received message in a console.
log.Printf(" > Received message: %s\n", message.Body)
// Создание экземпляра структуры Task
var code_obj Code
// Разбор JSON строки в структуру
err := json.Unmarshal([]byte(message.Body), &code_obj)
if err != nil {
log.Fatalf("Ошибка при разборе JSON: %v", err)
}
mkdir(code_obj.IDTask)
mkfile(code_obj.IDTask, code_obj.Code, "main.py")
mkfile(code_obj.IDTask, code_obj.Test, "test_hello.py")
run(code_obj.IDTask)
fmt.Println(code_obj.Code)
}
}()
<-forever
}
func mkdir(dirName string) {
// Имя директории, которую нужно создать
// Права доступа к директории (0755 - чтение, запись, выполнение для владельца, чтение и выполнение для группы и остальных)
permissions := os.ModeDir | 0755
// Создание директории
err := os.Mkdir(dirName, permissions)
if err != nil {
log.Printf("Ошибка при создании директории: %v", err)
}
fmt.Printf("Директория '%s' успешно создана.\n", dirName)
}
func mkfile(dirName string, base64String string, fName string) {
// Декодирование Base64 строки
decodedBytes, er := base64.StdEncoding.DecodeString(base64String)
if er != nil {
log.Fatalf("Ошибка при декодировании Base64: %v", er)
}
// Преобразование байтов в строку
fileContent := string(decodedBytes)
// Права доступа к файлу (0644 - чтение и запись для владельца, чтение для группы и остальных)
fileName := "./" + dirName + "/" + fName
permissions := 0644
// Преобразование содержимого в слайс байтов
data := []byte(fileContent)
// Создание файла и запись содержимого
err := os.WriteFile(fileName, data, os.FileMode(permissions))
if err != nil {
log.Fatalf("Ошибка при создании файла: %v", err)
}
fmt.Printf("Файл '%s' успешно создан с содержимым.\n", fileName)
}
func run(idTask string) {
// Получение текущей рабочей директории
currentDir, err := os.Getwd()
if err != nil {
log.Fatalf("Ошибка при получении текущей директории: %v", err)
}
dir := currentDir + "/" + idTask
// Изменение текущей рабочей директории
err = os.Chdir(dir)
if err != nil {
log.Fatalf("Ошибка при изменении директории: %v", err)
}
// Команда для запуска Python с кодом
fileName := "test_hello.py"
cmd := exec.Command("python", "-m", "unittest", fileName)
// Запуск команды и получение вывода
output, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Ошибка при выполнении Python кода: %v\nВывод: %s", err, string(output))
}
// Вывод результата
fmt.Printf("Вывод Python:\n%s\n", string(output))
}

View File

@ -0,0 +1,85 @@
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq" // Import the PostgreSQL driver
)
const (
dbHost = "localhost"
dbPort = 5432
dbUser = "postgres"
dbPassword = "123" // Замените на свой пароль
dbName = "auth"
)
func main() {
// Строка подключения к базе данных
connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
dbHost, dbPort, dbUser, dbPassword, dbName)
// to-do: написать обращение в кеш Redis
// Подключение к базе данных
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Проверка подключения
err = db.Ping()
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to the database!")
router := gin.Default()
router.LoadHTMLGlob("./templates/*")
// Обработчик для получения фрагмента кода
router.GET("/code/:id", func(c *gin.Context) {
id := c.Param("id")
var code string
err := db.QueryRow("SELECT json_text FROM task WHERE id = $1", id).Scan(&code)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"code": code})
})
// Обработчик для обновления фрагмента кода
router.POST("/code/:id", func(c *gin.Context) {
id := c.Param("id")
var requestBody struct {
Code string `json:"code" binding:"required"`
}
if err := c.BindJSON(&requestBody); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
_, err := db.Exec("UPDATE snippets SET code = $1 WHERE id = $2", requestBody.Code, id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Snippet updated successfully"})
})
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{})
})
// Запуск сервера
router.Run(":8080")
}

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Editor</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.15/mode/javascript/javascript.min.js"></script>
<style>
.CodeMirror {
border: 1px solid #eee;
height: auto;
}
.CodeMirror-scroll {
overflow-y: hidden;
overflow-x: auto;
}
</style>
</head>
<body>
<h1>Code Editor</h1>
<textarea id="codeEditor"></textarea>
<button onclick="updateCode()">Update Code</button>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
mode: "javascript",
lineNumbers: true,
theme: "default"
});
// Function to fetch the code snippet from the server
function fetchCode() {
fetch('/code/01975b05-647e-7ed5-abdd-f412a8a4882b') // Assuming snippet ID is 1
.then(response => response.json())
.then(data => {
editor.setValue(atob(JSON.parse(data.code).code));
})
.catch(error => console.error('Error fetching code:', error));
}
// Function to update the code snippet on the server
function updateCode() {
fetch('/code/1', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ code: editor.getValue() }),
})
.then(response => response.json())
.then(data => {
alert(data.message);
})
.catch(error => console.error('Error updating code:', error));
}
// Fetch code on page load
fetchCode();
</script>
</body>
</html>

View File

@ -5,9 +5,11 @@ import (
"log" "log"
"os" "os"
"encoding/json"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/streadway/amqp" "github.com/streadway/amqp"
) )
// Структура для JSON данных // Структура для JSON данных
@ -69,17 +71,27 @@ func main() {
app.Get("/send", func(c *fiber.Ctx) error { app.Get("/send", func(c *fiber.Ctx) error {
// Create a message to publish. // Create a message to publish.
// to-do: дописать приемку json // to-do: дописать приемку json
p := new(Code) mess := new(Code)
// Разбираем JSON из тела запроса и заполняем структуру // Разбираем JSON из тела запроса и заполняем структуру
_ = c.BodyParser(p); _ = c.BodyParser(mess);
jsonBody, err := json.Marshal(mess)
fmt.Println(p.Code) if err != nil {
message := amqp.Publishing{ log.Fatalf("Error encoding JSON: %v", err)
ContentType: "text/plain",
Body: []byte(c.Query("msg")),
} }
fmt.Println(mess.Code)
message := amqp.Publishing{
ContentType: "application/json",
Body: jsonBody,
}
// message := amqp.Publishing{
// ContentType: "text/plain",
// Body: []byte("Hello"),
// }
// Attempt to publish a message to the queue. // Attempt to publish a message to the queue.
if err := channelRabbitMQ.Publish( if err := channelRabbitMQ.Publish(
"", // exchange "", // exchange