package sfive import ( "encoding/json" "fmt" "io/ioutil" "net/http" "os" "strconv" "time" "github.com/zenazn/goji" "github.com/zenazn/goji/web" ) func hello(c web.C, w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"]) } func (self StatsSinkServer) getTagList(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "tags" values, err := self.store.GetTags() if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(DataContainer{values}) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func (self StatsSinkServer) getSourcesList(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "sources" values, err := self.store.GetSources() if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(DataContainer{values}) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func (self StatsSinkServer) getSource(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "source" id, err := strconv.ParseInt(c.URLParams["id"], 10, 64) if err != nil { http.Error(w, fmt.Sprintf("invalid id: %s: %v", resourceName, err), http.StatusBadRequest) return } value, err := self.store.GetSource(int(id)) if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(value) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func getFilter(r *http.Request) (filter StatsFilter) { from := r.FormValue("from") if from != "" { fromT, err := time.Parse(time.RFC3339, from) if err == nil { filter.start = &fromT } } to := r.FormValue("to") if to != "" { toT, err := time.Parse(time.RFC3339, to) if err == nil { filter.end = &toT } } hostname := r.FormValue("hostname") if hostname != "" { filter.hostname = &hostname } contentId := r.FormValue("contentId") if contentId != "" { filter.contentId = &contentId } format := r.FormValue("format") if format != "" { filter.format = &format } quality := r.FormValue("quality") if quality != "" { filter.quality = &quality } return } func (self StatsSinkServer) getUpdateList(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "updates" filter := getFilter(r) values, err := self.getUpdatesInvoke(&filter) if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(DataContainer{values}) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func (self StatsSinkServer) getUpdate(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "update" id, err := strconv.ParseInt(c.URLParams["id"], 10, 64) if err != nil { http.Error(w, fmt.Sprintf("invalid id: %s: %v", resourceName, err), http.StatusBadRequest) return } value, err := self.store.GetUpdate(int(id)) if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(value) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func (self StatsSinkServer) postUpdate(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "update" decoder := NewPlainDecoder() buffer, err := ioutil.ReadAll(r.Body) if err != nil { s5l.Printf("web: failed to read post value: %v\n", err) http.Error(w, fmt.Sprintf("failed reading : %s: %v", resourceName, err), http.StatusBadRequest) return } container := StatisticsDataContainer{} err = json.Unmarshal(buffer, &container) if err == nil { token := appendManyToken{ data: container.Data, response: make(chan bool, 2)} defer close(token.response) self.appendManyData <- token success := <-token.response if !success { http.Error(w, "failed to store data", http.StatusInternalServerError) } return } // else try single value data, err := decoder.Decode(buffer) if err != nil { s5l.Printf("web: failed to decode: %v\n", err) http.Error(w, fmt.Sprintf("failed decoding %s: %v", resourceName, err), http.StatusBadRequest) return } self.appendData <- data // TODO send response channel, wait for OK } func (self StatsSinkServer) getLastUpdateIdForUuid(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "lastupdateid" id := c.URLParams["id"] value, err := self.store.GetLastUpdateForUuid(id) if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } if value != nil { fmt.Fprintf(w, "%d", *value) } } func (self StatsSinkServer) getStats(c web.C, w http.ResponseWriter, r *http.Request) { const resourceName = "stats" filter := getFilter(r) values, err := self.getStatsInvoke(&filter) if err != nil { http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) return } jsonString, err := json.Marshal(values) if err != nil { http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%s", jsonString) } func (self StatsSinkServer) ServeWeb(vizAppLocation string) { if _, err := os.Stat(vizAppLocation); err != nil { if os.IsNotExist(err) { s5l.Panicf("web: viz-app at %s does not exist.", vizAppLocation) } else { s5l.Printf("web: failed to stat %s: %v", vizAppLocation, err) } } goji.Get("/hello/:name", hello) goji.Get("/tags", self.getTagList) goji.Get("/sources", self.getSourcesList) goji.Get("/sources/:id", self.getSource) goji.Get("/updates", self.getUpdateList) goji.Get("/updates/:id", self.getUpdate) goji.Post("/updates", self.postUpdate) goji.Get("/lastupdate/:id", self.getLastUpdateIdForUuid) goji.Get("/stats", self.getStats) goji.Handle("/viz/*", http.StripPrefix("/viz/", http.FileServer(http.Dir(vizAppLocation)))) goji.Serve() }