diff --git a/db/boltdb/boltdb.go b/db/boltdb/boltdb.go new file mode 100644 index 0000000..13d6113 --- /dev/null +++ b/db/boltdb/boltdb.go @@ -0,0 +1,343 @@ +package boltdb + +import ( + "bytes" + "errors" + "time" + + bolt "go.etcd.io/bbolt" +) + +var ( + ErrBucketInvalid = errors.New("bucket is invalid") + ErrKeyInvalid = errors.New("key is invalid") + ErrValueInvalid = errors.New("value is invalid") + ErrBucketNotFound = errors.New("bucket not found") + ErrKeyNotFound = errors.New("key not found") + ErrPrefixInvalid = errors.New("prefix is invalid") + ErrRangeStartInvalid = errors.New("range start is invalid") + ErrRangeEndInvalid = errors.New("range end is invalid") +) + +type boltDB struct { + db *bolt.DB +} + +func New(config ...Config) (db *boltDB) { + cfg := configDefault(config...) + db = &boltDB{} + db.db, _ = bolt.Open(cfg.Name, 0600, &bolt.Options{Timeout: 1 * time.Second}) + return +} + +// 获取数据库地址 +func (cc *boltDB) Path() (rv string) { + return cc.db.Path() +} + +// 关闭 +func (cc *boltDB) Close() (rer error) { + return cc.db.Close() +} + +// 建表 +func (cc *boltDB) CreateBucket(bucketName ...string) { + if bucketName == nil { + return + } + cc.db.Update(func(tx *bolt.Tx) error { + for _, name := range bucketName { + if name != "" { + tx.CreateBucketIfNotExists([]byte(name)) + } + } + return nil + }) +} + +// 删表 +func (cc *boltDB) DeleteBucket(bucketName ...string) { + if bucketName == nil { + return + } + cc.db.Update(func(tx *bolt.Tx) error { + for _, name := range bucketName { + if name != "" { + tx.DeleteBucket([]byte(name)) + } + } + return nil + }) +} + +// 保存 +func (cc *boltDB) Set(bucketName, key string, value []byte) (rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrKeyInvalid + if key == "" { + return + } + rer = ErrValueInvalid + if value == nil { + return + } + return cc.db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + return b.Put([]byte(key), value) + }) +} + +// 读取 +func (cc *boltDB) Get(bucketName, key string) (rv []byte, rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrKeyInvalid + if key == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + rv = b.Get([]byte(key)) + if rv == nil { + return ErrKeyNotFound + } + return nil + }) + return +} + +// 存在 +func (cc *boltDB) Has(bucketName, key string) (ok bool) { + _, err := cc.Get(bucketName, key) + return errors.Is(err, nil) +} + +// 不存在 +func (cc *boltDB) HasNot(bucketName, key string) (ok bool) { + _, err := cc.Get(bucketName, key) + return errors.Is(err, ErrKeyNotFound) +} + +// 删除 +func (cc *boltDB) Delete(bucketName, key string) (rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrKeyInvalid + if key == "" { + return + } + return cc.db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + return b.Delete([]byte(key)) + }) +} + +// 查询所有list +func (cc *boltDB) GetList(bucketName string) (rv [][]byte, rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + return b.ForEach(func(k, v []byte) error { + rv = append(rv, v) + return nil + }) + }) + return +} + +// 查询所有map +func (cc *boltDB) GetMap(bucketName string) (rv map[string][]byte, rer error) { + rv = make(map[string][]byte) + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + return b.ForEach(func(k, v []byte) error { + rv[string(k)] = v + return nil + }) + }) + return +} + +// 前缀扫描list +func (cc *boltDB) ScanPrefixList(bucketName, prefix string) (rv [][]byte, rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrPrefixInvalid + if prefix == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(prefix)); k != nil && bytes.HasPrefix(k, []byte(prefix)); k, v = c.Next() { + rv = append(rv, v) + } + return nil + }) + return +} + +// 前缀扫描map +func (cc *boltDB) ScanPrefixMap(bucketName, prefix string) (rv map[string][]byte, rer error) { + rv = make(map[string][]byte) + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrPrefixInvalid + if prefix == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(prefix)); k != nil && bytes.HasPrefix(k, []byte(prefix)); k, v = c.Next() { + rv[string(k)] = v + } + return nil + }) + return +} + +// 后缀扫描list +func (cc *boltDB) ScanSuffixList(bucketName, prefix string) (rv [][]byte, rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrPrefixInvalid + if prefix == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(prefix)); k != nil && bytes.HasSuffix(k, []byte(prefix)); k, v = c.Next() { + rv = append(rv, v) + } + return nil + }) + return +} + +// 后缀扫描map +func (cc *boltDB) ScanSuffixMap(bucketName, prefix string) (rv map[string][]byte, rer error) { + rv = make(map[string][]byte) + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrPrefixInvalid + if prefix == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(prefix)); k != nil && bytes.HasSuffix(k, []byte(prefix)); k, v = c.Next() { + rv[string(k)] = v + } + return nil + }) + return +} + +// 范围扫描list +func (cc *boltDB) ScanRangeList(bucketName, start, end string) (rv [][]byte, rer error) { + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrRangeStartInvalid + if start == "" { + return + } + rer = ErrRangeEndInvalid + if end == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(start)); k != nil && bytes.Compare(k, []byte(end)) <= 0; k, v = c.Next() { + rv = append(rv, v) + } + return nil + }) + return +} + +// 范围扫描list +func (cc *boltDB) ScanRangeMap(bucketName, start, end string) (rv map[string][]byte, rer error) { + rv = make(map[string][]byte) + rer = ErrBucketInvalid + if bucketName == "" { + return + } + rer = ErrRangeStartInvalid + if start == "" { + return + } + rer = ErrRangeEndInvalid + if end == "" { + return + } + rer = cc.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(bucketName)) + if b == nil { + return ErrBucketNotFound + } + c := b.Cursor() + for k, v := c.Seek([]byte(start)); k != nil && bytes.Compare(k, []byte(end)) <= 0; k, v = c.Next() { + rv[string(k)] = v + } + return nil + }) + return +} diff --git a/db/boltdb/config.go b/db/boltdb/config.go new file mode 100644 index 0000000..1328000 --- /dev/null +++ b/db/boltdb/config.go @@ -0,0 +1,22 @@ +package boltdb + +type Config struct { + Name string +} + +var cfg_default = Config{ + Name: "db.pp", +} + +func configDefault(config ...Config) Config { + if len(config) < 1 { + return cfg_default + } + cfg := config[0] + + if cfg.Name == "" { + cfg.Name = cfg_default.Name + } + + return cfg +} diff --git a/go.mod b/go.mod index 104d29e..0610ea0 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,12 @@ module git.shikicc.com/golang/kit go 1.21.4 require ( + go.etcd.io/bbolt v1.3.10 go.uber.org/zap v1.26.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) -require go.uber.org/multierr v1.10.0 // indirect +require ( + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/sys v0.4.0 // indirect +) diff --git a/go.sum b/go.sum index 2917eda..f773b14 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,18 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/log/zaplog/config.go b/log/zaplog/config.go index 6c7896e..dcbda86 100644 --- a/log/zaplog/config.go +++ b/log/zaplog/config.go @@ -17,7 +17,7 @@ type LogFileConfig struct { FileAge_DAY int // 日志文件保留天数 } -type ZapConfig struct { +type Config struct { JsonFormat bool // 是否使用json格式,默认false Mode int8 // 日志启用级别 DebugLog LogFileConfig // Debug日志配置 @@ -27,7 +27,7 @@ type ZapConfig struct { FatalLog LogFileConfig // Fatal日志配置 } -var cfg_default = ZapConfig{ +var cfg_default = Config{ DebugLog: LogFileConfig{ Filename: "./log/debug", FileSize_MB: 5, @@ -60,7 +60,7 @@ var cfg_default = ZapConfig{ }, } -func configDefault(config ...ZapConfig) ZapConfig { +func configDefault(config ...Config) Config { if len(config) < 1 { return cfg_default } diff --git a/log/zaplog/zaplog.go b/log/zaplog/zaplog.go index 73dec36..69e4ba2 100644 --- a/log/zaplog/zaplog.go +++ b/log/zaplog/zaplog.go @@ -33,7 +33,7 @@ func jsonencoderConfig() zapcore.EncoderConfig { return encoderConfig } -func New(config ...ZapConfig) *zap.SugaredLogger { +func New(config ...Config) *zap.SugaredLogger { cfg := configDefault(config...) var encoder zapcore.Encoder