// Copyright 2014 by Sascha L. Teichmann // Use of this source code is governed by the MIT license // that can be found in the LICENSE file. package main import ( "encoding/json" "log" "net/http" "path/filepath" "sync" "bitbucket.org/s_l_teichmann/mtredisalize/common" ) type tileUpdater struct { changes map[xz]bool mapDir string redisAddress string colors *common.Colors workers int cond *sync.Cond mu sync.Mutex } type xz struct { X int16 Z int16 } func (c xz) quantize() xz { return xz{X: (c.X - -1933) / 16, Z: (c.Z - -1933) / 16} } func newTileUpdater(mapDir, redisAddress string, colors *common.Colors, workers int) *tileUpdater { tu := tileUpdater{ mapDir: mapDir, redisAddress: redisAddress, changes: map[xz]bool{}, colors: colors, workers: workers} tu.cond = sync.NewCond(&tu.mu) return &tu } func (tu *tileUpdater) ServeHTTP(rw http.ResponseWriter, r *http.Request) { var err error var newChanges []xz decoder := json.NewDecoder(r.Body) if err = decoder.Decode(&newChanges); err != nil { log.Printf("WARN: JSON document broken: %s", err) http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } if len(newChanges) > 0 { tu.cond.L.Lock() for _, c := range newChanges { tu.changes[c.quantize()] = true } tu.cond.L.Unlock() tu.cond.Signal() } rw.WriteHeader(http.StatusOK) } func (tu *tileUpdater) doUpdates() { for { var changes map[xz]bool tu.cond.L.Lock() for len(tu.changes) == 0 { tu.cond.Wait() } changes = tu.changes tu.changes = map[xz]bool{} tu.cond.L.Unlock() baseDir := filepath.Join(tu.mapDir, "8") jobs := make(chan xz) var done sync.WaitGroup for i := 0; i < tu.workers; i++ { var client *common.RedisClient var err error if client, err = common.NewRedisClient("tcp", tu.redisAddress); err != nil { log.Printf("WARN: Cannot connect to redis server: %s", err) continue } btc := common.NewBaseTileCreator(client, tu.colors, baseDir, true) done.Add(1) go updateBaseTiles(jobs, btc, &done) } for c, _ := range changes { log.Printf("job: %+v", c) jobs <- c } done.Wait() } return } func updateBaseTiles(jobs chan xz, btc *common.BaseTileCreator, done *sync.WaitGroup) { for job := range jobs { x := job.X*16 + -1933 - 1 z := job.Z*16 + -1933 - 1 log.Printf("%d/%d %d/%d", x, z, job.X, job.Z) if err := btc.CreateTile(x, z, int(job.X), int(job.Z)); err != nil { log.Printf("WARN: create tile failed: %s", err) } } btc.Close() // TODO: Keep redis connection open to update the pyramid tiles. done.Done() }