1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/vcs-all-in-one-lfs-test-server

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
meta_store.go 9 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Shuanglei Tao Отправлено 19.06.2017 11:03 f5f7f0f
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"math"
"sort"
"strconv"
"time"
"github.com/boltdb/bolt"
)
// MetaStore implements a metadata storage. It stores user credentials and Meta information
// for objects. The storage is handled by boltdb.
type MetaStore struct {
db *bolt.DB
}
var (
errNoBucket = errors.New("Bucket not found")
errObjectNotFound = errors.New("Object not found")
errNotOwner = errors.New("Attempt to delete other user's lock")
)
var (
usersBucket = []byte("users")
objectsBucket = []byte("objects")
locksBucket = []byte("locks")
)
// NewMetaStore creates a new MetaStore using the boltdb database at dbFile.
func NewMetaStore(dbFile string) (*MetaStore, error) {
db, err := bolt.Open(dbFile, 0600, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return nil, err
}
db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucketIfNotExists(usersBucket); err != nil {
return err
}
if _, err := tx.CreateBucketIfNotExists(objectsBucket); err != nil {
return err
}
if _, err := tx.CreateBucketIfNotExists(locksBucket); err != nil {
return err
}
return nil
})
return &MetaStore{db: db}, nil
}
// Get retrieves the Meta information for an object given information in
// RequestVars
func (s *MetaStore) Get(v *RequestVars) (*MetaObject, error) {
meta, error := s.UnsafeGet(v)
return meta, error
}
// Get retrieves the Meta information for an object given information in
// RequestVars
// DO NOT CHECK authentication, as it is supposed to have been done before
func (s *MetaStore) UnsafeGet(v *RequestVars) (*MetaObject, error) {
var meta MetaObject
err := s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(objectsBucket)
if bucket == nil {
return errNoBucket
}
value := bucket.Get([]byte(v.Oid))
if len(value) == 0 {
return errObjectNotFound
}
dec := gob.NewDecoder(bytes.NewBuffer(value))
return dec.Decode(&meta)
})
if err != nil {
return nil, err
}
return &meta, nil
}
// Put writes meta information from RequestVars to the store.
func (s *MetaStore) Put(v *RequestVars) (*MetaObject, error) {
// Check if it exists first
if meta, err := s.Get(v); err == nil {
meta.Existing = true
return meta, nil
}
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
meta := MetaObject{Oid: v.Oid, Size: v.Size}
err := enc.Encode(meta)
if err != nil {
return nil, err
}
err = s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(objectsBucket)
if bucket == nil {
return errNoBucket
}
err = bucket.Put([]byte(v.Oid), buf.Bytes())
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return &meta, nil
}
// Delete removes the meta information from RequestVars to the store.
func (s *MetaStore) Delete(v *RequestVars) error {
err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(objectsBucket)
if bucket == nil {
return errNoBucket
}
err := bucket.Delete([]byte(v.Oid))
if err != nil {
return err
}
return nil
})
return err
}
// AddLocks write locks to the store for the repo.
func (s *MetaStore) AddLocks(repo string, l ...Lock) error {
err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(locksBucket)
if bucket == nil {
return errNoBucket
}
var locks []Lock
data := bucket.Get([]byte(repo))
if data != nil {
if err := json.Unmarshal(data, &locks); err != nil {
return err
}
}
locks = append(locks, l...)
sort.Sort(LocksByCreatedAt(locks))
data, err := json.Marshal(&locks)
if err != nil {
return err
}
return bucket.Put([]byte(repo), data)
})
return err
}
// Locks retrieves locks for the repo from the store
func (s *MetaStore) Locks(repo string) ([]Lock, error) {
var locks []Lock
err := s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(locksBucket)
if bucket == nil {
return errNoBucket
}
data := bucket.Get([]byte(repo))
if data != nil {
if err := json.Unmarshal(data, &locks); err != nil {
return err
}
}
return nil
})
return locks, err
}
// FilteredLocks return filtered locks for the repo
func (s *MetaStore) FilteredLocks(repo, path, cursor, limit string) (locks []Lock, next string, err error) {
locks, err = s.Locks(repo)
if err != nil {
return
}
if cursor != "" {
lastSeen := -1
for i, l := range locks {
if l.Id == cursor {
lastSeen = i
break
}
}
if lastSeen > -1 {
locks = locks[lastSeen:]
} else {
err = fmt.Errorf("cursor (%s) not found", cursor)
return
}
}
if path != "" {
var filtered []Lock
for _, l := range locks {
if l.Path == path {
filtered = append(filtered, l)
}
}
locks = filtered
}
if limit != "" {
var size int
size, err = strconv.Atoi(limit)
if err != nil || size < 0 {
locks = make([]Lock, 0)
err = fmt.Errorf("Invalid limit amount: %s", limit)
return
}
size = int(math.Min(float64(size), float64(len(locks))))
if size+1 < len(locks) {
next = locks[size].Id
}
locks = locks[:size]
}
return locks, next, nil
}
// DeleteLock removes lock for the repo by id from the store
func (s *MetaStore) DeleteLock(repo, user, id string, force bool) (*Lock, error) {
var deleted *Lock
err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(locksBucket)
if bucket == nil {
return errNoBucket
}
var locks []Lock
data := bucket.Get([]byte(repo))
if data != nil {
if err := json.Unmarshal(data, &locks); err != nil {
return err
}
}
newLocks := make([]Lock, 0, len(locks))
var lock Lock
for _, l := range locks {
if l.Id == id {
if l.Owner.Name != user && !force {
return errNotOwner
}
lock = l
} else if len(l.Id) > 0 {
newLocks = append(newLocks, l)
}
}
if lock.Id == "" {
return nil
}
deleted = &lock
if len(newLocks) == 0 {
return bucket.Delete([]byte(repo))
}
data, err := json.Marshal(&newLocks)
if err != nil {
return err
}
return bucket.Put([]byte(repo), data)
})
return deleted, err
}
type LocksByCreatedAt []Lock
func (c LocksByCreatedAt) Len() int { return len(c) }
func (c LocksByCreatedAt) Less(i, j int) bool { return c[i].LockedAt.Before(c[j].LockedAt) }
func (c LocksByCreatedAt) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
// Close closes the underlying boltdb.
func (s *MetaStore) Close() {
s.db.Close()
}
// AddUser adds user credentials to the meta store.
func (s *MetaStore) AddUser(user, pass string) error {
err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(usersBucket)
if bucket == nil {
return errNoBucket
}
err := bucket.Put([]byte(user), []byte(pass))
if err != nil {
return err
}
return nil
})
return err
}
// DeleteUser removes user credentials from the meta store.
func (s *MetaStore) DeleteUser(user string) error {
err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(usersBucket)
if bucket == nil {
return errNoBucket
}
err := bucket.Delete([]byte(user))
return err
})
return err
}
// MetaUser encapsulates information about a meta store user
type MetaUser struct {
Name string
}
// Users returns all MetaUsers in the meta store
func (s *MetaStore) Users() ([]*MetaUser, error) {
var users []*MetaUser
err := s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(usersBucket)
if bucket == nil {
return errNoBucket
}
bucket.ForEach(func(k, v []byte) error {
users = append(users, &MetaUser{string(k)})
return nil
})
return nil
})
return users, err
}
// Objects returns all MetaObjects in the meta store
func (s *MetaStore) Objects() ([]*MetaObject, error) {
var objects []*MetaObject
err := s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(objectsBucket)
if bucket == nil {
return errNoBucket
}
bucket.ForEach(func(k, v []byte) error {
var meta MetaObject
dec := gob.NewDecoder(bytes.NewBuffer(v))
err := dec.Decode(&meta)
if err != nil {
return err
}
objects = append(objects, &meta)
return nil
})
return nil
})
return objects, err
}
// AllLocks return all locks in the store, lock path is prepended with repo
func (s *MetaStore) AllLocks() ([]Lock, error) {
var locks []Lock
err := s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(locksBucket)
if bucket == nil {
return errNoBucket
}
bucket.ForEach(func(k, v []byte) error {
var l []Lock
if err := json.Unmarshal(v, &l); err != nil {
return err
}
for _, lv := range l {
lv.Path = fmt.Sprintf("%s:%s", k, lv.Path)
locks = append(locks, lv)
}
return nil
})
return nil
})
return locks, err
}
// Authenticate authorizes user with password and returns the user name
func (s *MetaStore) Authenticate(user, password string) (string, bool) {
// check admin
if len(user) > 0 && len(password) > 0 {
if ok := checkBasicAuth(user, password, true); ok {
return user, true
}
}
value := ""
s.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(usersBucket)
if bucket == nil {
return errNoBucket
}
value = string(bucket.Get([]byte(user)))
return nil
})
return user, value != "" && value == password
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/vcs-all-in-one-lfs-test-server.git
git@api.gitlife.ru:oschina-mirror/vcs-all-in-one-lfs-test-server.git
oschina-mirror
vcs-all-in-one-lfs-test-server
vcs-all-in-one-lfs-test-server
master