1
0

kvdb.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. package kvdb
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "sync"
  9. )
  10. // InMemoryKVDB is a simple in-memory key-value database
  11. type InMemoryKVDB struct {
  12. users map[string]*User // key: AccessKeyID
  13. bucketConfigs map[string]*BucketConfig // key: accountID:bucketID
  14. mu sync.RWMutex
  15. }
  16. // NewInMemoryKVDB creates a new in-memory key-value database
  17. func NewInMemoryKVDB() *InMemoryKVDB {
  18. return &InMemoryKVDB{
  19. users: make(map[string]*User),
  20. bucketConfigs: make(map[string]*BucketConfig),
  21. }
  22. }
  23. // GetUser retrieves a user by access key ID
  24. func (db *InMemoryKVDB) GetUser(accessKeyID string) (*User, error) {
  25. db.mu.RLock()
  26. defer db.mu.RUnlock()
  27. user, exists := db.users[accessKeyID]
  28. if !exists {
  29. return nil, ErrUserNotFound
  30. }
  31. // Return a copy to prevent external modifications
  32. userCopy := *user
  33. return &userCopy, nil
  34. }
  35. // CreateUser creates a new user
  36. func (db *InMemoryKVDB) CreateUser(user *User) error {
  37. db.mu.Lock()
  38. defer db.mu.Unlock()
  39. if _, exists := db.users[user.AccessKeyID]; exists {
  40. return ErrUserAlreadyExists
  41. }
  42. // Store a copy to prevent external modifications
  43. userCopy := *user
  44. db.users[user.AccessKeyID] = &userCopy
  45. return nil
  46. }
  47. // UpdateUser updates an existing user
  48. func (db *InMemoryKVDB) UpdateUser(user *User) error {
  49. db.mu.Lock()
  50. defer db.mu.Unlock()
  51. if _, exists := db.users[user.AccessKeyID]; !exists {
  52. return ErrUserNotFound
  53. }
  54. userCopy := *user
  55. db.users[user.AccessKeyID] = &userCopy
  56. return nil
  57. }
  58. // DeleteUser deletes a user
  59. func (db *InMemoryKVDB) DeleteUser(accessKeyID string) error {
  60. db.mu.Lock()
  61. defer db.mu.Unlock()
  62. if _, exists := db.users[accessKeyID]; !exists {
  63. return ErrUserNotFound
  64. }
  65. delete(db.users, accessKeyID)
  66. return nil
  67. }
  68. // ListUsers returns all users
  69. func (db *InMemoryKVDB) ListUsers() ([]*User, error) {
  70. db.mu.RLock()
  71. defer db.mu.RUnlock()
  72. users := make([]*User, 0, len(db.users))
  73. for _, user := range db.users {
  74. userCopy := *user
  75. users = append(users, &userCopy)
  76. }
  77. return users, nil
  78. }
  79. // ValidateCredentials validates user credentials
  80. func (db *InMemoryKVDB) ValidateCredentials(accessKeyID, secretAccessKey string) (*User, error) {
  81. user, err := db.GetUser(accessKeyID)
  82. if err != nil {
  83. return nil, err
  84. }
  85. if user.SecretAccessKey != secretAccessKey {
  86. return nil, errors.New("invalid credentials")
  87. }
  88. return user, nil
  89. }
  90. // SetBucketConfig sets the configuration for a bucket
  91. func (db *InMemoryKVDB) SetBucketConfig(config *BucketConfig) error {
  92. db.mu.Lock()
  93. defer db.mu.Unlock()
  94. key := config.AccountID + ":" + config.BucketID
  95. configCopy := *config
  96. db.bucketConfigs[key] = &configCopy
  97. return nil
  98. }
  99. // GetBucketConfig gets the configuration for a bucket
  100. func (db *InMemoryKVDB) GetBucketConfig(accountID, bucketID string) (*BucketConfig, error) {
  101. db.mu.RLock()
  102. defer db.mu.RUnlock()
  103. key := accountID + ":" + bucketID
  104. config, exists := db.bucketConfigs[key]
  105. if !exists {
  106. return nil, fmt.Errorf("bucket config not found")
  107. }
  108. configCopy := *config
  109. return &configCopy, nil
  110. }
  111. // DeleteBucketConfig deletes the configuration for a bucket
  112. func (db *InMemoryKVDB) DeleteBucketConfig(accountID, bucketID string) error {
  113. db.mu.Lock()
  114. defer db.mu.Unlock()
  115. key := accountID + ":" + bucketID
  116. if _, exists := db.bucketConfigs[key]; !exists {
  117. return fmt.Errorf("bucket config not found")
  118. }
  119. delete(db.bucketConfigs, key)
  120. return nil
  121. }
  122. // ListBucketConfigs lists all bucket configurations for an account
  123. func (db *InMemoryKVDB) ListBucketConfigs(accountID string) ([]*BucketConfig, error) {
  124. db.mu.RLock()
  125. defer db.mu.RUnlock()
  126. var configs []*BucketConfig
  127. prefix := accountID + ":"
  128. for key, config := range db.bucketConfigs {
  129. if len(key) >= len(prefix) && key[:len(prefix)] == prefix {
  130. configCopy := *config
  131. configs = append(configs, &configCopy)
  132. }
  133. }
  134. return configs, nil
  135. }
  136. // ResolveBucketName resolves a bucket name to accountID and bucketID
  137. func (db *InMemoryKVDB) ResolveBucketName(bucketName string) (string, string, error) {
  138. db.mu.RLock()
  139. defer db.mu.RUnlock()
  140. for _, config := range db.bucketConfigs {
  141. if config.BucketName == bucketName {
  142. return config.AccountID, config.BucketID, nil
  143. }
  144. }
  145. return "", "", fmt.Errorf("bucket not found: %s", bucketName)
  146. }
  147. // Close closes the database (no-op for in-memory)
  148. func (db *InMemoryKVDB) Close() error {
  149. return nil
  150. }
  151. // FileBasedKVDB is a file-based key-value database with persistence
  152. type FileBasedKVDB struct {
  153. filePath string
  154. users map[string]*User
  155. bucketConfigs map[string]*BucketConfig
  156. mu sync.RWMutex
  157. }
  158. // NewFileBasedKVDB creates a new file-based key-value database
  159. func NewFileBasedKVDB(filePath string) (*FileBasedKVDB, error) {
  160. db := &FileBasedKVDB{
  161. filePath: filePath,
  162. users: make(map[string]*User),
  163. bucketConfigs: make(map[string]*BucketConfig),
  164. }
  165. // Create directory if it doesn't exist
  166. dir := filepath.Dir(filePath)
  167. if err := os.MkdirAll(dir, 0755); err != nil {
  168. return nil, err
  169. }
  170. // Load existing data if file exists
  171. if err := db.load(); err != nil && !os.IsNotExist(err) {
  172. return nil, err
  173. }
  174. return db, nil
  175. }
  176. type fileBasedData struct {
  177. Users []*User `json:"users"`
  178. BucketConfigs []*BucketConfig `json:"bucket_configs"`
  179. }
  180. // load reads the database from disk
  181. func (db *FileBasedKVDB) load() error {
  182. data, err := os.ReadFile(db.filePath)
  183. if err != nil {
  184. return err
  185. }
  186. var fileData fileBasedData
  187. if err := json.Unmarshal(data, &fileData); err != nil {
  188. return err
  189. }
  190. db.mu.Lock()
  191. defer db.mu.Unlock()
  192. for _, user := range fileData.Users {
  193. db.users[user.AccessKeyID] = user
  194. }
  195. for _, config := range fileData.BucketConfigs {
  196. key := config.AccountID + ":" + config.BucketID
  197. db.bucketConfigs[key] = config
  198. }
  199. return nil
  200. }
  201. // save writes the database to disk
  202. func (db *FileBasedKVDB) save() error {
  203. users := make([]*User, 0, len(db.users))
  204. for _, user := range db.users {
  205. users = append(users, user)
  206. }
  207. configs := make([]*BucketConfig, 0, len(db.bucketConfigs))
  208. for _, config := range db.bucketConfigs {
  209. configs = append(configs, config)
  210. }
  211. fileData := fileBasedData{
  212. Users: users,
  213. BucketConfigs: configs,
  214. }
  215. data, err := json.MarshalIndent(fileData, "", " ")
  216. if err != nil {
  217. return err
  218. }
  219. return os.WriteFile(db.filePath, data, 0644)
  220. }
  221. // GetUser retrieves a user by access key ID
  222. func (db *FileBasedKVDB) GetUser(accessKeyID string) (*User, error) {
  223. db.mu.RLock()
  224. defer db.mu.RUnlock()
  225. user, exists := db.users[accessKeyID]
  226. if !exists {
  227. return nil, ErrUserNotFound
  228. }
  229. userCopy := *user
  230. return &userCopy, nil
  231. }
  232. // CreateUser creates a new user
  233. func (db *FileBasedKVDB) CreateUser(user *User) error {
  234. db.mu.Lock()
  235. defer db.mu.Unlock()
  236. if _, exists := db.users[user.AccessKeyID]; exists {
  237. return ErrUserAlreadyExists
  238. }
  239. userCopy := *user
  240. db.users[user.AccessKeyID] = &userCopy
  241. return db.save()
  242. }
  243. // UpdateUser updates an existing user
  244. func (db *FileBasedKVDB) UpdateUser(user *User) error {
  245. db.mu.Lock()
  246. defer db.mu.Unlock()
  247. if _, exists := db.users[user.AccessKeyID]; !exists {
  248. return ErrUserNotFound
  249. }
  250. userCopy := *user
  251. db.users[user.AccessKeyID] = &userCopy
  252. return db.save()
  253. }
  254. // DeleteUser deletes a user
  255. func (db *FileBasedKVDB) DeleteUser(accessKeyID string) error {
  256. db.mu.Lock()
  257. defer db.mu.Unlock()
  258. if _, exists := db.users[accessKeyID]; !exists {
  259. return ErrUserNotFound
  260. }
  261. delete(db.users, accessKeyID)
  262. return db.save()
  263. }
  264. // ListUsers returns all users
  265. func (db *FileBasedKVDB) ListUsers() ([]*User, error) {
  266. db.mu.RLock()
  267. defer db.mu.RUnlock()
  268. users := make([]*User, 0, len(db.users))
  269. for _, user := range db.users {
  270. userCopy := *user
  271. users = append(users, &userCopy)
  272. }
  273. return users, nil
  274. }
  275. // ValidateCredentials validates user credentials
  276. func (db *FileBasedKVDB) ValidateCredentials(accessKeyID, secretAccessKey string) (*User, error) {
  277. user, err := db.GetUser(accessKeyID)
  278. if err != nil {
  279. return nil, err
  280. }
  281. if user.SecretAccessKey != secretAccessKey {
  282. return nil, errors.New("invalid credentials")
  283. }
  284. return user, nil
  285. }
  286. // SetBucketConfig sets the configuration for a bucket
  287. func (db *FileBasedKVDB) SetBucketConfig(config *BucketConfig) error {
  288. db.mu.Lock()
  289. defer db.mu.Unlock()
  290. key := config.AccountID + ":" + config.BucketID
  291. configCopy := *config
  292. db.bucketConfigs[key] = &configCopy
  293. return db.save()
  294. }
  295. // GetBucketConfig gets the configuration for a bucket
  296. func (db *FileBasedKVDB) GetBucketConfig(accountID, bucketID string) (*BucketConfig, error) {
  297. db.mu.RLock()
  298. defer db.mu.RUnlock()
  299. key := accountID + ":" + bucketID
  300. config, exists := db.bucketConfigs[key]
  301. if !exists {
  302. return nil, fmt.Errorf("bucket config not found")
  303. }
  304. configCopy := *config
  305. return &configCopy, nil
  306. }
  307. // DeleteBucketConfig deletes the configuration for a bucket
  308. func (db *FileBasedKVDB) DeleteBucketConfig(accountID, bucketID string) error {
  309. db.mu.Lock()
  310. defer db.mu.Unlock()
  311. key := accountID + ":" + bucketID
  312. if _, exists := db.bucketConfigs[key]; !exists {
  313. return fmt.Errorf("bucket config not found")
  314. }
  315. delete(db.bucketConfigs, key)
  316. return db.save()
  317. }
  318. // ListBucketConfigs lists all bucket configurations for an account
  319. func (db *FileBasedKVDB) ListBucketConfigs(accountID string) ([]*BucketConfig, error) {
  320. db.mu.RLock()
  321. defer db.mu.RUnlock()
  322. var configs []*BucketConfig
  323. prefix := accountID + ":"
  324. for key, config := range db.bucketConfigs {
  325. if len(key) >= len(prefix) && key[:len(prefix)] == prefix {
  326. configCopy := *config
  327. configs = append(configs, &configCopy)
  328. }
  329. }
  330. return configs, nil
  331. }
  332. // ResolveBucketName resolves a bucket name to accountID and bucketID
  333. func (db *FileBasedKVDB) ResolveBucketName(bucketName string) (string, string, error) {
  334. db.mu.RLock()
  335. defer db.mu.RUnlock()
  336. for _, config := range db.bucketConfigs {
  337. if config.BucketName == bucketName {
  338. return config.AccountID, config.BucketID, nil
  339. }
  340. }
  341. return "", "", fmt.Errorf("bucket not found: %s", bucketName)
  342. }
  343. // Close closes the database
  344. func (db *FileBasedKVDB) Close() error {
  345. db.mu.Lock()
  346. defer db.mu.Unlock()
  347. return db.save()
  348. }