mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
upload
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"fotbal-club/internal/services"
|
||||
)
|
||||
|
||||
// PrefetchController exposes admin endpoints to inspect and trigger background prefetch cycles.
|
||||
type PrefetchController struct{}
|
||||
|
||||
// isDuringMatchFromCache checks cached FACR JSONs to determine if a match is ongoing.
|
||||
func isDuringMatchFromCache(cacheDir string) bool {
|
||||
now := time.Now()
|
||||
parseDT := func(s string) (time.Time, bool) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" { return time.Time{}, false }
|
||||
layouts := []string{"02.01.2006 15:04", time.RFC3339, "2006-01-02 15:04"}
|
||||
for _, layout := range layouts {
|
||||
if t, err := time.ParseInLocation(layout, s, time.Local); err == nil { return t, true }
|
||||
}
|
||||
return time.Time{}, false
|
||||
}
|
||||
within := func(ts time.Time) bool {
|
||||
start := ts.Add(-15 * time.Minute)
|
||||
end := ts.Add(150 * time.Minute)
|
||||
return now.After(start) && now.Before(end)
|
||||
}
|
||||
type flatMatch struct {
|
||||
DateTime string `json:"date_time"`
|
||||
Date string `json:"date"`
|
||||
Time string `json:"time"`
|
||||
Kickoff string `json:"kickoff"`
|
||||
}
|
||||
check := func(b []byte) bool {
|
||||
if len(b) == 0 { return false }
|
||||
var payload struct {
|
||||
Competitions []struct { Matches []struct {
|
||||
DateTime string `json:"date_time"`
|
||||
Date string `json:"date"`
|
||||
Time string `json:"time"`
|
||||
Kickoff string `json:"kickoff"`
|
||||
} `json:"matches"` } `json:"competitions"`
|
||||
Matches []flatMatch `json:"matches"`
|
||||
}
|
||||
_ = json.Unmarshal(b, &payload)
|
||||
for _, c := range payload.Competitions {
|
||||
for _, m := range c.Matches {
|
||||
var ts time.Time; var ok bool
|
||||
if m.DateTime != "" { ts, ok = parseDT(m.DateTime) } else if m.Date != "" || m.Time != "" { ts, ok = parseDT(strings.TrimSpace(m.Date+" "+m.Time)) } else if m.Kickoff != "" { ts, ok = parseDT(m.Kickoff) }
|
||||
if ok && within(ts) { return true }
|
||||
}
|
||||
}
|
||||
for _, m := range payload.Matches {
|
||||
var ts time.Time; var ok bool
|
||||
if m.DateTime != "" { ts, ok = parseDT(m.DateTime) } else if m.Date != "" || m.Time != "" { ts, ok = parseDT(strings.TrimSpace(m.Date+" "+m.Time)) } else if m.Kickoff != "" { ts, ok = parseDT(m.Kickoff) }
|
||||
if ok && within(ts) { return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
files := []string{ filepath.Join(cacheDir, "facr_club_info.json"), filepath.Join(cacheDir, "facr_tables.json") }
|
||||
for _, p := range files {
|
||||
if b, err := os.ReadFile(p); err == nil {
|
||||
if check(b) { return true }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewPrefetchController() *PrefetchController { return &PrefetchController{} }
|
||||
|
||||
// Status returns info about the last fetch and the approximate next run time.
|
||||
// GET /api/v1/admin/prefetch/status
|
||||
func (pc *PrefetchController) Status(c *gin.Context) {
|
||||
if c.GetString("userRole") != "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
||||
return
|
||||
}
|
||||
|
||||
cacheDir := filepath.Join("cache", "prefetch")
|
||||
metaPath := filepath.Join(cacheDir, "meta.json")
|
||||
var lastUpdated string
|
||||
if b, err := os.ReadFile(metaPath); err == nil {
|
||||
var m struct{ LastUpdated string `json:"lastUpdated"` }
|
||||
if json.Unmarshal(b, &m) == nil {
|
||||
lastUpdated = m.LastUpdated
|
||||
}
|
||||
}
|
||||
|
||||
// Determine configured interval
|
||||
interval := 30 * time.Minute
|
||||
if v := strings.TrimSpace(os.Getenv("PREFETCH_INTERVAL_MINUTES")); v != "" {
|
||||
if mins, err := strconv.Atoi(v); err == nil && mins > 0 {
|
||||
interval = time.Duration(mins) * time.Minute
|
||||
}
|
||||
}
|
||||
|
||||
// Fast mode if during match
|
||||
fast := isDuringMatchFromCache(cacheDir)
|
||||
next := time.Now().Add(interval)
|
||||
if fast {
|
||||
next = time.Now().Add(5 * time.Minute)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"lastUpdated": lastUpdated,
|
||||
"intervalMinutes": int(interval / time.Minute),
|
||||
"fastMode": fast,
|
||||
"nextApproximate": next.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
// Trigger starts an immediate prefetch cycle (best effort)
|
||||
// POST /api/v1/admin/prefetch/trigger
|
||||
func (pc *PrefetchController) Trigger(c *gin.Context) {
|
||||
if c.GetString("userRole") != "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
||||
return
|
||||
}
|
||||
// Resolve the base URL similar to main.go logic
|
||||
base := os.Getenv("PREFETCH_TARGET")
|
||||
if strings.TrimSpace(base) == "" {
|
||||
port := strings.TrimSpace(os.Getenv("PORT"))
|
||||
if port == "" { port = "8080" }
|
||||
base = "http://127.0.0.1:" + port + "/api/v1"
|
||||
}
|
||||
go func() {
|
||||
// fire-and-forget
|
||||
services.PrefetchOnce(base)
|
||||
// Additionally trigger an immediate Zonerama refresh based on cached settings
|
||||
// This ensures the admin trigger updates the gallery right away.
|
||||
cacheDir := filepath.Join("cache", "prefetch")
|
||||
b, err := os.ReadFile(filepath.Join(cacheDir, "settings.json"))
|
||||
if err == nil {
|
||||
var s struct{
|
||||
ZoneramaURL string `json:"zonerama_url"`
|
||||
GalleryURL string `json:"gallery_url"`
|
||||
}
|
||||
if jsonErr := json.Unmarshal(b, &s); jsonErr == nil {
|
||||
link := strings.TrimSpace(s.ZoneramaURL)
|
||||
if link == "" { link = strings.TrimSpace(s.GalleryURL) }
|
||||
if link != "" {
|
||||
_ = services.RefreshZoneramaNow(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Regenerate flat gallery files from existing albums
|
||||
_ = services.RegenerateFlatGalleryFiles()
|
||||
}()
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Prefetch started"})
|
||||
}
|
||||
Reference in New Issue
Block a user