database_openwrt.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. //go:build mipsle || riscv64
  2. // +build mipsle riscv64
  3. package database
  4. import (
  5. "encoding/json"
  6. "errors"
  7. "log"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "imuslab.com/zoraxy/mod/database/dbinc"
  12. )
  13. /*
  14. OpenWRT or RISCV backend
  15. For OpenWRT or RISCV platform, we will use the filesystem as the database backend
  16. as boltdb or leveldb is not supported on these platforms, including boltDB and LevelDB
  17. in conditional compilation will create a build error on these platforms
  18. */
  19. func newDatabase(dbfile string, backendType dbinc.BackendType) (*Database, error) {
  20. dbRootPath := filepath.ToSlash(filepath.Clean(dbfile))
  21. dbRootPath = "fsdb/" + dbRootPath
  22. err := os.MkdirAll(dbRootPath, 0755)
  23. if err != nil {
  24. return nil, err
  25. }
  26. log.Println("Filesystem Emulated Key-value Database Service Started: " + dbRootPath)
  27. return &Database{
  28. Db: dbRootPath,
  29. BackendType: dbinc.BackendFSOnly,
  30. Backend: nil,
  31. }, nil
  32. }
  33. func (d *Database) dump(filename string) ([]string, error) {
  34. //Get all file objects from root
  35. rootfiles, err := filepath.Glob(filepath.Join(d.Db.(string), "/*"))
  36. if err != nil {
  37. return []string{}, err
  38. }
  39. //Filter out the folders
  40. rootFolders := []string{}
  41. for _, file := range rootfiles {
  42. if !isDirectory(file) {
  43. rootFolders = append(rootFolders, filepath.Base(file))
  44. }
  45. }
  46. return rootFolders, nil
  47. }
  48. func (d *Database) newTable(tableName string) error {
  49. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  50. if !fileExists(tablePath) {
  51. return os.MkdirAll(tablePath, 0755)
  52. }
  53. return nil
  54. }
  55. func (d *Database) tableExists(tableName string) bool {
  56. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  57. if _, err := os.Stat(tablePath); errors.Is(err, os.ErrNotExist) {
  58. return false
  59. }
  60. if !isDirectory(tablePath) {
  61. return false
  62. }
  63. return true
  64. }
  65. func (d *Database) dropTable(tableName string) error {
  66. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  67. if d.tableExists(tableName) {
  68. return os.RemoveAll(tablePath)
  69. } else {
  70. return errors.New("table not exists")
  71. }
  72. }
  73. func (d *Database) write(tableName string, key string, value interface{}) error {
  74. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  75. js, err := json.Marshal(value)
  76. if err != nil {
  77. return err
  78. }
  79. key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")
  80. return os.WriteFile(filepath.Join(tablePath, key+".entry"), js, 0755)
  81. }
  82. func (d *Database) read(tableName string, key string, assignee interface{}) error {
  83. if !d.keyExists(tableName, key) {
  84. return errors.New("key not exists")
  85. }
  86. key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")
  87. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  88. entryPath := filepath.Join(tablePath, key+".entry")
  89. content, err := os.ReadFile(entryPath)
  90. if err != nil {
  91. return err
  92. }
  93. err = json.Unmarshal(content, &assignee)
  94. return err
  95. }
  96. func (d *Database) keyExists(tableName string, key string) bool {
  97. key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")
  98. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  99. entryPath := filepath.Join(tablePath, key+".entry")
  100. return fileExists(entryPath)
  101. }
  102. func (d *Database) delete(tableName string, key string) error {
  103. if !d.keyExists(tableName, key) {
  104. return errors.New("key not exists")
  105. }
  106. key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")
  107. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  108. entryPath := filepath.Join(tablePath, key+".entry")
  109. return os.Remove(entryPath)
  110. }
  111. func (d *Database) listTable(tableName string) ([][][]byte, error) {
  112. if !d.tableExists(tableName) {
  113. return [][][]byte{}, errors.New("table not exists")
  114. }
  115. tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))
  116. entries, err := filepath.Glob(filepath.Join(tablePath, "/*.entry"))
  117. if err != nil {
  118. return [][][]byte{}, err
  119. }
  120. var results [][][]byte = [][][]byte{}
  121. for _, entry := range entries {
  122. if !isDirectory(entry) {
  123. //Read it
  124. key := filepath.Base(entry)
  125. key = strings.TrimSuffix(key, filepath.Ext(key))
  126. key = strings.ReplaceAll(key, "-SLASH_SIGN-", "/")
  127. bkey := []byte(key)
  128. bval := []byte("")
  129. c, err := os.ReadFile(entry)
  130. if err != nil {
  131. break
  132. }
  133. bval = c
  134. results = append(results, [][]byte{bkey, bval})
  135. }
  136. }
  137. return results, nil
  138. }
  139. func (d *Database) close() {
  140. //Nothing to close as it is file system
  141. }
  142. func isDirectory(path string) bool {
  143. fileInfo, err := os.Stat(path)
  144. if err != nil {
  145. return false
  146. }
  147. return fileInfo.IsDir()
  148. }
  149. func fileExists(name string) bool {
  150. _, err := os.Stat(name)
  151. if err == nil {
  152. return true
  153. }
  154. if errors.Is(err, os.ErrNotExist) {
  155. return false
  156. }
  157. return false
  158. }