mirror of
https://github.com/rclone/rclone
synced 2024-12-02 11:53:45 +01:00
11da2a6c9b
The purpose of this is to make it easier to maintain and eventually to allow the rclone backends to be re-used in other projects without having to use the rclone configuration system. The new code layout is documented in CONTRIBUTING.
133 lines
3.2 KiB
Go
133 lines
3.2 KiB
Go
package fs
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// BwTimeSlot represents a bandwidth configuration at a point in time.
|
|
type BwTimeSlot struct {
|
|
HHMM int
|
|
Bandwidth SizeSuffix
|
|
}
|
|
|
|
// BwTimetable contains all configured time slots.
|
|
type BwTimetable []BwTimeSlot
|
|
|
|
// String returns a printable representation of BwTimetable.
|
|
func (x BwTimetable) String() string {
|
|
ret := []string{}
|
|
for _, ts := range x {
|
|
ret = append(ret, fmt.Sprintf("%04.4d,%s", ts.HHMM, ts.Bandwidth.String()))
|
|
}
|
|
return strings.Join(ret, " ")
|
|
}
|
|
|
|
// Set the bandwidth timetable.
|
|
func (x *BwTimetable) Set(s string) error {
|
|
// The timetable is formatted as:
|
|
// "hh:mm,bandwidth hh:mm,banwidth..." ex: "10:00,10G 11:30,1G 18:00,off"
|
|
// If only a single bandwidth identifier is provided, we assume constant bandwidth.
|
|
|
|
if len(s) == 0 {
|
|
return errors.New("empty string")
|
|
}
|
|
// Single value without time specification.
|
|
if !strings.Contains(s, " ") && !strings.Contains(s, ",") {
|
|
ts := BwTimeSlot{}
|
|
if err := ts.Bandwidth.Set(s); err != nil {
|
|
return err
|
|
}
|
|
ts.HHMM = 0
|
|
*x = BwTimetable{ts}
|
|
return nil
|
|
}
|
|
|
|
for _, tok := range strings.Split(s, " ") {
|
|
tv := strings.Split(tok, ",")
|
|
|
|
// Format must be HH:MM,BW
|
|
if len(tv) != 2 {
|
|
return errors.Errorf("invalid time/bandwidth specification: %q", tok)
|
|
}
|
|
|
|
// Basic timespec sanity checking
|
|
HHMM := tv[0]
|
|
if len(HHMM) != 5 {
|
|
return errors.Errorf("invalid time specification (hh:mm): %q", HHMM)
|
|
}
|
|
hh, err := strconv.Atoi(HHMM[0:2])
|
|
if err != nil {
|
|
return errors.Errorf("invalid hour in time specification %q: %v", HHMM, err)
|
|
}
|
|
if hh < 0 || hh > 23 {
|
|
return errors.Errorf("invalid hour (must be between 00 and 23): %q", hh)
|
|
}
|
|
mm, err := strconv.Atoi(HHMM[3:])
|
|
if err != nil {
|
|
return errors.Errorf("invalid minute in time specification: %q: %v", HHMM, err)
|
|
}
|
|
if mm < 0 || mm > 59 {
|
|
return errors.Errorf("invalid minute (must be between 00 and 59): %q", hh)
|
|
}
|
|
|
|
ts := BwTimeSlot{
|
|
HHMM: (hh * 100) + mm,
|
|
}
|
|
// Bandwidth limit for this time slot.
|
|
if err := ts.Bandwidth.Set(tv[1]); err != nil {
|
|
return err
|
|
}
|
|
*x = append(*x, ts)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LimitAt returns a BwTimeSlot for the time requested.
|
|
func (x BwTimetable) LimitAt(tt time.Time) BwTimeSlot {
|
|
// If the timetable is empty, we return an unlimited BwTimeSlot starting at midnight.
|
|
if len(x) == 0 {
|
|
return BwTimeSlot{HHMM: 0, Bandwidth: -1}
|
|
}
|
|
|
|
HHMM := tt.Hour()*100 + tt.Minute()
|
|
|
|
// By default, we return the last element in the timetable. This
|
|
// satisfies two conditions: 1) If there's only one element it
|
|
// will always be selected, and 2) The last element of the table
|
|
// will "wrap around" until overriden by an earlier time slot.
|
|
// there's only one time slot in the timetable.
|
|
ret := x[len(x)-1]
|
|
|
|
mindif := 0
|
|
first := true
|
|
|
|
// Look for most recent time slot.
|
|
for _, ts := range x {
|
|
// Ignore the past
|
|
if HHMM < ts.HHMM {
|
|
continue
|
|
}
|
|
dif := ((HHMM / 100 * 60) + (HHMM % 100)) - ((ts.HHMM / 100 * 60) + (ts.HHMM % 100))
|
|
if first {
|
|
mindif = dif
|
|
first = false
|
|
}
|
|
if dif <= mindif {
|
|
mindif = dif
|
|
ret = ts
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
// Type of the value
|
|
func (x BwTimetable) Type() string {
|
|
return "BwTimetable"
|
|
}
|