mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 15:38:57 +01:00
jottacloud: refactor timestamp handling
Jottacloud have several different apis and endpoints using a mix of different timestamp formats. In existing code the list operation (after the recent liststream implementation) uses format from golang's time.RFC3339 constant. Uploads (using the allocate api) uses format from a hard coded constant with value identical to golang's time.RFC3339. And then we have the classic JFS time format, which is similar to RFC3339 but not identical, using a different constant. Also the naming is a bit confusing, since the term api is used both as a generic term and also as a reference to the newer format used in the api subdomain where the allocate endpoint is located. This commit refactors these things a bit.
This commit is contained in:
parent
cc8dde402f
commit
4829527dac
@ -8,42 +8,69 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// default time format for almost all request and responses
|
// default time format historically used for all request and responses.
|
||||||
timeFormat = "2006-01-02-T15:04:05Z0700"
|
// Similar to time.RFC3339, but with an extra '-' in front of 'T',
|
||||||
// the API server seems to use a different format
|
// and no ':' separator in timezone offset. Some newer endpoints have
|
||||||
apiTimeFormat = "2006-01-02T15:04:05Z07:00"
|
// moved to proper time.RFC3339 conformant format instead.
|
||||||
|
jottaTimeFormat = "2006-01-02-T15:04:05Z0700"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Time represents time values in the Jottacloud API. It uses a custom RFC3339 like format.
|
// unmarshalXML turns XML into a Time
|
||||||
type Time time.Time
|
func unmarshalXMLTime(d *xml.Decoder, start xml.StartElement, timeFormat string) (time.Time, error) {
|
||||||
|
|
||||||
// UnmarshalXML turns XML into a Time
|
|
||||||
func (t *Time) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
||||||
var v string
|
var v string
|
||||||
if err := d.DecodeElement(&v, &start); err != nil {
|
if err := d.DecodeElement(&v, &start); err != nil {
|
||||||
return err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
if v == "" {
|
if v == "" {
|
||||||
*t = Time(time.Time{})
|
return time.Time{}, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
newTime, err := time.Parse(timeFormat, v)
|
newTime, err := time.Parse(timeFormat, v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*t = Time(newTime)
|
return newTime, nil
|
||||||
}
|
}
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// JottaTime represents time values in the classic API using a custom RFC3339 like format
|
||||||
|
type JottaTime time.Time
|
||||||
|
|
||||||
|
// String returns JottaTime string in Jottacloud classic format
|
||||||
|
func (t JottaTime) String() string { return time.Time(t).Format(jottaTimeFormat) }
|
||||||
|
|
||||||
|
// UnmarshalXML turns XML into a JottaTime
|
||||||
|
func (t *JottaTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
|
tm, err := unmarshalXMLTime(d, start, jottaTimeFormat)
|
||||||
|
*t = JottaTime(tm)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalXML turns a Time into XML
|
// MarshalXML turns a JottaTime into XML
|
||||||
func (t *Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (t *JottaTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
return e.EncodeElement(t.String(), start)
|
return e.EncodeElement(t.String(), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return Time string in Jottacloud format
|
// Rfc3339Time represents time values in the newer APIs using standard RFC3339 format
|
||||||
func (t Time) String() string { return time.Time(t).Format(timeFormat) }
|
type Rfc3339Time time.Time
|
||||||
|
|
||||||
// APIString returns Time string in Jottacloud API format
|
// String returns Rfc3339Time string in Jottacloud RFC3339 format
|
||||||
func (t Time) APIString() string { return time.Time(t).Format(apiTimeFormat) }
|
func (t Rfc3339Time) String() string { return time.Time(t).Format(time.RFC3339) }
|
||||||
|
|
||||||
|
// UnmarshalXML turns XML into a Rfc3339Time
|
||||||
|
func (t *Rfc3339Time) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
|
tm, err := unmarshalXMLTime(d, start, time.RFC3339)
|
||||||
|
*t = Rfc3339Time(tm)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalXML turns a Rfc3339Time into XML
|
||||||
|
func (t *Rfc3339Time) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
|
return e.EncodeElement(t.String(), start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON turns a Rfc3339Time into JSON
|
||||||
|
func (t *Rfc3339Time) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf("\"%s\"", t.String())), nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoginToken is struct representing the login token generated in the WebUI
|
// LoginToken is struct representing the login token generated in the WebUI
|
||||||
type LoginToken struct {
|
type LoginToken struct {
|
||||||
@ -333,9 +360,9 @@ type JottaFolder struct {
|
|||||||
Name string `xml:"name,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Deleted Flag `xml:"deleted,attr"`
|
Deleted Flag `xml:"deleted,attr"`
|
||||||
Path string `xml:"path"`
|
Path string `xml:"path"`
|
||||||
CreatedAt Time `xml:"created"`
|
CreatedAt JottaTime `xml:"created"`
|
||||||
ModifiedAt Time `xml:"modified"`
|
ModifiedAt JottaTime `xml:"modified"`
|
||||||
Updated Time `xml:"updated"`
|
Updated JottaTime `xml:"updated"`
|
||||||
Folders []JottaFolder `xml:"folders>folder"`
|
Folders []JottaFolder `xml:"folders>folder"`
|
||||||
Files []JottaFile `xml:"files>file"`
|
Files []JottaFile `xml:"files>file"`
|
||||||
}
|
}
|
||||||
@ -365,9 +392,9 @@ type JottaFile struct {
|
|||||||
PublicURI string `xml:"publicURI"`
|
PublicURI string `xml:"publicURI"`
|
||||||
PublicSharePath string `xml:"publicSharePath"`
|
PublicSharePath string `xml:"publicSharePath"`
|
||||||
State string `xml:"currentRevision>state"`
|
State string `xml:"currentRevision>state"`
|
||||||
CreatedAt Time `xml:"currentRevision>created"`
|
CreatedAt JottaTime `xml:"currentRevision>created"`
|
||||||
ModifiedAt Time `xml:"currentRevision>modified"`
|
ModifiedAt JottaTime `xml:"currentRevision>modified"`
|
||||||
Updated Time `xml:"currentRevision>updated"`
|
Updated JottaTime `xml:"currentRevision>updated"`
|
||||||
Size int64 `xml:"currentRevision>size"`
|
Size int64 `xml:"currentRevision>size"`
|
||||||
MimeType string `xml:"currentRevision>mime"`
|
MimeType string `xml:"currentRevision>mime"`
|
||||||
MD5 string `xml:"currentRevision>md5"`
|
MD5 string `xml:"currentRevision>md5"`
|
||||||
|
@ -932,25 +932,6 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
|||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type listStreamTime time.Time
|
|
||||||
|
|
||||||
func (c *listStreamTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
||||||
var v string
|
|
||||||
if err := d.DecodeElement(&v, &start); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t, err := time.Parse(time.RFC3339, v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*c = listStreamTime(t)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c listStreamTime) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(fmt.Sprintf("\"%s\"", time.Time(c).Format(time.RFC3339))), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseListRStream(ctx context.Context, r io.Reader, trimPrefix string, filesystem *Fs, callback func(fs.DirEntry) error) error {
|
func parseListRStream(ctx context.Context, r io.Reader, trimPrefix string, filesystem *Fs, callback func(fs.DirEntry) error) error {
|
||||||
|
|
||||||
type stats struct {
|
type stats struct {
|
||||||
@ -964,8 +945,8 @@ func parseListRStream(ctx context.Context, r io.Reader, trimPrefix string, files
|
|||||||
Name string `xml:"filename"`
|
Name string `xml:"filename"`
|
||||||
Checksum string `xml:"md5"`
|
Checksum string `xml:"md5"`
|
||||||
Size int64 `xml:"size"`
|
Size int64 `xml:"size"`
|
||||||
Modified listStreamTime `xml:"modified"`
|
Modified api.Rfc3339Time `xml:"modified"` // Note: Liststream response includes 3 decimal milliseconds, but we ignore them since there is second precision everywhere else
|
||||||
Created listStreamTime `xml:"created"`
|
Created api.Rfc3339Time `xml:"created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type xmlFolder struct {
|
type xmlFolder struct {
|
||||||
@ -1228,7 +1209,7 @@ func (f *Fs) createOrUpdate(ctx context.Context, file string, modTime time.Time,
|
|||||||
|
|
||||||
opts.Parameters.Set("cphash", "true")
|
opts.Parameters.Set("cphash", "true")
|
||||||
|
|
||||||
fileDate := api.Time(modTime).String()
|
fileDate := api.JottaTime(modTime).String()
|
||||||
opts.ExtraHeaders["JSize"] = strconv.FormatInt(size, 10)
|
opts.ExtraHeaders["JSize"] = strconv.FormatInt(size, 10)
|
||||||
opts.ExtraHeaders["JMd5"] = md5
|
opts.ExtraHeaders["JMd5"] = md5
|
||||||
opts.ExtraHeaders["JCreated"] = fileDate
|
opts.ExtraHeaders["JCreated"] = fileDate
|
||||||
@ -1749,7 +1730,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
|
|||||||
Options: options,
|
Options: options,
|
||||||
ExtraHeaders: make(map[string]string),
|
ExtraHeaders: make(map[string]string),
|
||||||
}
|
}
|
||||||
fileDate := api.Time(src.ModTime(ctx)).APIString()
|
fileDate := api.Rfc3339Time(src.ModTime(ctx)).String()
|
||||||
|
|
||||||
// the allocate request
|
// the allocate request
|
||||||
var request = api.AllocateFileRequest{
|
var request = api.AllocateFileRequest{
|
||||||
|
Loading…
Reference in New Issue
Block a user