aides-uploader/main.go

214 lines
5.8 KiB
Go
Raw Normal View History

2024-11-29 14:32:44 +00:00
package main
import (
"bytes"
2024-12-13 12:02:23 +00:00
"encoding/json"
2024-11-29 14:32:44 +00:00
"flag"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"
)
type Configuration struct {
ServerURL string
Repo string
Token string
FilePatterns []string
Files []string
}
2024-12-13 12:02:23 +00:00
type TaskResponse struct {
TaskID int `json:"taskID"`
Status int `json:"status"`
}
2024-11-29 14:32:44 +00:00
func parseFlags() Configuration {
var cfg Configuration
flag.StringVar(&cfg.ServerURL, "url", "http://localhost:9999", "Базовый URL сервера загрузки")
flag.StringVar(&cfg.Repo, "repo", "", "Название репозитория (обязательно)")
flag.StringVar(&cfg.Token, "token", "", "Токен авторизации (обязательно)")
files := flag.String("files", "", "Список путей к файлам или паттернов (разделены запятой) для загрузки (обязательно)")
flag.Parse()
missing := false
if cfg.Repo == "" {
fmt.Println("Ошибка: -repo является обязательным")
missing = true
}
if cfg.Token == "" {
fmt.Println("Ошибка: -token является обязательным")
missing = true
}
if *files == "" {
fmt.Println("Ошибка: -files является обязательным")
missing = true
}
if missing {
flag.Usage()
os.Exit(1)
}
cfg.FilePatterns = splitAndTrim(*files, ",")
var allFiles []string
for _, pattern := range cfg.FilePatterns {
matches, err := filepath.Glob(pattern)
if err != nil {
fmt.Fprintf(os.Stderr, "Неверный паттерн glob '%s': %v\n", pattern, err)
continue
}
if len(matches) == 0 {
fmt.Fprintf(os.Stderr, "Предупреждение: Паттерн '%s' не совпадает ни с одним файлом\n", pattern)
continue
}
allFiles = append(allFiles, matches...)
}
cfg.Files = unique(allFiles)
if len(cfg.Files) == 0 {
fmt.Println("Ошибка: Не найдено файлов для загрузки после обработки паттернов")
os.Exit(1)
}
return cfg
}
func splitAndTrim(s, sep string) []string {
parts := strings.Split(s, sep)
var trimmed []string
for _, part := range parts {
part = strings.TrimSpace(part)
if part != "" {
trimmed = append(trimmed, part)
}
}
return trimmed
}
func unique(input []string) []string {
seen := make(map[string]struct{})
var result []string
for _, item := range input {
if _, exists := seen[item]; !exists {
seen[item] = struct{}{}
result = append(result, item)
}
}
return result
}
2024-12-13 12:02:23 +00:00
func createMultipartRequest(url string, files []string, token string, repo string) (*http.Request, error) {
2024-11-29 14:32:44 +00:00
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
for _, filePath := range files {
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("не удалось открыть файл %s: %w", filePath, err)
}
defer file.Close()
part, err := writer.CreateFormFile("files", filepath.Base(filePath))
if err != nil {
return nil, fmt.Errorf("не удалось создать поле формы для файла %s: %w", filePath, err)
}
_, err = io.Copy(part, file)
if err != nil {
return nil, fmt.Errorf("не удалось скопировать содержимое файла %s: %w", filePath, err)
}
}
2024-12-13 12:02:23 +00:00
err := writer.WriteField("repo", repo)
if err != nil {
return nil, fmt.Errorf("не удалось добавить поле repo: %w", err)
}
err = writer.Close()
2024-11-29 14:32:44 +00:00
if err != nil {
return nil, fmt.Errorf("не удалось закрыть multipart писатель: %w", err)
}
req, err := http.NewRequest("POST", url, &buf)
if err != nil {
return nil, fmt.Errorf("не удалось создать HTTP-запрос: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Bearer "+token)
return req, nil
}
2024-12-13 12:02:23 +00:00
func createTask(cfg Configuration) (int, error) {
taskURL := fmt.Sprintf("%s/tasks", strings.TrimRight(cfg.ServerURL, "/"))
requestBody, err := json.Marshal(map[string]string{
"Repo": cfg.Repo,
})
if err != nil {
return 0, fmt.Errorf("не удалось создать тело запроса: %w", err)
}
2024-11-29 14:32:44 +00:00
2024-12-13 12:02:23 +00:00
req, err := http.NewRequest("POST", taskURL, bytes.NewReader(requestBody))
if err != nil {
return 0, fmt.Errorf("не удалось создать HTTP-запрос: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+cfg.Token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return 0, fmt.Errorf("не удалось выполнить HTTP-запрос: %w", err)
}
defer resp.Body.Close()
var taskResp TaskResponse
err = json.NewDecoder(resp.Body).Decode(&taskResp)
if err != nil {
return 0, fmt.Errorf("не удалось декодировать ответ: %w", err)
}
return taskResp.TaskID, nil
}
func uploadFiles(cfg Configuration, taskID int) error {
uploadURL := fmt.Sprintf("%s/tasks/%d/upload", strings.TrimRight(cfg.ServerURL, "/"), taskID)
req, err := createMultipartRequest(uploadURL, cfg.Files, cfg.Token, cfg.Repo)
2024-11-29 14:32:44 +00:00
if err != nil {
return fmt.Errorf("не удалось создать multipart-запрос: %w", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("не удалось выполнить HTTP-запрос: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("не удалось прочитать тело ответа: %w", err)
}
fmt.Println(string(respBody))
return nil
}
func main() {
cfg := parseFlags()
2024-12-13 12:02:23 +00:00
taskID, err := createTask(cfg)
2024-11-29 14:32:44 +00:00
if err != nil {
fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err)
os.Exit(1)
}
2024-12-13 12:02:23 +00:00
uploadFiles(cfg, taskID)
2024-11-29 14:32:44 +00:00
}