forked from twinj/uuid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filesystem.go
119 lines (100 loc) · 2.56 KB
/
filesystem.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
// Package savers provides implementations for the uuid.Saver interface.
package savers
import (
"encoding/gob"
"github.com/myesui/uuid"
"log"
"os"
"path"
"time"
)
var _ uuid.Saver = &FileSystemSaver{}
func init() {
gob.Register(&uuid.Store{})
}
// FileSystemSaver implements the uuid.Saver interface.
type FileSystemSaver struct {
// A file to save the state to
// Used gob format on uuid.State entity
file *os.File
// Preferred location for the store
Path string
// Whether to log each save
Report bool
// The amount of time between each save call
time.Duration
// The next time to save
uuid.Timestamp
*log.Logger
}
func (o *FileSystemSaver) Init() uuid.Saver {
o.Logger = log.New(os.Stderr, "uuid-saver", log.LstdFlags)
o.Duration = 10 * time.Second
o.Path = path.Join(os.TempDir(), "myesui-uuid-generator-fs-saver.gob")
o.Timestamp = uuid.Now()
return o
}
// Save saves the given store to the filesystem.
func (o *FileSystemSaver) Save(store uuid.Store) {
if store.Timestamp >= o.Timestamp {
err := o.openAndDo(o.encode, &store)
if err == nil {
if o.Report {
o.Println("file system saver saved", store)
}
}
o.Timestamp = store.Add(o.Duration)
}
}
// Read reads and loads the Store from the filesystem.
func (o *FileSystemSaver) Read() (store uuid.Store, err error) {
store = uuid.Store{}
_, err = os.Stat(o.Path);
if err != nil {
if os.IsNotExist(err) {
dir, file := path.Split(o.Path)
if dir == "" || dir == "/" {
dir = os.TempDir()
}
o.Path = path.Join(dir, file)
err = os.MkdirAll(dir, os.ModeDir|0700)
if err == nil {
// If new encode blank store
goto open
}
}
goto failed
}
open:
err = o.openAndDo(o.decode, &store)
if err == nil {
o.Println("file system saver created", o.Path)
return
}
failed:
o.Println("file system saver read error - will autogenerate", err)
return
}
func (o *FileSystemSaver) openAndDo(fDo func(*uuid.Store), store *uuid.Store) (err error) {
o.file, err = os.OpenFile(o.Path, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0600)
defer o.file.Close()
if err == nil {
fDo(store)
return
}
o.Println("error opening file", err)
return
}
func (o *FileSystemSaver) encode(pStore *uuid.Store) {
// ensure reader state is ready for use
enc := gob.NewEncoder(o.file)
// swallow error for encode as its only for cyclic pointers
enc.Encode(&pStore)
}
func (o *FileSystemSaver) decode(store *uuid.Store) {
// ensure reader state is ready for use
o.file.Seek(0, 0)
dec := gob.NewDecoder(o.file)
// swallow error for encode as its only for cyclic pointers
dec.Decode(&store)
}