1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "reflect"
  7. "github.com/boltdb/bolt"
  8. "github.com/timshannon/bolthold"
  9. )
  10. // BoltDB WebUI 工具:
  11. // cd ./data
  12. // boltdbweb -d=db.bolt -p=9000 -s="G:/Work/GoPath/src/github.com/evnix/boltdbweb/"
  13. const (
  14. boltDBFileName = "data/db.bolt"
  15. )
  16. var (
  17. //BoltX BoltDB Store
  18. BoltX *BoltWrap
  19. boltXModels = make(map[string]interface{}) // bolt models map
  20. boltXHasInit bool // bolt models has int
  21. )
  22. func init() {
  23. Registr2Bolt(&BoltIDIncrement{})
  24. }
  25. // initBoltDB 初始化 BoltDB 配置
  26. func initBoltDB() {
  27. BoltX = NewBoltWrap(boltDBFileName)
  28. //INFO: bolthold 会为每个 typeOf(BoltModels) 创建一个 Bucket,
  29. // 对每个 Model 初始化一下, 避免没有对某 Model 进行过 `写` 操作之前 Get 的时候报 bucket nil 错误.
  30. for _, data := range boltXModels {
  31. if err := BoltX.Upsert("-", data); err != nil {
  32. panic(err)
  33. }
  34. }
  35. }
  36. // Registr2Bolt init Registr BoltDB Model
  37. func Registr2Bolt(defaultData interface{}) {
  38. boltXModels[reflect.TypeOf(defaultData).String()] = defaultData
  39. }
  40. // GetBoltStore get bolt store
  41. func GetBoltStore(dbFileName string) (*bolthold.Store, error) {
  42. if len(dbFileName) <= 0 {
  43. return nil, errors.New("dbFileName param nil")
  44. }
  45. //return bolthold.Open(dbFileName, 0666, nil)
  46. jsonOptions := &bolthold.Options{
  47. Encoder: DefaultEncode,
  48. Decoder: DefaultDecode,
  49. }
  50. return bolthold.Open(dbFileName, 0666, jsonOptions)
  51. }
  52. //----------------------BoltWrap----------------------
  53. // BoltWrap bolt wrap
  54. type BoltWrap struct {
  55. *bolthold.Store
  56. dbFileName string
  57. }
  58. // BoltIDIncrement ID Increment
  59. type BoltIDIncrement struct {
  60. Current int64
  61. }
  62. // NewBoltWrap new BoltWrap
  63. func NewBoltWrap(dbFileName string) *BoltWrap {
  64. db, err := GetBoltStore(dbFileName)
  65. if err != nil {
  66. panic("init BoltDB fail")
  67. }
  68. return &BoltWrap{
  69. dbFileName: dbFileName,
  70. Store: db,
  71. }
  72. }
  73. // IsNotFoundError is error notFound
  74. func (b *BoltWrap) IsNotFoundError(err error) bool {
  75. return err == bolthold.ErrNotFound
  76. }
  77. // GeNextBoltID Ge Next BoltID
  78. func (b *BoltWrap) GeNextBoltID(tx *bolt.Tx, key interface{}) (int64, error) {
  79. if tx == nil || key == nil {
  80. return -1, errors.New("tx or key param nil")
  81. }
  82. id := &BoltIDIncrement{}
  83. err := b.TxGet(tx, key, id)
  84. if err != nil && !b.IsNotFoundError(err) {
  85. tx.Rollback()
  86. return -1, err
  87. }
  88. if id.Current <= 0 {
  89. id.Current = 1
  90. if err = b.TxUpsert(tx, key, id); err != nil {
  91. tx.Rollback()
  92. return -1, err
  93. }
  94. } else {
  95. id.Current++
  96. if err = b.TxUpdate(tx, key, id); err != nil {
  97. tx.Rollback()
  98. return -1, err
  99. }
  100. }
  101. return id.Current, nil
  102. }
  103. //-----------BoltDB JSON Encode/tDecode-------------
  104. // DefaultEncode is the default encoding func for bolthold (Gob)
  105. func DefaultEncode(value interface{}) ([]byte, error) {
  106. var buff bytes.Buffer
  107. en := json.NewEncoder(&buff)
  108. err := en.Encode(value)
  109. if err != nil {
  110. return nil, err
  111. }
  112. return buff.Bytes(), nil
  113. }
  114. // DefaultDecode is the default decoding func for bolthold (Gob)
  115. func DefaultDecode(data []byte, value interface{}) error {
  116. var buff bytes.Buffer
  117. de := json.NewDecoder(&buff)
  118. _, err := buff.Write(data)
  119. if err != nil {
  120. return err
  121. }
  122. err = de.Decode(value)
  123. if err != nil {
  124. return err
  125. }
  126. return nil
  127. }
ft_authoradmin  ft_create_time2017-08-18 10:45
 ft_update_time2017-08-18 10:46