aboutsummaryrefslogblamecommitdiff
path: root/website.go
blob: c06ccbc289af123c60aba2b53fdca491fe2336d1 (plain) (tree)


















































































































































































































                                                                                                                                                         
package main

import (
	"fmt"
	"sort"
	"strings"
	garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
)

var (
	ErrWebsiteNotFound = fmt.Errorf("Website not found")
	ErrFetchBucketInfo = fmt.Errorf("Failed to fetch bucket information")
	ErrWebsiteQuotaReached = fmt.Errorf("Can't create additional websites, quota reached")
	ErrEmptyBucketName = fmt.Errorf("You can't create a website with an empty name")
	ErrCantCreateBucket = fmt.Errorf("Can't create this bucket. Maybe another bucket already exists with this name or you have an invalid character")
	ErrCantAllowKey = fmt.Errorf("Can't allow given key on the target bucket")
	ErrCantConfigureBucket = fmt.Errorf("Unable to configure the bucket (activating website, adding quotas, etc.)")
)

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)
}

type WebsiteId struct {
	Pretty string
	Internal string
	Alt []string
	Expanded bool
	Url string

}
func NewWebsiteId(id string, aliases []string) *WebsiteId {
	pretty := id
	var alt []string
	if len(aliases) > 0 {
		pretty = aliases[0]
		alt = aliases[1:]
	}
	expanded := strings.Contains(pretty, ".")

	url := pretty
	if !expanded {
		url = fmt.Sprintf("%s.web.deuxfleurs.fr", pretty)
	}

	return &WebsiteId { pretty, id, alt, expanded, url }
}
func NewWebsiteIdFromBucketInfo(binfo *garage.BucketInfo) *WebsiteId {
	return NewWebsiteId(*binfo.Id, binfo.GlobalAliases)
}

type WebsiteController struct {
	User *LoggedUser
	WebsiteIdx map[string]*WebsiteId
	PrettyList []string
	WebsiteCount QuotaStat
}

func NewWebsiteController(user *LoggedUser) (*WebsiteController, error) {
	idx := map[string]*WebsiteId{}
	var wlist []string

	keyInfo, err := user.S3KeyInfo()
	if err != nil {
		return nil, err
	}

	for _, bckt := range(keyInfo.Buckets) {
		if len(bckt.GlobalAliases) > 0 {
			wid := NewWebsiteId(*bckt.Id, bckt.GlobalAliases)
			idx[wid.Pretty] = wid
			wlist = append(wlist, wid.Pretty)
		}
	}
	sort.Strings(wlist)

	maxW := user.Quota.WebsiteCount
	quota := NewQuotaStat(int64(len(wlist)), maxW, true)

	return &WebsiteController { user, idx, wlist, quota }, nil
}

func (w *WebsiteController) List() []*WebsiteId {
	r := make([]*WebsiteId, 0, len(w.PrettyList))
	for _, k := range w.PrettyList {
		r = append(r, w.WebsiteIdx[k]) 
	}
	return r
}

func (w *WebsiteController) Inspect(pretty string) (*WebsiteView, error) {
	website, ok := w.WebsiteIdx[pretty]
	if !ok {
		return nil, ErrWebsiteNotFound
	}

	binfo, err := grgGetBucket(website.Internal)
	if err != nil {
		return nil, ErrFetchBucketInfo
	}

	return NewWebsiteView(binfo), nil
}

func (w *WebsiteController) Patch(patch *WebsitePatch) (*WebsiteView, error) {
	return nil, nil
}

func (w *WebsiteController) Create(pretty string) (*WebsiteView, error) {
	if pretty == "" {
		return nil, ErrEmptyBucketName
	}

	if w.WebsiteCount.IsFull() {
		return nil, ErrWebsiteQuotaReached
	}

	binfo, err := grgCreateBucket(pretty)
	if err != nil {
		return nil, ErrCantCreateBucket
	}

	s3key, err := w.User.S3KeyInfo()
	if err != nil {
		return nil, err
	}

	binfo, err = grgAllowKeyOnBucket(*binfo.Id, *s3key.AccessKeyId)
	if err != nil {
		return nil, ErrCantAllowKey
	}

	qr := w.User.Quota.DefaultWebsiteQuota()
	wr := allowWebsiteDefault()

	ur := garage.NewUpdateBucketRequest()
	ur.SetWebsiteAccess(*wr)
	ur.SetQuotas(*qr)


	binfo, err = grgUpdateBucket(*binfo.Id, ur)
	if err != nil {
		return nil, ErrCantConfigureBucket
	}

	return NewWebsiteView(binfo), nil
}


type WebsiteView struct {
	Name *WebsiteId
	Size QuotaStat
	Files QuotaStat
}

func NewWebsiteView(binfo *garage.BucketInfo) *WebsiteView {
	q := binfo.GetQuotas()

	wid := NewWebsiteIdFromBucketInfo(binfo)
	size := NewQuotaStat(*binfo.Bytes, (&q).GetMaxSize(), true)
	objects := NewQuotaStat(*binfo.Objects, (&q).GetMaxObjects(), false)
	return &WebsiteView { wid, size, objects }
}

type WebsitePatch struct {
	size int64
}