package contented import ( "encoding/json" "errors" "fmt" "log" "net/http" "os" "time" "github.com/speps/go-hashids" bolt "go.etcd.io/bbolt" ) const ( hashIdSalt = "contented" hashIdMinLength = 2 ) type Metadata struct { FileHash string FileSize int64 UploadTime time.Time UploadIP string Filename string MimeType string } func (this *Server) Metadata(fileID string) (*Metadata, error) { var m Metadata err := this.db.View(func(tx *bolt.Tx) error { content := tx.Bucket(this.metadataBucket).Get([]byte(fileID)) if len(content) == 0 { return os.ErrNotExist } return json.Unmarshal(content, &m) }) if err != nil { return nil, err } return &m, nil } func idToString(v uint64) string { hd := hashids.NewData() hd.Salt = hashIdSalt hd.MinLength = hashIdMinLength h := hashids.NewWithData(hd) s, _ := h.EncodeInt64([]int64{int64(v)}) return s } func (this *Server) AddMetadata(m Metadata) (string, error) { jb, err := json.Marshal(m) if err != nil { return "", err } var shortRef string = "" err = this.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(this.metadataBucket) seq, err := b.NextSequence() if err != nil { return fmt.Errorf("NextSequence: %w", err) } shortRef = idToString(seq) if b.Get([]byte(shortRef)) != nil { return fmt.Errorf("Next bucket sequence %d creates colliding ID %s", seq, shortRef) } return b.Put([]byte(shortRef), jb) }) if err != nil { return "", err } if shortRef == "" { return "", errors.New("Invalid URL generated") } return shortRef, nil } func (this *Server) handleInformation(w http.ResponseWriter, fileID string) { m, err := this.Metadata(fileID) if err != nil { if os.IsNotExist(err) { http.Error(w, "Not found", 404) return } log.Println(err.Error()) http.Error(w, "Internal error", 500) return } this.serveJsonObject(w, m) }