-
Notifications
You must be signed in to change notification settings - Fork 27
/
model.go
136 lines (110 loc) · 3.02 KB
/
model.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package model
import (
"crypto/md5"
"encoding/json"
"fmt"
"os"
"os/user"
"path/filepath"
"time"
"github.com/timeglass/glass/_vendor/github.com/boltdb/bolt"
"github.com/timeglass/glass/_vendor/github.com/hashicorp/errwrap"
)
type Model struct {
repoDir string
repoDirHash string
}
func New(dir string) *Model {
hash := md5.Sum([]byte(dir))
return &Model{
repoDir: dir,
repoDirHash: fmt.Sprintf("%x", hash),
}
}
func (m *Model) Open() (*bolt.DB, error) {
u, err := user.Current()
if err != nil {
return nil, errwrap.Wrapf("Failed to detect current user for opening database: {{err}}", err)
}
dbdir := filepath.Join(u.HomeDir, ".timeglass")
err = os.MkdirAll(dbdir, 0777)
if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("Failed to create directory '%s' for opening database: {{err}}", dbdir), err)
}
dbpath := filepath.Join(dbdir, m.repoDirHash+".db")
opts := &bolt.Options{Timeout: time.Millisecond * 100}
db, err := bolt.Open(dbpath, 0600, opts)
if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("Failed to open database '%s': {{err}}", dbpath), err)
}
return db, nil
}
func (m *Model) Close(db *bolt.DB) {
err := db.Close()
//@todo handle error?
_ = err
}
func (m *Model) UpsertDaemonInfo(info *Daemon) error {
db, err := m.Open()
if err != nil {
return err
}
defer m.Close(db)
return db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(MetaBucketName))
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Failed to create meta bucket: {{err}}"), err)
}
data, err := info.Serialize()
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Failed to serialize db deamon '%s': {{err}}", info.Addr), err)
}
b.Put([]byte(DeamonKeyName), data)
return nil
})
}
func (m *Model) ReadDaemonInfo() (*Daemon, error) {
var info *Daemon
db, err := m.Open()
if err != nil {
return nil, err
}
defer m.Close(db)
return info, db.View(func(tx *bolt.Tx) error {
var err error
b := tx.Bucket([]byte(MetaBucketName))
if b == nil {
info = &Daemon{}
return nil
}
data := b.Get([]byte(DeamonKeyName))
if data != nil {
info, err = NewDaemonFromSerialized(data)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("Failed to deserialize daemon from db: {{err}}, data: '%s'", string(data)), err)
}
}
return nil
})
}
func (m *Model) ReadConfig() (*Config, error) {
conf := DefaultConfig
p := filepath.Join(m.repoDir, "timeglass.json")
f, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
return conf, nil
}
return nil, errwrap.Wrapf(fmt.Sprintf("Error opening configuration file '%s', it does exist but: {{err}}", p), err)
}
dec := json.NewDecoder(f)
defer f.Close()
err = dec.Decode(conf)
if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("Error decoding '%s' as JSON, please check for syntax errors: {{err}}", p), err)
}
if time.Duration(conf.MBU) < time.Minute {
return nil, fmt.Errorf("configuration 'mbu': An MBU of less then 1min is not supported, received: '%s'", conf.MBU)
}
return conf, nil
}