store.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package store
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "os"
  8. "path/filepath"
  9. "sync"
  10. "github.com/google/uuid"
  11. )
  12. type Store struct {
  13. ID string `json:"id"`
  14. FirstTimeRun bool `json:"first-time-run"`
  15. }
  16. var (
  17. lock sync.Mutex
  18. store Store
  19. )
  20. func GetID() string {
  21. lock.Lock()
  22. defer lock.Unlock()
  23. if store.ID == "" {
  24. initStore()
  25. }
  26. return store.ID
  27. }
  28. func GetFirstTimeRun() bool {
  29. lock.Lock()
  30. defer lock.Unlock()
  31. if store.ID == "" {
  32. initStore()
  33. }
  34. return store.FirstTimeRun
  35. }
  36. func SetFirstTimeRun(val bool) {
  37. lock.Lock()
  38. defer lock.Unlock()
  39. if store.FirstTimeRun == val {
  40. return
  41. }
  42. store.FirstTimeRun = val
  43. writeStore(getStorePath())
  44. }
  45. // lock must be held
  46. func initStore() {
  47. storeFile, err := os.Open(getStorePath())
  48. if err == nil {
  49. defer storeFile.Close()
  50. err = json.NewDecoder(storeFile).Decode(&store)
  51. if err == nil {
  52. slog.Debug(fmt.Sprintf("loaded existing store %s - ID: %s", getStorePath(), store.ID))
  53. return
  54. }
  55. } else if !errors.Is(err, os.ErrNotExist) {
  56. slog.Debug(fmt.Sprintf("unexpected error searching for store: %s", err))
  57. }
  58. slog.Debug("initializing new store")
  59. store.ID = uuid.New().String()
  60. writeStore(getStorePath())
  61. }
  62. func writeStore(storeFilename string) {
  63. ollamaDir := filepath.Dir(storeFilename)
  64. _, err := os.Stat(ollamaDir)
  65. if errors.Is(err, os.ErrNotExist) {
  66. if err := os.MkdirAll(ollamaDir, 0o755); err != nil {
  67. slog.Error(fmt.Sprintf("create ollama dir %s: %v", ollamaDir, err))
  68. return
  69. }
  70. }
  71. payload, err := json.Marshal(store)
  72. if err != nil {
  73. slog.Error(fmt.Sprintf("failed to marshal store: %s", err))
  74. return
  75. }
  76. fp, err := os.OpenFile(storeFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o755)
  77. if err != nil {
  78. slog.Error(fmt.Sprintf("write store payload %s: %v", storeFilename, err))
  79. return
  80. }
  81. defer fp.Close()
  82. if n, err := fp.Write(payload); err != nil || n != len(payload) {
  83. slog.Error(fmt.Sprintf("write store payload %s: %d vs %d -- %v", storeFilename, n, len(payload), err))
  84. return
  85. }
  86. slog.Debug("Store contents: " + string(payload))
  87. slog.Info(fmt.Sprintf("wrote store: %s", storeFilename))
  88. }