package web import ( "bytes" "image/png" "net/http" "strconv" "sync" "time" "rond-with-you/internal/fog" ) // 差异瓦片要反复读同一份快照、同一份库内迷雾,单槽缓存住两边的块集即可—— // 站长一次只会看一份预览。缓存里的 map 加载完就只读,渲染时并发遍历是安全的。 var ( diffSetsMu sync.Mutex diffSetsToken string diffSetsAt time.Time diffSetsCur map[[2]int][]byte diffSetsInc map[[2]int][]byte ) // diffSetsTTL 短于暂存的 2 小时:库内迷雾随时可能被别的操作改掉, // 缓存太久会让差异图与页面上那组数字对不上。 const diffSetsTTL = 10 * time.Minute func (s *Server) fogDiffSets(token string) (cur, inc map[[2]int][]byte, err error) { diffSetsMu.Lock() defer diffSetsMu.Unlock() if token == diffSetsToken && time.Since(diffSetsAt) < diffSetsTTL { return diffSetsCur, diffSetsInc, nil } data, err := s.loadStashedFog(token) if err != nil { return nil, nil, err } blocks, _, err := fog.Decode(data) if err != nil { return nil, nil, err } ix, err := s.fogIndex() if err != nil { return nil, nil, err } cur = map[[2]int][]byte{} ix.View(func(m map[[2]int][]byte) { for k, bm := range m { cur[k] = bm } }) inc = make(map[[2]int][]byte, len(blocks)) for _, b := range blocks { inc[[2]int{b.GX, b.GY}] = b.Bitmap } diffSetsToken, diffSetsCur, diffSetsInc, diffSetsAt = token, cur, inc, time.Now() return cur, inc, nil } // adminFogDiffTile 渲染一张差异瓦片:绿=叠加会新增、灰=两边都有、红=整体替换会丢。 // 只给站长看,不涉及遮罩。 func (s *Server) adminFogDiffTile(w http.ResponseWriter, r *http.Request) { z, err1 := strconv.Atoi(r.PathValue("z")) x, err2 := strconv.Atoi(r.PathValue("x")) y, err3 := strconv.Atoi(r.PathValue("y")) if err1 != nil || err2 != nil || err3 != nil || z < 0 || z > 22 || x < 0 || y < 0 || x >= 1<= 1<