Ctrl K
ComunidadGuías…

server/internal/handlers/github_releases.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package handlers

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"time"

	"blackbox/server/internal/models"
	"gorm.io/gorm"
)

const githubReleasesURL = "https://api.github.com/repos/maxjb-xyz/blackbox/releases?per_page=100"
const githubCacheTTL = time.Hour

var githubHTTPClient = &http.Client{Timeout: 10 * time.Second}

func GetGitHubReleases(database *gorm.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Check cache
		var cachedAt models.AppSetting
		var cachedBody models.AppSetting
		atErr := database.Where("key = ?", "github_releases_cached_at").First(&cachedAt).Error
		bodyErr := database.Where("key = ?", "github_releases_body").First(&cachedBody).Error

		if atErr == nil && bodyErr == nil {
			if t, err := time.Parse(time.RFC3339, cachedAt.Value); err == nil {
				if time.Since(t) < githubCacheTTL {
					w.Header().Set("Content-Type", "application/json")
					w.Header().Set("Cache-Control", "no-store")
					if _, err := w.Write([]byte(cachedBody.Value)); err != nil {
						log.Printf("GetGitHubReleases write cached: %v", err)
					}
					return
				}
			}
		}

		// Fetch from GitHub
		req, err := http.NewRequestWithContext(r.Context(), http.MethodGet, githubReleasesURL, nil)
		if err != nil {
			writeError(w, http.StatusInternalServerError, "failed to build request")
			return
		}
		resp, err := githubHTTPClient.Do(req)
		if err != nil {
			writeError(w, http.StatusBadGateway, "failed to reach GitHub")
			return
		}
		defer func() {
			if closeErr := resp.Body.Close(); closeErr != nil {
				log.Printf("GetGitHubReleases close body: %v", closeErr)
			}
		}()
		body, err := io.ReadAll(io.LimitReader(resp.Body, 512*1024))
		if err != nil || resp.StatusCode != http.StatusOK {
			writeError(w, http.StatusBadGateway, "GitHub API error")
			return
		}

		// Validate JSON
		var releases []json.RawMessage
		if err := json.Unmarshal(body, &releases); err != nil {
			writeError(w, http.StatusBadGateway, "invalid GitHub response")
			return
		}

		// Cache
		now := time.Now().UTC().Format(time.RFC3339)
		if err := database.Save(&models.AppSetting{Key: "github_releases_cached_at", Value: now, UpdatedAt: time.Now()}).Error; err != nil {
			log.Printf("GetGitHubReleases cache timestamp save: %v", err)
		}
		if err := database.Save(&models.AppSetting{Key: "github_releases_body", Value: string(body), UpdatedAt: time.Now()}).Error; err != nil {
			log.Printf("GetGitHubReleases cache body save: %v", err)
		}

		w.Header().Set("Content-Type", "application/json")
		w.Header().Set("Cache-Control", "no-store")
		if _, err := w.Write(body); err != nil {
			log.Printf("GetGitHubReleases write: %v", err)
		}
	}
}