From d45d99517c5a170cb2a439ee6710fb8577295eaf Mon Sep 17 00:00:00 2001 From: valitovgaziz Date: Wed, 29 Oct 2025 06:11:21 +0500 Subject: [PATCH] modified: main_dc/docker-compose.yml modified: main_dc/nginx/nginx-ssl.conf modified: main_dc/yalarba/api_es/Dockerfile modified: main_dc/yalarba/api_es/cmd/main.go modified: main_dc/yalarba/api_es/go.mod new file: main_dc/yalarba/api_es/go.sum add api_es for REST API backend to easysite, add config nginx, add server connection from api_es to db_tp --- main_dc/docker-compose.yml | 28 +++- main_dc/nginx/nginx-ssl.conf | 23 +++ main_dc/yalarba/api_es/Dockerfile | 8 +- main_dc/yalarba/api_es/cmd/main.go | 219 ++++++++++++++++++++++++++++- main_dc/yalarba/api_es/go.mod | 18 +++ main_dc/yalarba/api_es/go.sum | 31 ++++ 6 files changed, 321 insertions(+), 6 deletions(-) create mode 100644 main_dc/yalarba/api_es/go.sum diff --git a/main_dc/docker-compose.yml b/main_dc/docker-compose.yml index f9c3117..268223a 100644 --- a/main_dc/docker-compose.yml +++ b/main_dc/docker-compose.yml @@ -177,6 +177,31 @@ services: timeout: 10s retries: 3 + api_easysite: + build: + context: ./api_easysite + dockerfile: Dockerfile + container_name: api_easysite + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + DB_HOST: db + DB_PORT: 5432 + DB_USER: postgres + DB_PASSWORD: postgres + DB_NAME: mydb + APP_PORT: 8081 + networks: + - app-network + - web-network + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8081/health"] + interval: 30s + timeout: 10s + retries: 3 + volumes: certbot_data: certbot_www: @@ -194,6 +219,5 @@ networks: bb-network: driver: bridge - # Эта опция автоматически удаляет orphans -x-remove-orphans: true \ No newline at end of file +x-remove-orphans: true diff --git a/main_dc/nginx/nginx-ssl.conf b/main_dc/nginx/nginx-ssl.conf index 384693f..a875e19 100644 --- a/main_dc/nginx/nginx-ssl.conf +++ b/main_dc/nginx/nginx-ssl.conf @@ -100,6 +100,29 @@ server { proxy_send_timeout 600; proxy_read_timeout 600; } + + # Новый блок для API + location /api/ { + proxy_pass http://api_easysite:8081/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Port $server_port; + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + + # CORS headers + add_header Access-Control-Allow-Origin "*"; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; + add_header Access-Control-Allow-Headers "Content-Type, Authorization"; + + # Handle preflight requests + if ($request_method = OPTIONS) { + return 204; + } + } } server { diff --git a/main_dc/yalarba/api_es/Dockerfile b/main_dc/yalarba/api_es/Dockerfile index fb396ec..8bd7ef2 100644 --- a/main_dc/yalarba/api_es/Dockerfile +++ b/main_dc/yalarba/api_es/Dockerfile @@ -1,8 +1,10 @@ -# Используем официальный образ Go FROM golang:1.25.1-alpine WORKDIR /app +# Устанавливаем зависимости для компиляции +RUN apk add --no-cache gcc musl-dev + # Копируем go.mod и go.sum COPY go.mod go.sum ./ RUN go mod download @@ -11,8 +13,8 @@ RUN go mod download COPY . . # Компилируем БЕЗ CGO -RUN CGO_ENABLED=0 GOOS=linux go build -o bin/main ./cmd/main.go +RUN CGO_ENABLED=0 GOOS=linux go build -o bin/main . -EXPOSE 8080 +EXPOSE 8081 CMD ["./bin/main"] \ No newline at end of file diff --git a/main_dc/yalarba/api_es/cmd/main.go b/main_dc/yalarba/api_es/cmd/main.go index 20b3674..7eab285 100644 --- a/main_dc/yalarba/api_es/cmd/main.go +++ b/main_dc/yalarba/api_es/cmd/main.go @@ -1,9 +1,226 @@ package main import ( + "encoding/json" "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/logger" ) +// Модели для БД +type User struct { + ID uint `gorm:"primaryKey" json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` + Name string `json:"name"` + Email string `json:"email"` +} + +type Config struct { + DBHost string + DBPort string + DBUser string + DBPassword string + DBName string + AppPort string +} + +var db *gorm.DB +var config Config + func main() { - fmt.Println("Starting api_es ...") + // Загрузка конфигурации + config = Config{ + DBHost: getEnv("DB_HOST", "db"), + DBPort: getEnv("DB_PORT", "5432"), + DBUser: getEnv("DB_USER", "postgres"), + DBPassword: getEnv("DB_PASSWORD", "postgres"), + DBName: getEnv("DB_NAME", "mydb"), + AppPort: getEnv("APP_PORT", "8081"), + } + + // Инициализация БД + if err := initDB(); err != nil { + log.Fatal("Failed to connect to database:", err) + } + + // Автомиграция + if err := db.AutoMigrate(&User{}); err != nil { + log.Fatal("Failed to migrate database:", err) + } + + r := chi.NewRouter() + + // Стандартные middleware + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + r.Use(middleware.Timeout(60 * time.Second)) + + // Маршруты API + r.Route("/api", func(r chi.Router) { + r.Get("/", handleRoot) + r.Get("/users", getUsers) + r.Post("/users", createUser) + r.Get("/users/{id}", getUser) + r.Put("/users/{id}", updateUser) + r.Delete("/users/{id}", deleteUser) + }) + + // Health check + r.Get("/health", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}) + }) + + // Запуск сервера + log.Printf("Server starting on port %s", config.AppPort) + if err := http.ListenAndServe(":"+config.AppPort, r); err != nil { + log.Fatal("Failed to start server:", err) + } +} + +func initDB() error { + dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=UTC", + config.DBHost, config.DBUser, config.DBPassword, config.DBName, config.DBPort) + + var err error + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Info), + }) + if err != nil { + return err + } + + sqlDB, err := db.DB() + if err != nil { + return err + } + + // Настройка пула соединений + sqlDB.SetMaxIdleConns(10) + sqlDB.SetMaxOpenConns(100) + sqlDB.SetConnMaxLifetime(time.Hour) + + log.Println("Successfully connected to database") + return nil +} + +func getEnv(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} + +// Обработчики API +func handleRoot(w http.ResponseWriter, r *http.Request) { + response := map[string]string{ + "message": "EasySite REST API Server", + "version": "1.0.0", + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) +} + +func getUsers(w http.ResponseWriter, r *http.Request) { + var users []User + if err := db.Find(&users).Error; err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(users) +} + +func createUser(w http.ResponseWriter, r *http.Request) { + var user User + if err := json.NewDecoder(r.Body).Decode(&user); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if err := db.Create(&user).Error; err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(user) +} + +func getUser(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + var user User + + if err := db.First(&user, id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + http.Error(w, "User not found", http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(user) +} + +func updateUser(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + var user User + + if err := db.First(&user, id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + http.Error(w, "User not found", http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + var updateData User + if err := json.NewDecoder(r.Body).Decode(&updateData); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if err := db.Model(&user).Updates(updateData).Error; err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(user) +} + +func deleteUser(w http.ResponseWriter, r *http.Request) { + id := chi.URLParam(r, "id") + var user User + + if err := db.First(&user, id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + http.Error(w, "User not found", http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + if err := db.Delete(&user).Error; err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{"message": "User deleted successfully"}) } \ No newline at end of file diff --git a/main_dc/yalarba/api_es/go.mod b/main_dc/yalarba/api_es/go.mod index 9c51fab..5af8a08 100644 --- a/main_dc/yalarba/api_es/go.mod +++ b/main_dc/yalarba/api_es/go.mod @@ -1,3 +1,21 @@ module api_es go 1.25.1 + +require ( + github.com/go-chi/chi/v5 v5.2.3 + gorm.io/driver/postgres v1.6.0 +) + +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.6.0 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/text v0.21.0 // indirect + gorm.io/gorm v1.25.10 // indirect +) diff --git a/main_dc/yalarba/api_es/go.sum b/main_dc/yalarba/api_es/go.sum new file mode 100644 index 0000000..da1b8fe --- /dev/null +++ b/main_dc/yalarba/api_es/go.sum @@ -0,0 +1,31 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= +github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= +gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=