package upload import ( "encoding/json" "errors" "time" ) const ( // version is the max version of the config file format supported version = 1 ) var ( // ErrInvalidVersion is returned when the config file version is not supported. ErrInvalidVersion = errors.New("invalid version") // ErrUnsupportedStorageType is returned when the storage type is not supported. ErrUnsupportedStorageType = errors.New("unsupported storage type") ) // Duration is a wrapper around time.Duration that allows us to unmarshal type Duration time.Duration // MarshalJSON marshals the duration as a string func (d Duration) MarshalJSON() ([]byte, error) { return json.Marshal(time.Duration(d).String()) } // UnmarshalJSON unmarshals the duration from a string or a float64 func (d *Duration) UnmarshalJSON(b []byte) error { var v interface{} if err := json.Unmarshal(b, &v); err != nil { return err } switch value := v.(type) { case float64: *d = Duration(time.Duration(value)) return nil case string: tmp, err := time.ParseDuration(value) if err != nil { return err } *d = Duration(tmp) return nil default: return errors.New("invalid duration") } } // StorageType is a wrapper around string that allows us to unmarshal type StorageType string // UnmarshalJSON unmarshals the storage type from a string and validates it func (s *StorageType) UnmarshalJSON(b []byte) error { var v interface{} if err := json.Unmarshal(b, &v); err != nil { return err } switch value := v.(type) { case string: *s = StorageType(value) if *s != "s3" { return ErrUnsupportedStorageType } return nil default: return ErrUnsupportedStorageType } } // Config is the config file format for the upload service type Config struct { Version int `json:"version"` Type StorageType `json:"type"` NoCompress bool `json:"no_compress,omitempty"` Interval Duration `json:"interval"` Sub json.RawMessage `json:"sub"` } // S3Config is the subconfig for the S3 storage type type S3Config struct { AccessKeyID string `json:"access_key_id"` SecretAccessKey string `json:"secret_access_key"` Region string `json:"region"` Bucket string `json:"bucket"` Path string `json:"path"` } // Unmarshal unmarshals the config file and returns the config and subconfig func Unmarshal(data []byte) (*Config, *S3Config, error) { cfg := &Config{} err := json.Unmarshal(data, cfg) if err != nil { return nil, nil, err } if cfg.Version > version { return nil, nil, ErrInvalidVersion } s3cfg := &S3Config{} err = json.Unmarshal(cfg.Sub, s3cfg) if err != nil { return nil, nil, err } return cfg, s3cfg, nil }