-
Notifications
You must be signed in to change notification settings - Fork 0
/
storage.go
109 lines (89 loc) · 2.32 KB
/
storage.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
// Package metrica (storage.go) implements a version of a storage using the filesystem
package metrica
import (
"fmt"
"io"
"os"
"strings"
"sync"
"time"
)
// Counter is an alias for time.Time
type Counter time.Time
// Counters is a list of Counters
type Counters []Counter
// FileStorage is a struct that implements the Storage methods
type FileStorage struct {
mu *sync.Mutex
fileName string
}
// NewFileStorage initializes a new FileStorage
func NewFileStorage(mu *sync.Mutex, fileName string) *FileStorage {
return &FileStorage{
mu: mu,
fileName: fileName,
}
}
// Write save a Counter in the file
func (m *FileStorage) Write(c Counter) error {
m.mu.Lock()
defer m.mu.Unlock()
f, err := os.OpenFile(m.fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("error opening file: %v", err)
}
_, err = f.WriteString(fmt.Sprintf("%v\n", c.Format()))
if err != nil {
return fmt.Errorf("error writing file: %v", err)
}
return nil
}
// Read returns a list of Counters
func (m *FileStorage) Read() (Counters, error) {
m.mu.Lock()
defer m.mu.Unlock()
f, err := os.Open(m.fileName)
if err != nil {
return nil, fmt.Errorf("error opening file: %v", err)
}
defer func() {
_ = f.Close()
}()
fileData, err := io.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("error reading file: %v", err)
}
datetimes := strings.Split(string(fileData), "\n")
if datetimes[len(datetimes)-1] == "" {
datetimes = datetimes[:len(datetimes)-1]
}
return parseDatetimesToCounters(datetimes)
}
// Format returns the datetime in RFC3339Nano format
func (c Counter) Format() string {
return time.Time(c).Format(time.RFC3339Nano)
}
// Count60sec returns the number of datetimes in the last 60 seconds
func (cs Counters) Count60sec() int64 {
currentTime := time.Now()
var count int64
lowerLimit := currentTime.Add(-60 * time.Second)
for _, c := range cs {
t := time.Time(c)
if t.After(lowerLimit) && t.Before(currentTime) {
count++
}
}
return count
}
func parseDatetimesToCounters(datetimes []string) (Counters, error) {
var counters []Counter
for _, datetime := range datetimes {
t, err := time.Parse(time.RFC3339Nano, datetime)
if err != nil {
return nil, fmt.Errorf("error parsing datetime: %v", err)
}
counters = append(counters, Counter(t))
}
return counters, nil
}