-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
Copy pathduration.go
130 lines (111 loc) · 2.83 KB
/
duration.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
package notification
import (
"bytes"
"fmt"
"strconv"
"time"
"unicode"
"unicode/utf8"
"github.com/influxdata/flux"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/codes"
)
// Duration is a custom type used for generating flux compatible durations.
type Duration ast.DurationLiteral
// TimeDuration convert notification.Duration to time.Duration.
func (d Duration) TimeDuration() time.Duration {
dl := ast.DurationLiteral(d)
dd, _ := ast.DurationFrom(&dl, time.Time{})
return dd
}
// MarshalJSON turns a Duration into a JSON-ified string.
func (d Duration) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteByte('"')
for _, d := range d.Values {
b.WriteString(strconv.Itoa(int(d.Magnitude)))
b.WriteString(d.Unit)
}
b.WriteByte('"')
return b.Bytes(), nil
}
// UnmarshalJSON turns a flux duration literal into a Duration.
func (d *Duration) UnmarshalJSON(b []byte) error {
dur, err := parseDuration(string(b[1 : len(b)-1]))
if err != nil {
return err
}
*d = Duration{Values: dur}
return nil
}
// FromTimeDuration converts a time.Duration to a notification.Duration type.
func FromTimeDuration(d time.Duration) (Duration, error) {
dur, err := parseDuration(d.String())
if err != nil {
return Duration{}, err
}
return Duration{Values: dur}, nil
}
// TODO(jsternberg): This file copies over code from an internal package
// because we need them from an internal package and the only way they
// are exposed is through a package that depends on the core flux parser.
// We want to avoid a dependency on the core parser so we copy these
// implementations.
//
// In the future, we should consider exposing these functions from flux
// in a non-internal package outside of the parser package.
// parseDuration will convert a string into components of the duration.
func parseDuration(lit string) ([]ast.Duration, error) {
var values []ast.Duration
for len(lit) > 0 {
n := 0
for n < len(lit) {
ch, size := utf8.DecodeRuneInString(lit[n:])
if size == 0 {
panic("invalid rune in duration")
}
if !unicode.IsDigit(ch) {
break
}
n += size
}
if n == 0 {
return nil, &flux.Error{
Code: codes.Invalid,
Msg: fmt.Sprintf("invalid duration %s", lit),
}
}
magnitude, err := strconv.ParseInt(lit[:n], 10, 64)
if err != nil {
return nil, err
}
lit = lit[n:]
n = 0
for n < len(lit) {
ch, size := utf8.DecodeRuneInString(lit[n:])
if size == 0 {
panic("invalid rune in duration")
}
if !unicode.IsLetter(ch) {
break
}
n += size
}
if n == 0 {
return nil, &flux.Error{
Code: codes.Invalid,
Msg: fmt.Sprintf("duration is missing a unit: %s", lit),
}
}
unit := lit[:n]
if unit == "µs" {
unit = "us"
}
values = append(values, ast.Duration{
Magnitude: magnitude,
Unit: unit,
})
lit = lit[n:]
}
return values, nil
}