дзеркало
				https://bitbucket.org/s_l_teichmann/mtsatellite
				synced 2025-10-31 16:15:27 +01:00 
			
		
		
		
	Generate ETags and encode PNG directly to response stream.
This commit is contained in:
		| @@ -1 +0,0 @@ | ||||
| * Generate and use ETags to improve caching behavior. | ||||
| @@ -12,11 +12,10 @@ import ( | ||||
| 	"image/png" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"bytes" | ||||
|  | ||||
| 	"bitbucket.org/s_l_teichmann/mtredisalize/common" | ||||
|  | ||||
| 	"github.com/gorilla/mux" | ||||
| @@ -64,6 +63,15 @@ func toUint(s string) uint { | ||||
| 	return uint(x) | ||||
| } | ||||
|  | ||||
| func createETag(path string) (etag string, err error) { | ||||
| 	var fi os.FileInfo | ||||
| 	if fi, err = os.Stat(path); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	etag = fmt.Sprintf("%x-%x", fi.ModTime().Unix(), fi.Size()) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	var ( | ||||
| 		port   int | ||||
| @@ -84,41 +92,38 @@ func main() { | ||||
|  | ||||
| 	r := mux.NewRouter() | ||||
| 	r.HandleFunc("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png", func(rw http.ResponseWriter, r *http.Request) { | ||||
|  | ||||
| 		vars := mux.Vars(r) | ||||
| 		xs := vars["x"] | ||||
| 		ys := vars["y"] | ||||
| 		zs := vars["z"] | ||||
|  | ||||
| 		x, y, z := toUint(xs), toUint(ys), toUint(zs) | ||||
| 		if z < 9 { | ||||
| 			filename := fmt.Sprintf("%d/%d/%d.png", z, x, y) | ||||
| 			http.ServeFile(rw, r, filepath.Join(mapDir, filename)) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if z > 16 { | ||||
| 			z = 16 | ||||
| 		} | ||||
| 		//fmt.Printf("x %d\n", x) | ||||
| 		//fmt.Printf("y %d\n", y) | ||||
| 		//fmt.Printf("z %d\n", z) | ||||
| 		tx := x >> (z - 8) | ||||
| 		ty := y >> (z - 8) | ||||
| 		rx := x & ^(^uint(0) << (z - 8)) | ||||
| 		ry := y & ^(^uint(0) << (z - 8)) | ||||
|  | ||||
| 		parts := uint(1) << (z - 8) | ||||
| 		//fmt.Printf("z %d\n", z) | ||||
| 		//fmt.Printf("parts %d\n", parts) | ||||
|  | ||||
| 		w := uint(256) / parts | ||||
| 		xo := w * rx | ||||
| 		yo := w * (parts - 1 - ry) | ||||
| 		//fmt.Printf("w %d\n", w) | ||||
| 		//fmt.Printf("xo %d\n", xo) | ||||
| 		//fmt.Printf("yo %d\n", yo) | ||||
| 		//fmt.Printf("rx %d\n", rx) | ||||
| 		//fmt.Printf("ry %d\n", ry) | ||||
|  | ||||
| 		baseTile := filepath.Join(mapDir, fmt.Sprintf("8/%d/%d.png", tx, ty)) | ||||
|  | ||||
| 		var etag string | ||||
| 		var err error | ||||
|  | ||||
| 		if ifNoneMatch := r.Header.Get("If-None-Match"); ifNoneMatch != "" { | ||||
| 			if etag, err = createETag(baseTile); err == nil { | ||||
| 				if ifNoneMatch == etag { | ||||
| 					http.Error(rw, http.StatusText(http.StatusNotModified), http.StatusNotModified) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		img := common.LoadPNG(baseTile) | ||||
|  | ||||
| 		type subImage interface { | ||||
| @@ -129,24 +134,47 @@ func main() { | ||||
| 		var ok bool | ||||
| 		if si, ok = img.(subImage); !ok { | ||||
| 			// Should not happen. | ||||
| 			http.ServeFile(rw, r, filepath.Join(mapDir, baseTile)) | ||||
| 			http.Error(rw, | ||||
| 				http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		rx := x & ^(^uint(0) << (z - 8)) | ||||
| 		ry := y & ^(^uint(0) << (z - 8)) | ||||
|  | ||||
| 		parts := uint(1) << (z - 8) | ||||
|  | ||||
| 		w := uint(256) / parts | ||||
| 		xo := w * rx | ||||
| 		yo := w * (parts - 1 - ry) | ||||
| 		//fmt.Printf("x %d\n", x) | ||||
| 		//fmt.Printf("y %d\n", y) | ||||
| 		//fmt.Printf("z %d\n", z) | ||||
| 		//fmt.Printf("z %d\n", z) | ||||
| 		//fmt.Printf("parts %d\n", parts) | ||||
| 		//fmt.Printf("w %d\n", w) | ||||
| 		//fmt.Printf("xo %d\n", xo) | ||||
| 		//fmt.Printf("yo %d\n", yo) | ||||
| 		//fmt.Printf("rx %d\n", rx) | ||||
| 		//fmt.Printf("ry %d\n", ry) | ||||
|  | ||||
| 		img = si.SubImage(image.Rect(int(xo), int(yo), int(xo+w), int(yo+w))) | ||||
| 		img = blowUp(img) | ||||
|  | ||||
| 		var buf bytes.Buffer | ||||
| 		if err := png.Encode(&buf, img); err != nil { | ||||
| 			http.ServeFile(rw, r, filepath.Join(mapDir, baseTile)) | ||||
| 			return | ||||
| 		} | ||||
| 		b := buf.Bytes() | ||||
| 		rw.Header().Set("Content-Type", "image/png") | ||||
| 		// Don't set the content length to use chunked mode. | ||||
| 		// rw.Header().Set("Content-Length", strconv.Itoa(len(b))) | ||||
| 		if _, err := rw.Write(b); err != nil { | ||||
| 			log.Printf("WARM: sending image failed: %s", err) | ||||
| 		if etag == "" { | ||||
| 			if etag, err = createETag(baseTile); err != nil { | ||||
| 				log.Printf("Cannot create ETag: %s", baseTile) | ||||
| 			} else { | ||||
| 				rw.Header().Set("ETag", etag) | ||||
| 			} | ||||
| 		} else { | ||||
| 			rw.Header().Set("ETag", etag) | ||||
| 		} | ||||
|  | ||||
| 		if err = png.Encode(rw, img); err != nil { | ||||
| 			log.Printf("WARN: encoding image failed: %s", err) | ||||
| 			return | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
|   | ||||
		Посилання в новій задачі
	
	Block a user