@@ -11,8 +11,9 @@ import (
11
11
12
12
// BwTimeSlot represents a bandwidth configuration at a point in time.
13
13
type BwTimeSlot struct {
14
- HHMM int
15
- Bandwidth SizeSuffix
14
+ DayOfTheWeek int
15
+ HHMM int
16
+ Bandwidth SizeSuffix
16
17
}
17
18
18
19
// BwTimetable contains all configured time slots.
@@ -22,15 +23,64 @@ type BwTimetable []BwTimeSlot
22
23
func (x BwTimetable ) String () string {
23
24
ret := []string {}
24
25
for _ , ts := range x {
25
- ret = append (ret , fmt .Sprintf ("%04.4d,%s" , ts .HHMM , ts .Bandwidth .String ()))
26
+ ret = append (ret , fmt .Sprintf ("%s-% 04.4d,%s" , time . Weekday ( ts . DayOfTheWeek ) , ts .HHMM , ts .Bandwidth .String ()))
26
27
}
27
28
return strings .Join (ret , " " )
28
29
}
29
30
31
+ // Basic hour format checking
32
+ func validateHour (HHMM string ) error {
33
+ if len (HHMM ) != 5 {
34
+ return errors .Errorf ("invalid time specification (hh:mm): %q" , HHMM )
35
+ }
36
+ hh , err := strconv .Atoi (HHMM [0 :2 ])
37
+ if err != nil {
38
+ return errors .Errorf ("invalid hour in time specification %q: %v" , HHMM , err )
39
+ }
40
+ if hh < 0 || hh > 23 {
41
+ return errors .Errorf ("invalid hour (must be between 00 and 23): %q" , hh )
42
+ }
43
+ mm , err := strconv .Atoi (HHMM [3 :])
44
+ if err != nil {
45
+ return errors .Errorf ("invalid minute in time specification: %q: %v" , HHMM , err )
46
+ }
47
+ if mm < 0 || mm > 59 {
48
+ return errors .Errorf ("invalid minute (must be between 00 and 59): %q" , hh )
49
+ }
50
+ return nil
51
+ }
52
+
53
+ // Basic weekday format checking
54
+ func parseWeekday (dayOfWeek string ) (int , error ) {
55
+ dayOfWeek = strings .ToLower (dayOfWeek )
56
+ if dayOfWeek == "sun" || dayOfWeek == "sunday" {
57
+ return 0 , nil
58
+ }
59
+ if dayOfWeek == "mon" || dayOfWeek == "monday" {
60
+ return 1 , nil
61
+ }
62
+ if dayOfWeek == "tue" || dayOfWeek == "tuesday" {
63
+ return 2 , nil
64
+ }
65
+ if dayOfWeek == "wed" || dayOfWeek == "wednesday" {
66
+ return 3 , nil
67
+ }
68
+ if dayOfWeek == "thu" || dayOfWeek == "thursday" {
69
+ return 4 , nil
70
+ }
71
+ if dayOfWeek == "fri" || dayOfWeek == "friday" {
72
+ return 5 , nil
73
+ }
74
+ if dayOfWeek == "sat" || dayOfWeek == "saturday" {
75
+ return 6 , nil
76
+ }
77
+ return 0 , errors .Errorf ("invalid weekday: %q" , dayOfWeek )
78
+ }
79
+
30
80
// Set the bandwidth timetable.
31
81
func (x * BwTimetable ) Set (s string ) error {
32
82
// The timetable is formatted as:
33
- // "hh:mm,bandwidth hh:mm,banwidth..." ex: "10:00,10G 11:30,1G 18:00,off"
83
+ // "dayOfWeek- hh:mm,bandwidth dayOfWeek- hh:mm,banwidth..." ex: "Mon- 10:00,10G Mon- 11:30,1G Tue- 18:00,off"
34
84
// If only a single bandwidth identifier is provided, we assume constant bandwidth.
35
85
36
86
if len (s ) == 0 {
@@ -42,6 +92,7 @@ func (x *BwTimetable) Set(s string) error {
42
92
if err := ts .Bandwidth .Set (s ); err != nil {
43
93
return err
44
94
}
95
+ ts .DayOfTheWeek = 0
45
96
ts .HHMM = 0
46
97
* x = BwTimetable {ts }
47
98
return nil
@@ -50,69 +101,100 @@ func (x *BwTimetable) Set(s string) error {
50
101
for _ , tok := range strings .Split (s , " " ) {
51
102
tv := strings .Split (tok , "," )
52
103
53
- // Format must be HH:MM,BW
104
+ // Format must be dayOfWeek- HH:MM,BW
54
105
if len (tv ) != 2 {
55
106
return errors .Errorf ("invalid time/bandwidth specification: %q" , tok )
56
107
}
57
108
58
- // Basic timespec sanity checking
59
- HHMM := tv [0 ]
60
- if len (HHMM ) != 5 {
61
- return errors .Errorf ("invalid time specification (hh:mm): %q" , HHMM )
62
- }
63
- hh , err := strconv .Atoi (HHMM [0 :2 ])
64
- if err != nil {
65
- return errors .Errorf ("invalid hour in time specification %q: %v" , HHMM , err )
66
- }
67
- if hh < 0 || hh > 23 {
68
- return errors .Errorf ("invalid hour (must be between 00 and 23): %q" , hh )
69
- }
70
- mm , err := strconv .Atoi (HHMM [3 :])
71
- if err != nil {
72
- return errors .Errorf ("invalid minute in time specification: %q: %v" , HHMM , err )
73
- }
74
- if mm < 0 || mm > 59 {
75
- return errors .Errorf ("invalid minute (must be between 00 and 59): %q" , hh )
76
- }
77
-
78
- ts := BwTimeSlot {
79
- HHMM : (hh * 100 ) + mm ,
109
+ weekday := 0
110
+ HHMM := ""
111
+ if ! strings .Contains (tv [0 ], "-" ) {
112
+ HHMM = tv [0 ]
113
+ if err := validateHour (HHMM ); err != nil {
114
+ return err
115
+ }
116
+ for i := 0 ; i < 7 ; i ++ {
117
+ hh , _ := strconv .Atoi (HHMM [0 :2 ])
118
+ mm , _ := strconv .Atoi (HHMM [3 :])
119
+ ts := BwTimeSlot {
120
+ DayOfTheWeek : i ,
121
+ HHMM : (hh * 100 ) + mm ,
122
+ }
123
+ if err := ts .Bandwidth .Set (tv [1 ]); err != nil {
124
+ return err
125
+ }
126
+ * x = append (* x , ts )
127
+ }
128
+ } else {
129
+ timespec := strings .Split (tv [0 ], "-" )
130
+ if len (timespec ) != 2 {
131
+ return errors .Errorf ("invalid time specification: %q" , tv [0 ])
132
+ }
133
+ var err error
134
+ weekday , err = parseWeekday (timespec [0 ])
135
+ if err != nil {
136
+ return err
137
+ }
138
+ HHMM = timespec [1 ]
139
+ if err := validateHour (HHMM ); err != nil {
140
+ return err
141
+ }
142
+
143
+ hh , _ := strconv .Atoi (HHMM [0 :2 ])
144
+ mm , _ := strconv .Atoi (HHMM [3 :])
145
+ ts := BwTimeSlot {
146
+ DayOfTheWeek : weekday ,
147
+ HHMM : (hh * 100 ) + mm ,
148
+ }
149
+ // Bandwidth limit for this time slot.
150
+ if err := ts .Bandwidth .Set (tv [1 ]); err != nil {
151
+ return err
152
+ }
153
+ * x = append (* x , ts )
80
154
}
81
- // Bandwidth limit for this time slot.
82
- if err := ts .Bandwidth .Set (tv [1 ]); err != nil {
83
- return err
84
- }
85
- * x = append (* x , ts )
86
155
}
87
156
return nil
88
157
}
89
158
159
+ // Difference in minutes between lateDayOfWeekHHMM and earlyDayOfWeekHHMM
160
+ func timeDiff (lateDayOfWeekHHMM int , earlyDayOfWeekHHMM int ) int {
161
+
162
+ lateTimeMinutes := (lateDayOfWeekHHMM / 10000 ) * 24 * 60
163
+ lateTimeMinutes += ((lateDayOfWeekHHMM / 100 ) % 100 ) * 60
164
+ lateTimeMinutes += lateDayOfWeekHHMM % 100
165
+
166
+ earlyTimeMinutes := (earlyDayOfWeekHHMM / 10000 ) * 24 * 60
167
+ earlyTimeMinutes += ((earlyDayOfWeekHHMM / 100 ) % 100 ) * 60
168
+ earlyTimeMinutes += earlyDayOfWeekHHMM % 100
169
+
170
+ return lateTimeMinutes - earlyTimeMinutes
171
+ }
172
+
90
173
// LimitAt returns a BwTimeSlot for the time requested.
91
174
func (x BwTimetable ) LimitAt (tt time.Time ) BwTimeSlot {
92
- // If the timetable is empty, we return an unlimited BwTimeSlot starting at midnight.
175
+ // If the timetable is empty, we return an unlimited BwTimeSlot starting at Sunday midnight.
93
176
if len (x ) == 0 {
94
- return BwTimeSlot {HHMM : 0 , Bandwidth : - 1 }
177
+ return BwTimeSlot {DayOfTheWeek : 0 , HHMM : 0 , Bandwidth : - 1 }
95
178
}
96
179
97
- HHMM := tt .Hour ()* 100 + tt .Minute ()
180
+ dayOfWeekHHMM := int ( tt . Weekday ()) * 10000 + tt .Hour ()* 100 + tt .Minute ()
98
181
99
182
// By default, we return the last element in the timetable. This
100
183
// satisfies two conditions: 1) If there's only one element it
101
184
// will always be selected, and 2) The last element of the table
102
- // will "wrap around" until overriden by an earlier time slot.
185
+ // will "wrap around" until overridden by an earlier time slot.
103
186
// there's only one time slot in the timetable.
104
187
ret := x [len (x )- 1 ]
105
-
106
188
mindif := 0
107
189
first := true
108
190
109
191
// Look for most recent time slot.
110
192
for _ , ts := range x {
111
193
// Ignore the past
112
- if HHMM < ts .HHMM {
194
+ if dayOfWeekHHMM < ( ts . DayOfTheWeek * 10000 ) + ts .HHMM {
113
195
continue
114
196
}
115
- dif := (( HHMM / 100 * 60 ) + ( HHMM % 100 )) - (( ts .HHMM / 100 * 60 ) + ( ts .HHMM % 100 ) )
197
+ dif := timeDiff ( dayOfWeekHHMM , ( ts .DayOfTheWeek * 10000 ) + ts .HHMM )
116
198
if first {
117
199
mindif = dif
118
200
first = false
0 commit comments