82 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rain
import (
"context"
"fmt"
"log"
"os"
"path"
"regexp"
"strconv"
"strings"
"time"
"weatherstation/internal/database"
)
var (
// Matches .../<PRODUCT>/<YYYYMMDD>/<HH>/<mm>/<z>/<y>/<x>.bin
// Example: /tiles/China/CMPA_RT_China_0P01_HOR-PRE_GISJPG_Tiles/20251007/01/00/7/40/102.bin
tileRE = regexp.MustCompile(`(?i)/tiles/.+?/([^/]+)/([0-9]{8})/([0-9]{2})/([0-9]{2})/([0-9]+)/([0-9]+)/([0-9]+)\.bin$`)
)
// TileRef references a CMPA rain tile.
type TileRef struct {
Product string
DT time.Time // nominal time in Asia/Shanghai (UTC+8)
Z, Y, X int
}
// ParseCMPATileURL parses a CMPA tile URL/path and extracts product, time (UTC+8), z/y/x.
// The timestamp in the path is UTC; we convert to Asia/Shanghai by adding 8h.
func ParseCMPATileURL(u string) (TileRef, error) {
p := u
if i := strings.IndexAny(p, "?#"); i >= 0 {
p = p[:i]
}
p = path.Clean(p)
m := tileRE.FindStringSubmatch(p)
if len(m) == 0 {
return TileRef{}, fmt.Errorf("unrecognized CMPA tile path: %s", u)
}
product := m[1]
yyyymmdd := m[2]
hh := m[3]
mm := m[4]
z := mustAtoi(m[5])
y := mustAtoi(m[6])
x := mustAtoi(m[7])
// Parse as UTC then shift to CST(+8)
utcT, err := time.ParseInLocation("20060102 15 04", fmt.Sprintf("%s %s %s", yyyymmdd, hh, mm), time.UTC)
if err != nil {
return TileRef{}, fmt.Errorf("parse utc time: %w", err)
}
loc, _ := time.LoadLocation("Asia/Shanghai")
if loc == nil {
loc = time.FixedZone("CST", 8*3600)
}
dt := utcT.In(loc)
return TileRef{Product: product, DT: dt, Z: z, Y: y, X: x}, nil
}
func mustAtoi(s string) int { n, _ := strconv.Atoi(s); return n }
// StoreTileBytes parses the URL, computes metadata and upserts into rain_tiles.
func StoreTileBytes(ctx context.Context, urlOrPath string, data []byte) error {
ref, err := ParseCMPATileURL(urlOrPath)
if err != nil {
return err
}
// 可选:强制 +8 小时(若上游传入的时间已为 UTC 且未转换,可用此开关修正)
if strings.EqualFold(strings.TrimSpace(strings.ToLower(os.Getenv("RAIN_FORCE_SHIFT8"))), "1") {
ref.DT = ref.DT.Add(8 * time.Hour)
}
// 可选调试打印解析出的时间CST与 URL
if strings.EqualFold(strings.TrimSpace(strings.ToLower(os.Getenv("RAIN_DEBUG"))), "1") {
log.Printf("[rain] store tile: url=%s -> product=%s dt(local)=%s z=%d y=%d x=%d",
urlOrPath, ref.Product, ref.DT.Format("2006-01-02 15:04:05 -0700"), ref.Z, ref.Y, ref.X)
}
db := database.GetDB()
return database.UpsertRainTile(ctx, db, ref.Product, ref.DT, ref.Z, ref.Y, ref.X, 256, 256, data)
}