package main import ( "crypto/sha1" "encoding/hex" "encoding/json" "errors" "io" "io/ioutil" "net/http" "os" "regexp" "sort" "strconv" ) type Storage struct { Path string } var ( tokenPattern = regexp.MustCompile(`[a-fA-F0-9]{10,}`) ) func (s *Storage) MustInit() error { os.Mkdir(s.Path, 0755) os.Mkdir(s.Path+"/battles", 0755) os.Mkdir(s.Path+"/tokens", 0700) return nil } func (s *Storage) CanPost(token string) (bool, error) { if !tokenPattern.MatchString(token) { return false, errors.New("invalid token") } _, err := os.Stat(s.Path + "/tokens/" + token) return err == nil, nil } func (b *Battle) CalculateHash() { hash := sha1.New() killmails := b.Killmails sort.Slice(killmails, func(lhs, rhs int) bool { return killmails[lhs].Id < killmails[rhs].Id }) for _, km := range killmails { io.WriteString(hash, strconv.FormatUint(km.Id, 10)) } sum := hash.Sum(nil) b.Id = hex.EncodeToString(sum[:]) } func (s *Storage) LoadBattle(battle *Battle) error { stream, err := os.Open(s.Path + "/battles/" + battle.Id) if err != nil { return err } decoder := json.NewDecoder(stream) if err = decoder.Decode(battle); err != nil { return err } return nil } func (s *Storage) AddBattle(battle *Battle) error { if len(battle.Killmails) < 1 { return errors.New("missing killmails") } battle.CalculateHash() data, err := json.Marshal(battle) if err != nil { return err } return ioutil.WriteFile(s.Path+"/battles/"+battle.Id, data, 0644) } func (s *Storage) ServeBattle(id string, w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") http.ServeFile(w, r, s.Path+"/battles/"+id) } func (s *Storage) ListRecentBattles(count int) ([]Battle, error) { files, err := ioutil.ReadDir(s.Path + "/battles") if err != nil { return nil, err } sort.Slice(files, func(lhs, rhs int) bool { return files[lhs].ModTime().After(files[rhs].ModTime()) }) battles := make([]Battle, 0, count) for i := 0; i < count && i < len(files); i++ { battle := Battle{Id: files[i].Name(), LastModified: files[i].ModTime()} if err = s.LoadBattle(&battle); err != nil { return nil, err } battles = append(battles, battle) } return battles, nil }