aboutsummaryrefslogblamecommitdiff
path: root/quotas.go
blob: 9a2e426005667724cdd1146790732f4cc5487d3e (plain) (tree)



























































                                                                         
                                                                                 


                                       
                                                                                        













                                                                             






































































                                                                 
package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/go-ldap/ldap/v3"
	garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
)

const (
	// --- Default Quota Values ---
	QUOTA_WEBSITE_SIZE_DEFAULT = 1024 * 1024 * 50 // 50MB
	QUOTA_WEBSITE_SIZE_BURSTED = 1024 * 1024 * 200 // 200MB
	QUOTA_WEBSITE_OBJECTS = 10000 // 10k objects
	QUOTA_WEBSITE_COUNT = 5 // 5 buckets

	// --- Per-user overridable fields ---
	FIELD_QUOTA_WEBSITE_SIZE_BURSTED = "quota_website_size_bursted"
        FIELD_QUOTA_WEBSITE_COUNT = "quota_website_count"
)

type UserQuota struct {
	WebsiteCount int64
	WebsiteSizeDefault int64
	WebsiteSizeBursted int64
	WebsiteObjects int64
}

func NewUserQuota() *UserQuota {
	return &UserQuota {
		WebsiteCount: QUOTA_WEBSITE_COUNT,
		WebsiteSizeDefault: QUOTA_WEBSITE_SIZE_DEFAULT,
		WebsiteSizeBursted: QUOTA_WEBSITE_SIZE_BURSTED,
		WebsiteObjects: QUOTA_WEBSITE_OBJECTS,
	}
}

var (
	ErrQuotaEmpty = fmt.Errorf("No quota is defined for this entry")
	ErrQuotaInvalid = fmt.Errorf("The defined quota can't be parsed")
)

func entryToQuota(entry *ldap.Entry, field string) (int64, error) {
	f := entry.GetAttributeValue(field)
	if f == "" {
		return -1, ErrQuotaEmpty
	}

	q, err := strconv.ParseInt(f, 10, 64)
	if err != nil {
		return -1, errors.Join(ErrQuotaInvalid, err)
	}
	return q, nil
}

func NewUserQuotaFromEntry(entry *ldap.Entry) *UserQuota {
	quotas := NewUserQuota()

	if q, err := entryToQuota(entry, FIELD_QUOTA_WEBSITE_COUNT); err == nil {
		quotas.WebsiteCount = q
	}

	if q, err := entryToQuota(entry, FIELD_QUOTA_WEBSITE_SIZE_BURSTED); err == nil {
		quotas.WebsiteSizeBursted = q
	}

	return quotas
}

func (q *UserQuota) DefaultWebsiteQuota() *garage.UpdateBucketRequestQuotas {
	qr := garage.NewUpdateBucketRequestQuotas()

	qr.SetMaxSize(q.WebsiteSizeDefault) 
	qr.SetMaxObjects(q.WebsiteSizeBursted)

	return qr
}

func (q *UserQuota) WebsiteSizeAdjust(sz int64) int64 {
	if sz < q.WebsiteSizeDefault {
		return q.WebsiteSizeDefault 
	} else if sz > q.WebsiteSizeBursted {
		return q.WebsiteSizeBursted
	} else {
		return sz
	}
}

func (q *UserQuota) WebsiteObjectAdjust(objs int64) int64 {
	if objs > q.WebsiteObjects || objs <= 0 {
		return q.WebsiteObjects
	} else {
		return objs
	}
}

func (q *UserQuota) WebsiteSizeBurstedPretty() string {
	return prettyValue(q.WebsiteSizeBursted)
}

// --- A quota stat we can use
type QuotaStat struct {
	Current   int64
	Max	  int64
	Ratio	  float64
	Burstable bool
}
func NewQuotaStat(current, max int64, burstable bool) QuotaStat {
	return QuotaStat {
		Current: current,
		Max: max,
		Ratio: float64(current) / float64(max),
		Burstable: burstable,
	}
}
func (q *QuotaStat) IsFull() bool {
	return q.Current >= q.Max
}
func (q *QuotaStat) Percent() int64 {
	return int64(q.Ratio * 100)
}

func (q *QuotaStat) PrettyCurrent() string {
	return prettyValue(q.Current)
}
func (q *QuotaStat) PrettyMax() string {
	return prettyValue(q.Max)
}

func prettyValue(v int64) string {
	if v < 1024 {
		return fmt.Sprintf("%d octets", v)
	}
	v = v / 1024
	if v < 1024 {
		return fmt.Sprintf("%d kio", v)
	}
	v = v / 1024
	if v < 1024 {
		return fmt.Sprintf("%d Mio", v)
	}
	v = v / 1024	
	if v < 1024 {
		return fmt.Sprintf("%d Gio", v)
	}
	v = v / 1024
	return fmt.Sprintf("%d Tio", v)
}