db.go 1.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package jsondb provides a trivial "database": a Go object saved to
  4. // disk as JSON.
  5. package jsondb
  6. import (
  7. "encoding/json"
  8. "errors"
  9. "io/fs"
  10. "os"
  11. "tailscale.com/atomicfile"
  12. )
  13. // DB is a database backed by a JSON file.
  14. type DB[T any] struct {
  15. // Data is the contents of the database.
  16. Data *T
  17. path string
  18. }
  19. // Open opens the database at path, creating it with a zero value if
  20. // necessary.
  21. func Open[T any](path string) (*DB[T], error) {
  22. bs, err := os.ReadFile(path)
  23. if errors.Is(err, fs.ErrNotExist) {
  24. return &DB[T]{
  25. Data: new(T),
  26. path: path,
  27. }, nil
  28. } else if err != nil {
  29. return nil, err
  30. }
  31. var val T
  32. if err := json.Unmarshal(bs, &val); err != nil {
  33. return nil, err
  34. }
  35. return &DB[T]{
  36. Data: &val,
  37. path: path,
  38. }, nil
  39. }
  40. // Save writes db.Data back to disk.
  41. func (db *DB[T]) Save() error {
  42. bs, err := json.Marshal(db.Data)
  43. if err != nil {
  44. return err
  45. }
  46. return atomicfile.WriteFile(db.path, bs, 0600)
  47. }