// Initialize loads the previous state of the statistics func Initialize() error { logger.Debug("server", "Started Initialize on statistics object") var cfiles uint64 var csize uint64 var err error err = database.DB.View(func(tx *bolt.Tx) error { S.Decode(tx.Bucket([]byte("statistics")).Get([]byte("main"))) return tx.Bucket([]byte("resources")).ForEach(func(k, v []byte) error { r := &Resource{} if err = r.Decode(v); err != nil { return err } csize += uint64(r.Size) cfiles++ return nil }) }) if err != nil { logger.Err("server", "Could not initialize statistics") return err } S.CurrentFiles = cfiles S.CurrentSize = csize logger.Info("server", fmt.Sprintf("Total %d (%s)", S.TotalFiles, utils.HumanBytes(S.TotalSize))) logger.Info("server", fmt.Sprintf("Current %d (%s)", cfiles, utils.HumanBytes(csize))) logger.Debug("server", "Done Initialize on statistics object") return err }
// Index handles the main page func Index(c *gin.Context) { logger.InfoC(c, "server", "GET /") data := gin.H{ "fulldoc": conf.C.FullDoc, "size_limit": utils.HumanBytes(uint64(conf.C.SizeLimit * utils.MegaByte)), "sensitive_mode": conf.C.SensitiveMode, } if conf.C.Stats { data["total_size"] = utils.HumanBytes(models.S.TotalSize) data["total_files"] = models.S.TotalFiles } c.HTML(http.StatusOK, "index.html", data) }
// LogDeleted logs when a file is deleted (due to a one-time view) func (r Resource) LogDeleted(c *gin.Context) { e := fmt.Sprintf("%sDeleted%s %s - %s", logger.Red, logger.Reset, r.Key, utils.HumanBytes(uint64(r.Size))) if r.Once { e += " - once" } logger.InfoC(c, "server", e) }
// Delete deletes a resource in database and on disk func (r Resource) Delete() error { logger.Debug("server", "Started Delete on Resource", r.Key) var err error err = database.DB.Update(func(tx *bolt.Tx) error { if err = tx.Bucket([]byte("resources")).Delete([]byte(r.Key)); err != nil { return err } S.CurrentFiles-- S.CurrentSize -= uint64(r.Size) var data []byte if data, err = S.Encode(); err != nil { return err } return tx.Bucket([]byte("statistics")).Put([]byte("main"), data) }) if err != nil { return err } err = os.Remove(path.Join(conf.C.UploadDir, r.Key)) logger.Debug("server", "Done Delete on Resource", r.Key) logger.Debug("server", fmt.Sprintf("Serving %d (%s) files", S.CurrentFiles, utils.HumanBytes(S.CurrentSize))) return err }
// HeadC handles the head request for an encryptd file func HeadC(c *gin.Context) { var err error id := c.Param("uniuri") key := c.Param("key") re := models.Resource{} if err = re.Get(id); err != nil { logger.InfoC(c, "server", "Not found", id) c.AbortWithStatus(http.StatusNotFound) return } if re.Key == "" { logger.InfoC(c, "server", "Not found", id) c.AbortWithStatus(http.StatusNotFound) return } logger.InfoC(c, "server", "Head", fmt.Sprintf("%s - %s", re.Key, utils.HumanBytes(uint64(re.Size)))) f, err := os.Open(path.Join(conf.C.UploadDir, re.Key)) if err != nil { logger.ErrC(c, "server", fmt.Sprintf("Couldn't open %s", re.Key), err) c.AbortWithStatus(http.StatusInternalServerError) return } block, err := aes.NewCipher([]byte(key)) if err != nil { logger.ErrC(c, "server", "Couldn't create AES cipher", err) c.String(http.StatusInternalServerError, "Something went wrong on the server. Try again later.") c.AbortWithStatus(http.StatusInternalServerError) return } var iv [aes.BlockSize]byte stream := cipher.NewCFBDecrypter(block, iv[:]) reader := &cipher.StreamReader{S: stream, R: f} c.Header("Content-Disposition", "filename=\""+re.Name+"\"") io.Copy(c.Writer, reader) }
// Monit monitors the database and file system to remove old entries func Monit() { logger.Info("monitoring", "Started Monitoring") var err error tc := time.NewTicker(1 * time.Minute) for { logger.Debug("monitoring", "Started Monit on Resources") now := time.Now() found := 0 var sizeRemoved uint64 err = database.DB.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("resources")) err = b.ForEach(func(k, v []byte) error { var err error r := &models.Resource{} if err = r.Decode(v); err != nil { return err } if r.DeleteAt.Before(now) { if err = b.Delete([]byte(r.Key)); err != nil { logger.Err("monitoring", "While deleting entry (skipped)", err) } else { if err = os.Remove(path.Join(conf.C.UploadDir, r.Key)); err != nil { logger.Err("monitoring", "While deleting file (skipped)", err) } else { found++ sizeRemoved += uint64(r.Size) } } } return nil }) if err != nil { return err } if found > 0 { var data []byte models.S.CurrentFiles -= uint64(found) models.S.CurrentSize -= sizeRemoved if data, err = models.S.Encode(); err != nil { return err } return tx.Bucket([]byte("statistics")).Put([]byte("main"), data) } return nil }) if err != nil { logger.Err("monitoring", "While monitoring", err) } else { if found > 0 { logger.Info("monitoring", fmt.Sprintf("Deleted %d entries and files in %s", found, time.Since(now))) logger.Info("monitoring", fmt.Sprintf("Serving %d (%s) files", models.S.CurrentFiles, utils.HumanBytes(models.S.CurrentSize))) } logger.Debug("monitoring", fmt.Sprintf("Serving %d (%s) files", models.S.CurrentFiles, utils.HumanBytes(models.S.CurrentSize))) } logger.Debug("monitoring", fmt.Sprintf("Done Monit on Resources (%s)", time.Since(now))) <-tc.C } }