func (h *HTTP) mirrorStatsHandler(w http.ResponseWriter, r *http.Request, ctx *Context) { rconn := h.redis.Get() defer rconn.Close() // Get all mirrors ID mirrorsIDs, err := redis.Strings(rconn.Do("LRANGE", "MIRRORS", "0", "-1")) if err != nil { http.Error(w, "Cannot fetch the list of mirrors", http.StatusInternalServerError) return } // <dlstats> rconn.Send("MULTI") // Get all mirrors stats for _, id := range mirrorsIDs { today := time.Now().Format("2006_01_02") rconn.Send("HGET", "STATS_MIRROR_"+today, id) rconn.Send("HGET", "STATS_MIRROR_BYTES_"+today, id) } stats, err := redis.Values(rconn.Do("EXEC")) if err != nil { http.Error(w, "Cannot fetch stats", http.StatusInternalServerError) return } var results []MirrorStats var index int64 for _, id := range mirrorsIDs { var downloads int64 if v, _ := redis.String(stats[index], nil); v != "" { downloads, _ = strconv.ParseInt(v, 10, 64) } var bytes int64 if v, _ := redis.String(stats[index+1], nil); v != "" { bytes, _ = strconv.ParseInt(v, 10, 64) } s := MirrorStats{ ID: id, Downloads: downloads, Bytes: bytes, } results = append(results, s) index += 2 } sort.Sort(ByDownloadNumbers{results}) // </dlstats> // <map> var mlist []mirrors.Mirror mlist = make([]mirrors.Mirror, 0, len(mirrorsIDs)) for _, mirrorID := range mirrorsIDs { var mirror mirrors.Mirror reply, err := redis.Values(rconn.Do("HGETALL", fmt.Sprintf("MIRROR_%s", mirrorID))) if err != nil { continue } if len(reply) == 0 { err = redis.ErrNil continue } err = redis.ScanStruct(reply, &mirror) if err != nil { continue } mirror.CountryFields = strings.Fields(mirror.CountryCodes) mlist = append(mlist, mirror) } // </map> w.Header().Set("Content-Type", "text/html; charset=utf-8") err = ctx.Templates().mirrorstats.ExecuteTemplate(ctx.ResponseWriter(), "base", MirrorStatsPage{results, mlist}) if err != nil { log.Errorf("HTTP error: %s", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } }
func (c *cli) CmdEdit(args ...string) error { cmd := SubCmd("edit", "[IDENTIFIER]", "Edit a mirror") if err := cmd.Parse(args); err != nil { return nil } if cmd.NArg() != 1 { cmd.Usage() return nil } // Find the editor to use editor := os.Getenv("EDITOR") if editor == "" { log.Fatal("Environment variable $EDITOR not set") } // Guess which mirror to use list, err := c.matchMirror(cmd.Arg(0)) if err != nil { return err } if len(list) == 0 { fmt.Fprintf(os.Stderr, "No match for %s\n", cmd.Arg(0)) return nil } else if len(list) > 1 { for _, e := range list { fmt.Fprintf(os.Stderr, "%s\n", e) } return nil } id := list[0] // Connect to the database r := database.NewRedis() conn, err := r.Connect() if err != nil { log.Fatal("Redis: ", err) } defer conn.Close() // Get the mirror information key := fmt.Sprintf("MIRROR_%s", id) m, err := redis.Values(conn.Do("HGETALL", key)) if err != nil { fmt.Fprintf(os.Stderr, "Cannot fetch mirror details: %s\n", err) return err } var mirror mirrors.Mirror err = redis.ScanStruct(m, &mirror) if err != nil { return err } // Generate a yaml configuration string from the struct out, err := yaml.Marshal(mirror) // Open a temporary file f, err := ioutil.TempFile(os.TempDir(), "edit") if err != nil { log.Fatal("Cannot create temporary file:", err) } defer os.Remove(f.Name()) f.WriteString("# You can now edit this mirror configuration.\n" + "# Just save and quit when you're done.\n\n") f.WriteString(string(out)) f.WriteString(fmt.Sprintf("\n%s\n\n%s\n", commentSeparator, mirror.Comment)) f.Close() // Checksum the original file chk, _ := filesystem.HashFile(f.Name()) reopen: // Launch the editor with the filename as first parameter exe := exec.Command(editor, f.Name()) exe.Stdin = os.Stdin exe.Stdout = os.Stdout exe.Stderr = os.Stderr err = exe.Run() if err != nil { log.Fatal(err) } // Read the file back out, err = ioutil.ReadFile(f.Name()) if err != nil { log.Fatal("Cannot read file", f.Name()) } // Checksum the file back and compare chk2, _ := filesystem.HashFile(f.Name()) if chk == chk2 { fmt.Println("Aborted") return nil } var ( yamlstr string = string(out) comment string ) commentIndex := strings.Index(yamlstr, commentSeparator) if commentIndex > 0 { comment = strings.TrimSpace(yamlstr[commentIndex+len(commentSeparator):]) yamlstr = yamlstr[:commentIndex] } // Fill the struct from the yaml err = yaml.Unmarshal([]byte(yamlstr), &mirror) if err != nil { eagain: fmt.Printf("%s\nRetry? [Y/n]", err.Error()) reader := bufio.NewReader(os.Stdin) s, _ := reader.ReadString('\n') switch s[0] { case 'y', 'Y', 10: goto reopen case 'n', 'N': fmt.Println("Aborted") return nil default: goto eagain } } // Reformat contry codes mirror.CountryCodes = strings.Replace(mirror.CountryCodes, ",", " ", -1) ccodes := strings.Fields(mirror.CountryCodes) mirror.CountryCodes = "" for _, c := range ccodes { mirror.CountryCodes += strings.ToUpper(c) + " " } mirror.CountryCodes = strings.TrimRight(mirror.CountryCodes, " ") // Reformat continent code //FIXME sanitize mirror.ContinentCode = strings.ToUpper(mirror.ContinentCode) // Normalize URLs if mirror.HttpURL != "" { mirror.HttpURL = utils.NormalizeURL(mirror.HttpURL) } if mirror.RsyncURL != "" { mirror.RsyncURL = utils.NormalizeURL(mirror.RsyncURL) } if mirror.FtpURL != "" { mirror.FtpURL = utils.NormalizeURL(mirror.FtpURL) } mirror.Comment = comment // Save the values back into redis _, err = conn.Do("HMSET", key, "ID", id, "http", mirror.HttpURL, "rsync", mirror.RsyncURL, "ftp", mirror.FtpURL, "sponsorName", mirror.SponsorName, "sponsorURL", mirror.SponsorURL, "sponsorLogo", mirror.SponsorLogoURL, "adminName", mirror.AdminName, "adminEmail", mirror.AdminEmail, "customData", mirror.CustomData, "continentOnly", mirror.ContinentOnly, "countryOnly", mirror.CountryOnly, "asOnly", mirror.ASOnly, "score", mirror.Score, "latitude", mirror.Latitude, "longitude", mirror.Longitude, "continentCode", mirror.ContinentCode, "countryCodes", mirror.CountryCodes, "asnum", mirror.Asnum, "comment", mirror.Comment, "enabled", mirror.Enabled) if err != nil { log.Fatal("Couldn't save the configuration into redis:", err) } // Publish update database.Publish(conn, database.MIRROR_UPDATE, id) fmt.Println("Mirror edited successfully") return nil }