mirror of
https://github.com/haiwen/seafile-server.git
synced 2025-07-20 10:09:55 +00:00
174 lines
3.6 KiB
Go
174 lines
3.6 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"fmt"
|
||
|
"github.com/haiwen/seafile-server/fileserver/repomgr"
|
||
|
"gopkg.in/ini.v1"
|
||
|
"path/filepath"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// InfiniteQuota indicates that the quota is unlimited.
|
||
|
const (
|
||
|
InfiniteQuota = -2
|
||
|
)
|
||
|
|
||
|
func checkQuota(repoID string, delta int64) (int, error) {
|
||
|
if repoID == "" {
|
||
|
err := fmt.Errorf("bad argumets")
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
vInfo, err := repomgr.GetVirtualRepoInfo(repoID)
|
||
|
if err != nil {
|
||
|
err := fmt.Errorf("failed to get virtual repo: %v", err)
|
||
|
return -1, err
|
||
|
}
|
||
|
rRepoID := repoID
|
||
|
if vInfo != nil {
|
||
|
rRepoID = vInfo.OriginRepoID
|
||
|
}
|
||
|
|
||
|
user, err := repomgr.GetRepoOwner(rRepoID)
|
||
|
if err != nil {
|
||
|
err := fmt.Errorf("failed to get repo owner: %v", err)
|
||
|
return -1, err
|
||
|
}
|
||
|
if user == "" {
|
||
|
err := fmt.Errorf("repo %s has no owner", repoID)
|
||
|
return -1, err
|
||
|
}
|
||
|
quota, err := getUserQuota(user)
|
||
|
if err != nil {
|
||
|
err := fmt.Errorf("failed to get user quota: %v", err)
|
||
|
return -1, err
|
||
|
}
|
||
|
|
||
|
if quota == InfiniteQuota {
|
||
|
return 0, nil
|
||
|
}
|
||
|
usage, err := getUserUsage(user)
|
||
|
if err != nil || usage < 0 {
|
||
|
err := fmt.Errorf("failed to get user usage: %v", err)
|
||
|
return -1, err
|
||
|
}
|
||
|
usage += delta
|
||
|
if usage >= quota {
|
||
|
return 1, nil
|
||
|
}
|
||
|
|
||
|
return 0, nil
|
||
|
}
|
||
|
|
||
|
func getUserQuota(user string) (int64, error) {
|
||
|
var quota int64
|
||
|
sqlStr := "SELECT quota FROM UserQuota WHERE user=?"
|
||
|
row := seafileDB.QueryRow(sqlStr, user)
|
||
|
if err := row.Scan("a); err != nil {
|
||
|
if err != sql.ErrNoRows {
|
||
|
return -1, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if quota <= 0 {
|
||
|
quota = getDefaultQuota()
|
||
|
}
|
||
|
|
||
|
return quota, nil
|
||
|
}
|
||
|
|
||
|
// Storage unit.
|
||
|
const (
|
||
|
KB = 1000
|
||
|
MB = 1000000
|
||
|
GB = 1000000000
|
||
|
TB = 1000000000000
|
||
|
)
|
||
|
|
||
|
func getDefaultQuota() int64 {
|
||
|
seafileConfPath := filepath.Join(absDataDir, "seafile.conf")
|
||
|
config, err := ini.Load(seafileConfPath)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
var quota int64
|
||
|
section, err := config.GetSection("quota")
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
key, err := section.GetKey("default")
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quotaStr := key.String()
|
||
|
quota = parseQuota(quotaStr)
|
||
|
|
||
|
return quota
|
||
|
}
|
||
|
|
||
|
func parseQuota(quotaStr string) int64 {
|
||
|
var quota int64
|
||
|
var multiplier int64 = GB
|
||
|
if end := strings.Index(quotaStr, "kb"); end > 0 {
|
||
|
multiplier = KB
|
||
|
quotaInt, err := strconv.ParseInt(quotaStr[:end], 10, 0)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quota = quotaInt * multiplier
|
||
|
} else if end := strings.Index(quotaStr, "mb"); end > 0 {
|
||
|
multiplier = MB
|
||
|
quotaInt, err := strconv.ParseInt(quotaStr[:end], 10, 0)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quota = quotaInt * multiplier
|
||
|
} else if end := strings.Index(quotaStr, "gb"); end > 0 {
|
||
|
multiplier = GB
|
||
|
quotaInt, err := strconv.ParseInt(quotaStr[:end], 10, 0)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quota = quotaInt * multiplier
|
||
|
} else if end := strings.Index(quotaStr, "tb"); end > 0 {
|
||
|
multiplier = TB
|
||
|
quotaInt, err := strconv.ParseInt(quotaStr[:end], 10, 0)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quota = quotaInt * multiplier
|
||
|
} else {
|
||
|
quotaInt, err := strconv.ParseInt(quotaStr, 10, 0)
|
||
|
if err != nil {
|
||
|
return InfiniteQuota
|
||
|
}
|
||
|
quota = quotaInt * multiplier
|
||
|
}
|
||
|
|
||
|
return quota
|
||
|
}
|
||
|
|
||
|
func getUserUsage(user string) (int64, error) {
|
||
|
var usage sql.NullInt64
|
||
|
sqlStr := "SELECT SUM(size) FROM " +
|
||
|
"RepoOwner o LEFT JOIN VirtualRepo v ON o.repo_id=v.repo_id, " +
|
||
|
"RepoSize WHERE " +
|
||
|
"owner_id=? AND o.repo_id=RepoSize.repo_id " +
|
||
|
"AND v.repo_id IS NULL"
|
||
|
|
||
|
row := seafileDB.QueryRow(sqlStr, user)
|
||
|
if err := row.Scan(&usage); err != nil {
|
||
|
if err != sql.ErrNoRows {
|
||
|
return -1, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if usage.Valid {
|
||
|
return usage.Int64, nil
|
||
|
}
|
||
|
|
||
|
return 0, nil
|
||
|
}
|