package main import ( "bytes" "flag" "fmt" "image" "image/color" "image/png" "log" "net/http" "os" "sync" "time" ) var port = flag.Int("port", 8000, "port") type Now struct { lastUpdated time.Time cacheWindow time.Duration buffer *bytes.Buffer lock sync.RWMutex } func NewNow(d time.Duration) *Now { return &Now{ cacheWindow: d, buffer: &bytes.Buffer{}, } } func (n *Now) ServeHTTP(w http.ResponseWriter, req *http.Request) { log.Printf("%+v", req.RemoteAddr) if time.Now().After(n.lastUpdated.Add(n.cacheWindow)) { log.Println("updating image") n.Update() n.lastUpdated = time.Now() } n.lock.RLock() w.Write(n.buffer.Bytes()) n.lock.RUnlock() } func (n *Now) Update() { resp, err := http.Get("http://imgs.xkcd.com/comics/now.png") if err != nil { log.Fatal(err) } defer resp.Body.Close() src, err := png.Decode(resp.Body) if err != nil { log.Fatal(err) } bounds := src.Bounds() dest := image.NewNRGBA(bounds) for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { r, g, b, _ := src.At(x, y).RGBA() if r == 0xFFFF && g == 0xFFFF && b == 0xFFFF { dest.Set(x, y, color.NRGBA{0, 0, 0, 0}) } else { dest.Set(x, y, src.At(x, y)) } } } n.lock.Lock() png.Encode(n.buffer, dest) n.lock.Unlock() } func main() { flag.Parse() hostname, err := os.Hostname() if err != nil { log.Fatal("problem getting hostname:", err) } log.Printf("serving on: http://%s:%d/", hostname, *port) addr := fmt.Sprintf(":%d", *port) http.Handle("/", NewNow(15*time.Minute)) err = http.ListenAndServe(addr, nil) if err != nil { log.Fatal(err) } }