database.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package database
  2. /*
  3. ArOZ Online Database Access Module
  4. author: tobychui
  5. This is an improved Object oriented base solution to the original
  6. aroz online database script.
  7. */
  8. import (
  9. "encoding/json"
  10. "errors"
  11. "log"
  12. "sync"
  13. "github.com/boltdb/bolt"
  14. )
  15. type Database struct {
  16. Db *bolt.DB
  17. Tables sync.Map
  18. ReadOnly bool
  19. }
  20. func NewDatabase(dbfile string, readOnlyMode bool) (*Database, error) {
  21. db, err := bolt.Open(dbfile, 0600, nil)
  22. log.Println("Key-value Database Service Started: " + dbfile)
  23. tableMap := sync.Map{}
  24. //Build the table list from database
  25. err = db.View(func(tx *bolt.Tx) error {
  26. return tx.ForEach(func(name []byte, _ *bolt.Bucket) error {
  27. tableMap.Store(string(name), "")
  28. return nil
  29. })
  30. })
  31. return &Database{
  32. Db: db,
  33. Tables: tableMap,
  34. ReadOnly: readOnlyMode,
  35. }, err
  36. }
  37. /*
  38. Create / Drop a table
  39. Usage:
  40. err := sysdb.NewTable("MyTable")
  41. err := sysdb.DropTable("MyTable")
  42. */
  43. func (d *Database) UpdateReadWriteMode(readOnly bool) {
  44. d.ReadOnly = readOnly
  45. }
  46. //Dump the whole db into a log file
  47. func (d *Database) Dump(filename string) ([]string, error) {
  48. results := []string{}
  49. d.Tables.Range(func(tableName, v interface{}) bool {
  50. entries, err := d.ListTable(tableName.(string))
  51. if err != nil {
  52. log.Println("Reading table " + tableName.(string) + " failed: " + err.Error())
  53. return false
  54. }
  55. for _, keypairs := range entries {
  56. results = append(results, string(keypairs[0])+":"+string(keypairs[1])+"\n")
  57. }
  58. return true
  59. })
  60. return results, nil
  61. }
  62. //Create a new table
  63. func (d *Database) NewTable(tableName string) error {
  64. if d.ReadOnly == true {
  65. return errors.New("Operation rejected in ReadOnly mode")
  66. }
  67. err := d.Db.Update(func(tx *bolt.Tx) error {
  68. _, err := tx.CreateBucketIfNotExists([]byte(tableName))
  69. if err != nil {
  70. return err
  71. }
  72. return nil
  73. })
  74. d.Tables.Store(tableName, "")
  75. return err
  76. }
  77. //Check is table exists
  78. func (d *Database) TableExists(tableName string) bool {
  79. if _, ok := d.Tables.Load(tableName); ok {
  80. return true
  81. }
  82. return false
  83. }
  84. //Drop the given table
  85. func (d *Database) DropTable(tableName string) error {
  86. if d.ReadOnly == true {
  87. return errors.New("Operation rejected in ReadOnly mode")
  88. }
  89. err := d.Db.Update(func(tx *bolt.Tx) error {
  90. err := tx.DeleteBucket([]byte(tableName))
  91. if err != nil {
  92. return err
  93. }
  94. return nil
  95. })
  96. return err
  97. }
  98. /*
  99. Write to database with given tablename and key. Example Usage:
  100. type demo struct{
  101. content string
  102. }
  103. thisDemo := demo{
  104. content: "Hello World",
  105. }
  106. err := sysdb.Write("MyTable", "username/message",thisDemo);
  107. */
  108. func (d *Database) Write(tableName string, key string, value interface{}) error {
  109. if d.ReadOnly == true {
  110. return errors.New("Operation rejected in ReadOnly mode")
  111. }
  112. jsonString, err := json.Marshal(value)
  113. if err != nil {
  114. return err
  115. }
  116. err = d.Db.Update(func(tx *bolt.Tx) error {
  117. _, err := tx.CreateBucketIfNotExists([]byte(tableName))
  118. b := tx.Bucket([]byte(tableName))
  119. err = b.Put([]byte(key), jsonString)
  120. return err
  121. })
  122. return err
  123. }
  124. /*
  125. Read from database and assign the content to a given datatype. Example Usage:
  126. type demo struct{
  127. content string
  128. }
  129. thisDemo := new(demo)
  130. err := sysdb.Read("MyTable", "username/message",&thisDemo);
  131. */
  132. func (d *Database) Read(tableName string, key string, assignee interface{}) error {
  133. err := d.Db.View(func(tx *bolt.Tx) error {
  134. b := tx.Bucket([]byte(tableName))
  135. v := b.Get([]byte(key))
  136. json.Unmarshal(v, &assignee)
  137. return nil
  138. })
  139. return err
  140. }
  141. func (d *Database) KeyExists(tableName string, key string) bool {
  142. resultIsNil := false
  143. err := d.Db.View(func(tx *bolt.Tx) error {
  144. b := tx.Bucket([]byte(tableName))
  145. v := b.Get([]byte(key))
  146. if v == nil {
  147. resultIsNil = true
  148. }
  149. return nil
  150. })
  151. if err != nil {
  152. return false
  153. } else {
  154. if resultIsNil {
  155. return false
  156. } else {
  157. return true
  158. }
  159. }
  160. }
  161. /*
  162. Delete a value from the database table given tablename and key
  163. err := sysdb.Delete("MyTable", "username/message");
  164. */
  165. func (d *Database) Delete(tableName string, key string) error {
  166. if d.ReadOnly == true {
  167. return errors.New("Operation rejected in ReadOnly mode")
  168. }
  169. err := d.Db.Update(func(tx *bolt.Tx) error {
  170. tx.Bucket([]byte(tableName)).Delete([]byte(key))
  171. return nil
  172. })
  173. return err
  174. }
  175. /*
  176. //List table example usage
  177. //Assume the value is stored as a struct named "groupstruct"
  178. entries, err := sysdb.ListTable("test")
  179. if err != nil {
  180. panic(err)
  181. }
  182. for _, keypairs := range entries{
  183. log.Println(string(keypairs[0]))
  184. group := new(groupstruct)
  185. json.Unmarshal(keypairs[1], &group)
  186. log.Println(group);
  187. }
  188. */
  189. func (d *Database) ListTable(tableName string) ([][][]byte, error) {
  190. var results [][][]byte
  191. err := d.Db.View(func(tx *bolt.Tx) error {
  192. b := tx.Bucket([]byte(tableName))
  193. c := b.Cursor()
  194. for k, v := c.First(); k != nil; k, v = c.Next() {
  195. results = append(results, [][]byte{k, v})
  196. }
  197. return nil
  198. })
  199. return results, err
  200. }
  201. func (d *Database) Close() {
  202. d.Db.Close()
  203. return
  204. }