10000 fs: added weekday schedule into --bwlimit - fixes #1822 · devdevmac/rclone@56e1e82 · GitHub
[go: up one dir, main page]

Skip to content

Commit 56e1e82

Browse files
TenGumisncw
authored andcommitted
fs: added weekday schedule into --bwlimit - fixes rclone#1822
1 parent 8442498 commit 56e1e82

File tree

3 files changed

+396
-77
lines changed

3 files changed

+396
-77
lines changed

docs/content/docs.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,19 +279,40 @@ For example, to limit bandwidth usage to 10 MBytes/s use `--bwlimit 10M`
279279

280280
It is also possible to specify a "timetable" of limits, which will cause
281281
certain limits to be applied at certain times. To specify a timetable, format your
282-
entries as "HH:MM,BANDWIDTH HH:MM,BANDWIDTH...".
282+
entries as "WEEKDAY-HH:MM,BANDWIDTH WEEKDAY-HH:MM,BANDWIDTH..." where:
283+
WEEKDAY is optional element.
284+
It could be writen as whole world or only using 3 first characters.
285+
HH:MM is an hour from 00:00 to 23:59.
283286

284287
An example of a typical timetable to avoid link saturation during daytime
285288
working hours could be:
286289

287290
`--bwlimit "08:00,512 12:00,10M 13:00,512 18:00,30M 23:00,off"`
288291

289-
In this example, the transfer bandwidth will be set to 512kBytes/sec at 8am.
292+
In this example, the transfer bandwidth will be every day set to 512kBytes/sec at 8am.
290293
At noon, it will raise to 10Mbytes/s, and drop back to 512kBytes/sec at 1pm.
291294
At 6pm, the bandwidth limit will be set to 30MBytes/s, and at 11pm it will be
292295
completely disabled (full speed). Anything between 11pm and 8am will remain
293296
unlimited.
294297

298+
An example of timetable with WEEKDAY could be:
299+
300+
`--bwlimit "Mon-00:00,512 Fri-23:59,10M Sat-10:00,1M Sun-20:00,off"`
301+
302+
It mean that, the transfer bandwidh will be set to 512kBytes/sec on Monday.
303+
It will raise to 10Mbytes/s before the end of Friday.
304+
At 10:00 on Sunday it will be set to 1Mbyte/s.
305+
From 20:00 at Sunday will be unlimited.
306+
307+
Timeslots without weekday are extended to whole week.
308+
So this one example:
309+
310+
`--bwlimit "Mon-00:00,512 12:00,1M Sun-20:00,off"`
311+
312+
Is equal to this:
313+
314+
`--bwlimit "Mon-00:00,512Mon-12:00,1M Tue-12:00,1M Wed-12:00,1M Thu-12:00,1M Fri-12:00,1M Sat-12:00,1M Sun-12:00,1M Sun-20:00,off"`
315+
295316
Bandwidth limits only apply to the data transfer. They don't apply to the
296317
bandwidth of the directory listings etc.
297318

fs/bwtimetable.go

Lines changed: 121 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111

1212
// BwTimeSlot represents a bandwidth configuration at a point in time.
1313
type BwTimeSlot struct {
14-
HHMM int
15-
Bandwidth SizeSuffix
14+
DayOfTheWeek int
15+
HHMM int
16+
Bandwidth SizeSuffix
1617
}
1718

1819
// BwTimetable contains all configured time slots.
@@ -22,15 +23,64 @@ type BwTimetable []BwTimeSlot
2223
func (x BwTimetable) String() string {
2324
ret := []string{}
2425
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()))
2627
}
2728
return strings.Join(ret, " ")
2829
}
2930

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+
3080
// Set the bandwidth timetable.
3181
func (x *BwTimetable) Set(s string) error {
3282
// 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"
3484
// If only a single bandwidth identifier is provided, we assume constant bandwidth.
3585

3686
if len(s) == 0 {
@@ -42,6 +92,7 @@ func (x *BwTimetable) Set(s string) error {
4292
if err := ts.Bandwidth.Set(s); err != nil {
4393
return err
4494
}
95+
ts.DayOfTheWeek = 0
4596
ts.HHMM = 0
4697
*x = BwTimetable{ts}
4798
return nil
@@ -50,69 +101,100 @@ func (x *BwTimetable) Set(s string) error {
50101
for _, tok := range strings.Split(s, " ") {
51102
tv := strings.Split(tok, ",")
52103

53-
// Format must be HH:MM,BW
104+
// Format must be dayOfWeek-HH:MM,BW
54105
if len(tv) != 2 {
55106
return errors.Errorf("invalid time/bandwidth specification: %q", tok)
56107
}
57108

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)
80154
}
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)
86155
}
87156
return nil
88157
}
89158

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+
90173
// LimitAt returns a BwTimeSlot for the time requested.
91174
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.
93176
if len(x) == 0 {
94-
return BwTimeSlot{HHMM: 0, Bandwidth: -1}
177+
return BwTimeSlot{DayOfTheWeek: 0, HHMM: 0, Bandwidth: -1}
95178
}
96179

97-
HHMM := tt.Hour()*100 + tt.Minute()
180+
dayOfWeekHHMM := int(tt.Weekday())*10000 + tt.Hour()*100 + tt.Minute()
98181

99182
// By default, we return the last element in the timetable. This
100183
// satisfies two conditions: 1) If there's only one element it
101184
// 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.
103186
// there's only one time slot in the timetable.
104187
ret := x[len(x)-1]
105-
106188
mindif := 0
107189
first := true
108190

109191
// Look for most recent time slot.
110192
for _, ts := range x {
111193
// Ignore the past
112-
if HHMM < ts.HHMM {
194+
if dayOfWeekHHMM < (ts.DayOfTheWeek*10000)+ts.HHMM {
113195
continue
114196
}
115-
dif := ((HHMM / 100 * 60) + (HHMM % 100)) - ((ts.HHMM / 100 * 60) + (ts.HHMM % 100))
197+
dif := timeDiff(dayOfWeekHHMM, (ts.DayOfTheWeek*10000)+ts.HHMM)
116198
if first {
117199
mindif = dif
118200
first = false

0 commit comments

Comments
 (0)
0