mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-12-23 16:50:18 +01:00
Generate ETags and encode PNG directly to response stream.
This commit is contained in:
parent
3943c7cc5d
commit
c42be33ba9
@ -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
|
||||
}
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user