database.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. if !d.TableExists(tableName) {
  144. //Table not exists. Do not proceed accessing key
  145. log.Println("[DB] ERROR: Requesting key from table that didn't exist!!!")
  146. return false
  147. }
  148. err := d.Db.View(func(tx *bolt.Tx) error {
  149. b := tx.Bucket([]byte(tableName))
  150. v := b.Get([]byte(key))
  151. if v == nil {
  152. resultIsNil = true
  153. }
  154. return nil
  155. })
  156. if err != nil {
  157. return false
  158. } else {
  159. if resultIsNil {
  160. return false
  161. } else {
  162. return true
  163. }
  164. }
  165. }
  166. /*
  167. Delete a value from the database table given tablename and key
  168. err := sysdb.Delete("MyTable", "username/message");
  169. */
  170. func (d *Database) Delete(tableName string, key string) error {
  171. if d.ReadOnly == true {
  172. return errors.New("Operation rejected in ReadOnly mode")
  173. }
  174. err := d.Db.Update(func(tx *bolt.Tx) error {
  175. tx.Bucket([]byte(tableName)).Delete([]byte(key))
  176. return nil
  177. })
  178. return err
  179. }
  180. /*
  181. //List table example usage
  182. //Assume the value is stored as a struct named "groupstruct"
  183. entries, err := sysdb.ListTable("test")
  184. if err != nil {
  185. panic(err)
  186. }
  187. for _, keypairs := range entries{
  188. log.Println(string(keypairs[0]))
  189. group := new(groupstruct)
  190. json.Unmarshal(keypairs[1], &group)
  191. log.Println(group);
  192. }
  193. */
  194. func (d *Database) ListTable(tableName string) ([][][]byte, error) {
  195. var results [][][]byte
  196. err := d.Db.View(func(tx *bolt.Tx) error {
  197. b := tx.Bucket([]byte(tableName))
  198. c := b.Cursor()
  199. for k, v := c.First(); k != nil; k, v = c.Next() {
  200. results = append(results, [][]byte{k, v})
  201. }
  202. return nil
  203. })
  204. return results, err
  205. }
  206. func (d *Database) Close() {
  207. d.Db.Close()
  208. return
  209. }