aides-repo-api/router/router.go

134 lines
4.9 KiB
Go
Raw Normal View History

2024-12-04 11:46:42 +00:00
package router
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path"
"rest_api/models" // Импорт пакета с моделями, где определены структуры конфигурации
"strconv"
"github.com/go-chi/render"
"github.com/go-chi/chi/v5" //Импорт пакета chi для маршрутизации
"github.com/go-chi/chi/v5/middleware" // Импорт middleware для логирования
)
func createSymlink(target, link string) error {
if _, err := os.Lstat(link); err == nil {
if err := os.Remove(link); err != nil {
return fmt.Errorf("failed to remove existing file or symlink: %w", err)
}
}
if err := os.Symlink(target, link); err != nil {
return fmt.Errorf("failed to create symlink: %w", err)
}
return nil
}
type Router struct {
Config models.Config
}
// Создает Роутер
func NewRouter(cfg models.Config) *Router {
return &Router{Config: cfg}
}
// Метод настройки маршрутов для Роутера
func (r *Router) SetupRoutes() *chi.Mux {
router := chi.NewRouter()
router.Use(middleware.Logger)
// Создаем директорию для загрузки
os.MkdirAll(path.Join(r.Config.UploadDir, "out"), os.ModePerm)
// Определяем маршрут для загрузки файлов("/upload/{executionID}" путь, по которому будет доступен данный маршрут.
//Путь включает переменную часть {executionID}, которая позволяет извлекать динамические параметры из URL.)
router.Post("/upload/{repo}/task/{taskID}", r.uploadHandler)
return router
}
// Метод отвечает за загрузку файлов
func (r *Router) uploadHandler(w http.ResponseWriter, req *http.Request) {
if req.Header.Get("Authorization") != "Bearer "+r.Config.Token {
render.JSON(w, req, models.ErrResponse{Message: "Не авторизованный", Code: http.StatusUnauthorized})
return
}
// Извлекаем параметр taskID из URL и проверяем его наличие
taskID := chi.URLParam(req, "taskID")
repo := chi.URLParam(req, "repo")
if taskID == "" || repo == "" {
render.JSON(w, req, models.ErrResponse{Message: "Требуются параметры [repo] и [taskID]", Code: http.StatusBadRequest})
return
}
// Чтение файлов из запроса
err := req.ParseMultipartForm(r.Config.MaxSizeUpload) // Лимит 100 MB
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Парсинг не удался", Code: http.StatusBadRequest})
return
}
// При успешном парсинге извлекаем файлы
files := req.MultipartForm.File["files"] // Карта где ключами являются имена полей формы, а значениями — массивы заголовков файлов.
localPath := path.Join(repo, "task", taskID)
taskFolderPath := path.Join(r.Config.UploadDir, "extra", localPath)
os.MkdirAll(taskFolderPath, os.ModePerm)
for _, fileHeader := range files {
file, err := fileHeader.Open()
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Не удается открыть файл", Code: http.StatusInternalServerError})
return
}
defer file.Close()
// Полный путь для файла
filePath := path.Join(taskFolderPath, fileHeader.Filename)
//Удаляем файл если такой уже существует
if _, err := os.Stat(filePath); err == nil {
err = os.Remove(filePath)
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Не удалось удалить файл", Code: http.StatusInternalServerError})
return
}
}
// Сохранение файла на сервере
outFile, err := os.Create(filePath)
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Не удается создать файл", Code: http.StatusInternalServerError})
return
}
defer outFile.Close()
_, err = io.Copy(outFile, file)
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Не удалось сохранить файл", Code: http.StatusInternalServerError})
return
}
// Символическая ссылка
targetPath := path.Join("../extra/", localPath, fileHeader.Filename)
symLink := path.Join(r.Config.UploadDir, "out", fileHeader.Filename)
err = createSymlink(targetPath, symLink)
if err != nil {
render.JSON(w, req, models.ErrResponse{Message: "Не удается создать ссылку", Code: http.StatusInternalServerError})
return
}
}
//Ответы в формате JSON
resp := map[string]string{
"taskID": taskID,
"repository": repo,
"message": "Файлы успешно загружены",
"fileCount": strconv.Itoa(len(files)),
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)
}