-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.go
173 lines (156 loc) · 3.32 KB
/
util.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package watched
import (
"bytes"
"errors"
"fmt"
"os"
"strings"
"time"
)
// Format 1: Journal.201206082715.01.log
// Format 2: Journal.2023-12-27T134309.01.log
func IsJournalFile(name string) (format int) {
if !strings.HasPrefix(name, "Journal.") || !strings.HasSuffix(name, ".log") {
return 0
}
switch len(name) { // TODO just a heuristic
case 27:
return 1
case 32:
return 2
}
return -1 // Allows to accept synthetic names e.g. for tests
}
func JournalFileCmpr(f, g string) int {
ff, gf := IsJournalFile(f), IsJournalFile(g)
switch ff {
case 2:
if gf == 2 {
return strings.Compare(f, g)
}
return 1
case 1:
switch gf {
case 2:
return -1
case 1:
return strings.Compare(f, g)
}
return 1
case -1:
switch gf {
case -1:
return strings.Compare(f, g)
case 1, 2:
return -1
}
return 1
case 0:
if gf == 0 {
return 0
}
return -1
}
return 0
}
// TODO Use [JouralFileCmpr]
func NewestJournal(inDir string) (res string, err error) {
dir, err := os.Open(inDir)
if err != nil {
return "", err
}
defer dir.Close()
var maxTime time.Time
infos, err := dir.Readdir(1)
for len(infos) > 0 && err == nil {
info := infos[0]
if IsJournalFile(info.Name()) != 0 && (info.ModTime().After(maxTime) || len(res) == 0) {
res = info.Name()
maxTime = info.ModTime()
}
infos, err = dir.Readdir(1)
}
return res, nil
}
func IsStatusFile(name string) StatusType {
return statsFiles[name]
}
var statsFiles = make(map[string]StatusType)
func init() {
for i := StatusType(1); i < EndStatusType; i++ {
statsFiles[i.String()+".json"] = i
}
}
func PeekTime(str []byte) (t time.Time, err error) {
idx := bytes.Index(str, timestampTag)
if idx < 0 {
estr := string(str)
if len(estr) > 50 {
estr = string(str[:50]) + "…"
}
return time.Time{}, fmt.Errorf("no timestamp in event: %s", estr)
}
val := str[idx+13 : idx+33]
return time.Parse(time.RFC3339, string(val))
}
func PeekEvent(str []byte) (event string, err error) {
idx := bytes.Index(str, eventTag)
if idx < 0 {
return "", errors.New("no event type in event")
}
str = str[idx+9:]
idx = bytes.IndexByte(str, '"')
if idx < 0 {
return "", errors.New("cannot find end of event type")
}
return string(str[:idx]), nil
}
func Peek(str []byte) (t time.Time, event string, err error) {
if t, err = PeekTime(str); err != nil {
return t, "", err
}
event, err = PeekEvent(str)
return t, event, err
}
const (
timestamTagStr = `"timestamp":`
eventTagStr = `"event":`
)
var (
timestampTag = []byte(timestamTagStr)
eventTag = []byte(eventTagStr)
)
type JournalProgress struct {
file string
eNo int
}
func (jp *JournalProgress) File() string { return jp.file }
func (jp *JournalProgress) EventNo() int { return jp.eNo }
func (jp *JournalProgress) Reset() {
jp.file = ""
jp.eNo = 0
}
func (jp *JournalProgress) IsNew(file string, n int) bool {
if IsJournalFile(file) == 0 || n < 1 {
return false
}
fcmpr := JournalFileCmpr(file, jp.file)
switch {
case fcmpr > 0:
return true
case fcmpr < 0:
return false
}
return n > jp.eNo
}
func (jp *JournalProgress) Set(file string, n int) error {
switch {
case IsJournalFile(file) == 0:
return fmt.Errorf("illegal journal file name '%s'", file)
case n < 1:
return fmt.Errorf("illegal event no %d in journal file '%s'", n, file)
}
jp.file = file
jp.eNo = n
return nil
}