427 lines
8.1 KiB
Go
427 lines
8.1 KiB
Go
package boltdb
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/boltdb/bolt"
|
|
"github.com/cdle/sillyplus/core/logs"
|
|
"github.com/cdle/sillyplus/core/storage"
|
|
|
|
"github.com/cdle/sillyplus/utils"
|
|
)
|
|
|
|
type Bucket struct {
|
|
name string
|
|
}
|
|
|
|
var db *bolt.DB
|
|
|
|
func (b Bucket) String() string {
|
|
return b.name
|
|
}
|
|
|
|
var expirationA = Bucket{
|
|
name: "timeouts",
|
|
}
|
|
|
|
type Expire struct {
|
|
Value string `json:"value"`
|
|
Time time.Time `json:"deadline"`
|
|
}
|
|
|
|
func Set(key string, value string, expiration time.Duration) error {
|
|
_, err := expirationA.Set(key, utils.JsonMarshal(&Expire{
|
|
Value: value,
|
|
Time: time.Now().Add(expiration),
|
|
}))
|
|
return err
|
|
}
|
|
|
|
func Get(key string) string {
|
|
e := Expire{}
|
|
data := expirationA.GetBytes(key)
|
|
json.Unmarshal(data, &e)
|
|
if e.Time.Before(time.Now()) {
|
|
return ""
|
|
}
|
|
return e.Value
|
|
}
|
|
|
|
var Buckets = []Bucket{}
|
|
|
|
func Initsillyplus() storage.Bucket {
|
|
bd := utils.GetDataHome() + "sillyGirl.db"
|
|
_, err := os.Stat(bd)
|
|
if err != nil {
|
|
f, err := os.Create(bd)
|
|
if err != nil {
|
|
logs.Info("傻妞无法创建数据文件 %s ,请手动创建", bd)
|
|
os.Exit(0)
|
|
}
|
|
f.Close()
|
|
}
|
|
db, err = bolt.Open(bd, 0600, nil)
|
|
if err != nil {
|
|
logs.Info("傻妞无法创建数据文件 %s ,请手动创建", bd)
|
|
os.Exit(0)
|
|
}
|
|
|
|
v := &Bucket{
|
|
name: "sillyGirl",
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (bucket *Bucket) GetName() string {
|
|
return bucket.name
|
|
}
|
|
|
|
func (bucket *Bucket) Copy(name string) storage.Bucket {
|
|
return &Bucket{name: name}
|
|
}
|
|
|
|
func (bucket *Bucket) Type() string {
|
|
return "boltdb"
|
|
}
|
|
|
|
func (bucket *Bucket) Buckets() []string {
|
|
var r []string
|
|
db.View(func(tx *bolt.Tx) error {
|
|
tx.ForEach(func(name []byte, _ *bolt.Bucket) error {
|
|
r = append(r, string(name))
|
|
return nil
|
|
})
|
|
return nil
|
|
})
|
|
return r
|
|
}
|
|
|
|
func (bucket *Bucket) Delete() error {
|
|
err := db.Update(func(tx *bolt.Tx) error {
|
|
k := fmt.Sprint(bucket.name)
|
|
e := tx.DeleteBucket([]byte(k))
|
|
if e == bolt.ErrBucketNotFound {
|
|
return nil
|
|
}
|
|
return e
|
|
})
|
|
return err
|
|
}
|
|
|
|
func (bucket *Bucket) Set2(key interface{}, value interface{}) (string, error) {
|
|
new := ""
|
|
msg := ""
|
|
k := fmt.Sprint(key)
|
|
switch value := value.(type) {
|
|
case []byte:
|
|
new = string(value)
|
|
case string:
|
|
new = value
|
|
case nil:
|
|
default:
|
|
new = fmt.Sprint(value)
|
|
}
|
|
return msg, db.Update(func(tx *bolt.Tx) error {
|
|
b, err := tx.CreateBucketIfNotExists([]byte(bucket.name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if new == "" {
|
|
if err := b.Delete([]byte(k)); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := b.Put([]byte(k), []byte(new)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (bucket *Bucket) Set(key interface{}, value interface{}) (string, error) {
|
|
new := ""
|
|
msg := ""
|
|
k := fmt.Sprint(key)
|
|
switch value := value.(type) {
|
|
case []byte:
|
|
new = string(value)
|
|
case string:
|
|
new = value
|
|
case nil:
|
|
default:
|
|
new = fmt.Sprint(value)
|
|
}
|
|
var handles []func(string, string, string) *storage.Final
|
|
for _, listen := range storage.Listens {
|
|
if listen.Name == bucket.name && (listen.Key == key || listen.Key == "*") {
|
|
handles = append(handles, listen.Handle)
|
|
}
|
|
}
|
|
if len(handles) > 0 {
|
|
old := bucket.GetString(key)
|
|
for _, handle := range handles {
|
|
fin := handle(old, new, k)
|
|
if fin != nil {
|
|
if fin.Message != "" {
|
|
msg = fin.Message
|
|
}
|
|
if fin.Error != nil {
|
|
return msg, fin.Error
|
|
}
|
|
if fin.Now != "" {
|
|
new = fin.Now
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return msg, db.Update(func(tx *bolt.Tx) error {
|
|
b, err := tx.CreateBucketIfNotExists([]byte(bucket.name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if new == "" {
|
|
if err := b.Delete([]byte(k)); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := b.Put([]byte(k), []byte(new)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (bucket *Bucket) GetString(kv ...interface{}) string {
|
|
// logs.Info(kv)
|
|
var key, value string
|
|
for i := range kv {
|
|
if i == 0 {
|
|
key = fmt.Sprint(kv[0])
|
|
} else {
|
|
value = fmt.Sprint(kv[1])
|
|
}
|
|
}
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
if v := string(b.Get([]byte(key))); v != "" {
|
|
value = v
|
|
}
|
|
return nil
|
|
})
|
|
return value
|
|
}
|
|
|
|
func (bucket *Bucket) GetBytes(key string) []byte {
|
|
var value []byte
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
if v := b.Get([]byte(key)); v != nil {
|
|
value = v
|
|
}
|
|
return nil
|
|
})
|
|
return value
|
|
}
|
|
|
|
func (bucket *Bucket) GetInt(key string, vs ...int) int {
|
|
var value int
|
|
if len(vs) != 0 {
|
|
value = vs[0]
|
|
}
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
v := utils.Int(string(b.Get([]byte(fmt.Sprint(key)))))
|
|
if v != 0 {
|
|
value = v
|
|
}
|
|
return nil
|
|
})
|
|
return value
|
|
}
|
|
|
|
func (bucket *Bucket) GetBool(key string, vs ...bool) bool {
|
|
var value bool
|
|
if len(vs) != 0 {
|
|
value = vs[0]
|
|
}
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
return nil
|
|
}
|
|
v := string(b.Get([]byte(fmt.Sprint(key))))
|
|
if v == "true" {
|
|
value = true
|
|
} else if v == "false" {
|
|
value = false
|
|
}
|
|
return nil
|
|
})
|
|
return value
|
|
}
|
|
|
|
func (bucket *Bucket) Foreach(f func(k, v []byte) error) {
|
|
var bs = [][][]byte{}
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b != nil {
|
|
err := b.ForEach(func(k, v []byte) error {
|
|
bs = append(bs, [][]byte{k, v})
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
for i := range bs {
|
|
f(bs[i][0], bs[i][1])
|
|
}
|
|
}
|
|
|
|
func (bucket *Bucket) Keys() ([]string, error) {
|
|
var bs = []string{}
|
|
err := db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b != nil {
|
|
err := b.ForEach(func(k, _ []byte) error {
|
|
if string(k) == "plugins" {
|
|
return nil
|
|
}
|
|
bs = append(bs, string(k))
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
return bs, err
|
|
}
|
|
|
|
func (bucket *Bucket) Create(i interface{}) error {
|
|
// logs.Info("-", i)
|
|
s := reflect.ValueOf(i).Elem()
|
|
id := s.FieldByName("ID")
|
|
sequence := s.FieldByName("Sequence")
|
|
return db.Update(func(tx *bolt.Tx) error {
|
|
b, err := tx.CreateBucketIfNotExists([]byte(bucket.name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, ok := id.Interface().(int); ok {
|
|
key := id.Int()
|
|
sq, err := b.NextSequence()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if key == 0 {
|
|
key = int64(sq)
|
|
id.SetInt(key)
|
|
}
|
|
if sequence != reflect.ValueOf(nil) {
|
|
sequence.SetInt(int64(sq))
|
|
}
|
|
buf, err := json.Marshal(i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return b.Put(utils.Itob(uint64(key)), buf)
|
|
} else {
|
|
key := id.String()
|
|
sq, err := b.NextSequence()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if key == "" {
|
|
key = fmt.Sprint(sq)
|
|
id.SetString(key)
|
|
}
|
|
if sequence != reflect.ValueOf(nil) {
|
|
sequence.SetInt(int64(sq))
|
|
}
|
|
buf, err := json.Marshal(i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return b.Put([]byte(key), buf)
|
|
}
|
|
})
|
|
}
|
|
|
|
func (bucket *Bucket) First(i interface{}) error {
|
|
var err error
|
|
s := reflect.ValueOf(i).Elem()
|
|
id := s.FieldByName("ID")
|
|
if v, ok := id.Interface().(int); ok {
|
|
err = db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
err = errors.New("bucket not find")
|
|
return nil
|
|
}
|
|
data := b.Get([]byte(fmt.Sprint(v)))
|
|
if len(data) == 0 {
|
|
err = errors.New("record not find")
|
|
return nil
|
|
}
|
|
return json.Unmarshal(data, i)
|
|
})
|
|
} else {
|
|
err = db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b == nil {
|
|
err = errors.New("bucket not find")
|
|
return nil
|
|
}
|
|
data := b.Get([]byte(id.Interface().(string)))
|
|
if len(data) == 0 {
|
|
err = errors.New("record not find")
|
|
return nil
|
|
}
|
|
return json.Unmarshal(data, i)
|
|
})
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (bucket *Bucket) Size() (int64, error) {
|
|
var r int64
|
|
bucket.Foreach(func(k, v []byte) error {
|
|
r++
|
|
return nil
|
|
})
|
|
return r, nil
|
|
}
|
|
|
|
func (bucket *Bucket) IsEmpty() (bool, error) {
|
|
r := true
|
|
db.View(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte(bucket.name))
|
|
if b != nil {
|
|
o, _ := b.Cursor().First()
|
|
r = o == nil
|
|
}
|
|
return nil
|
|
})
|
|
return r, nil
|
|
}
|