forked from TrueCloudLab/rclone
yandex: complete rewrite
Get rid of the api client and use rest/pacer for all API calls Add Copy, Move, DirMove, PublicLink, About optional interfaces Improve general error handling Remove ListR for now due to inconsitent behaviour fixes #2586, progress on #2740 and #2178
This commit is contained in:
parent
31e2ce03c3
commit
155264ae12
31 changed files with 981 additions and 1729 deletions
|
@ -1,34 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
//from yadisk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
//RootAddr is the base URL for Yandex Disk API.
|
|
||||||
const RootAddr = "https://cloud-api.yandex.com" //also https://cloud-api.yandex.net and https://cloud-api.yandex.ru
|
|
||||||
|
|
||||||
func (c *Client) setRequestScope(req *http.Request) {
|
|
||||||
req.Header.Add("Accept", "application/json")
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
req.Header.Add("Authorization", "OAuth "+c.token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) scopedRequest(method, urlPath string, body io.Reader) (*http.Request, error) {
|
|
||||||
fullURL := RootAddr
|
|
||||||
if urlPath[:1] != "/" {
|
|
||||||
fullURL += "/" + urlPath
|
|
||||||
} else {
|
|
||||||
fullURL += urlPath
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(method, fullURL, body)
|
|
||||||
if err != nil {
|
|
||||||
return req, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setRequestScope(req)
|
|
||||||
return req, nil
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
//Client struct
|
|
||||||
type Client struct {
|
|
||||||
token string
|
|
||||||
basePath string
|
|
||||||
HTTPClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewClient creates new client
|
|
||||||
func NewClient(token string, client ...*http.Client) *Client {
|
|
||||||
return newClientInternal(
|
|
||||||
token,
|
|
||||||
"https://cloud-api.yandex.com/v1/disk", //also "https://cloud-api.yandex.net/v1/disk" "https://cloud-api.yandex.ru/v1/disk"
|
|
||||||
client...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClientInternal(token string, basePath string, client ...*http.Client) *Client {
|
|
||||||
c := &Client{
|
|
||||||
token: token,
|
|
||||||
basePath: basePath,
|
|
||||||
}
|
|
||||||
if len(client) != 0 {
|
|
||||||
c.HTTPClient = client[0]
|
|
||||||
} else {
|
|
||||||
c.HTTPClient = http.DefaultClient
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
//ErrorHandler type
|
|
||||||
type ErrorHandler func(*http.Response) error
|
|
||||||
|
|
||||||
var defaultErrorHandler ErrorHandler = func(resp *http.Response) error {
|
|
||||||
if resp.StatusCode/100 == 5 {
|
|
||||||
return errors.New("server error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode/100 == 4 {
|
|
||||||
var response DiskClientError
|
|
||||||
contents, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
err := json.Unmarshal(contents, &response)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode/100 == 3 {
|
|
||||||
return errors.New("redirect error")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (HTTPRequest *HTTPRequest) run(client *Client) ([]byte, error) {
|
|
||||||
var err error
|
|
||||||
values := make(url.Values)
|
|
||||||
for k, v := range HTTPRequest.Parameters {
|
|
||||||
values.Set(k, fmt.Sprintf("%v", v))
|
|
||||||
}
|
|
||||||
|
|
||||||
var req *http.Request
|
|
||||||
if HTTPRequest.Method == "POST" {
|
|
||||||
// TODO json serialize
|
|
||||||
req, err = http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
client.basePath+HTTPRequest.Path,
|
|
||||||
strings.NewReader(values.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// TODO
|
|
||||||
// req.Header.Set("Content-Type", "application/json")
|
|
||||||
} else {
|
|
||||||
req, err = http.NewRequest(
|
|
||||||
HTTPRequest.Method,
|
|
||||||
client.basePath+HTTPRequest.Path+"?"+values.Encode(),
|
|
||||||
nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for headerName := range HTTPRequest.Headers {
|
|
||||||
var headerValues = HTTPRequest.Headers[headerName]
|
|
||||||
for _, headerValue := range headerValues {
|
|
||||||
req.Header.Set(headerName, headerValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return runRequest(client, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runRequest(client *Client, req *http.Request) ([]byte, error) {
|
|
||||||
return runRequestWithErrorHandler(client, req, defaultErrorHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runRequestWithErrorHandler(client *Client, req *http.Request, errorHandler ErrorHandler) (out []byte, err error) {
|
|
||||||
resp, err := client.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
return checkResponseForErrorsWithErrorHandler(resp, errorHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkResponseForErrorsWithErrorHandler(resp *http.Response, errorHandler ErrorHandler) ([]byte, error) {
|
|
||||||
if resp.StatusCode/100 > 2 {
|
|
||||||
return nil, errorHandler(resp)
|
|
||||||
}
|
|
||||||
return ioutil.ReadAll(resp.Body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckClose is a utility function used to check the return from
|
|
||||||
// Close in a defer statement.
|
|
||||||
func CheckClose(c io.Closer, err *error) {
|
|
||||||
cerr := c.Close()
|
|
||||||
if *err == nil {
|
|
||||||
*err = cerr
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
//CustomPropertyResponse struct we send and is returned by the API for CustomProperty request.
|
|
||||||
type CustomPropertyResponse struct {
|
|
||||||
CustomProperties map[string]interface{} `json:"custom_properties"`
|
|
||||||
}
|
|
||||||
|
|
||||||
//SetCustomProperty will set specified data from Yandex Disk
|
|
||||||
func (c *Client) SetCustomProperty(remotePath string, property string, value string) error {
|
|
||||||
rcm := map[string]interface{}{
|
|
||||||
property: value,
|
|
||||||
}
|
|
||||||
cpr := CustomPropertyResponse{rcm}
|
|
||||||
data, _ := json.Marshal(cpr)
|
|
||||||
body := bytes.NewReader(data)
|
|
||||||
err := c.SetCustomPropertyRequest(remotePath, body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//SetCustomPropertyRequest will make an CustomProperty request and return a URL to CustomProperty data to.
|
|
||||||
func (c *Client) SetCustomPropertyRequest(remotePath string, body io.Reader) (err error) {
|
|
||||||
values := url.Values{}
|
|
||||||
values.Add("path", remotePath)
|
|
||||||
req, err := c.scopedRequest("PATCH", "/v1/disk/resources?"+values.Encode(), body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := CheckAPIError(resp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
//If needed we can read response and check if custom_property is set.
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Delete will remove specified file/folder from Yandex Disk
|
|
||||||
func (c *Client) Delete(remotePath string, permanently bool) error {
|
|
||||||
|
|
||||||
values := url.Values{}
|
|
||||||
values.Add("permanently", strconv.FormatBool(permanently))
|
|
||||||
values.Add("path", remotePath)
|
|
||||||
urlPath := "/v1/disk/resources?" + values.Encode()
|
|
||||||
fullURL := RootAddr
|
|
||||||
if urlPath[:1] != "/" {
|
|
||||||
fullURL += "/" + urlPath
|
|
||||||
} else {
|
|
||||||
fullURL += urlPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.PerformDelete(fullURL)
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
//DiskInfoRequest type
|
|
||||||
type DiskInfoRequest struct {
|
|
||||||
client *Client
|
|
||||||
HTTPRequest *HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req *DiskInfoRequest) request() *HTTPRequest {
|
|
||||||
return req.HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
//DiskInfoResponse struct is returned by the API for DiskInfo request.
|
|
||||||
type DiskInfoResponse struct {
|
|
||||||
TrashSize uint64 `json:"TrashSize"`
|
|
||||||
TotalSpace uint64 `json:"TotalSpace"`
|
|
||||||
UsedSpace uint64 `json:"UsedSpace"`
|
|
||||||
SystemFolders map[string]string `json:"SystemFolders"`
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewDiskInfoRequest create new DiskInfo Request
|
|
||||||
func (c *Client) NewDiskInfoRequest() *DiskInfoRequest {
|
|
||||||
return &DiskInfoRequest{
|
|
||||||
client: c,
|
|
||||||
HTTPRequest: createGetRequest(c, "/", nil),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Exec run DiskInfo Request
|
|
||||||
func (req *DiskInfoRequest) Exec() (*DiskInfoResponse, error) {
|
|
||||||
data, err := req.request().run(req.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var info DiskInfoResponse
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if info.SystemFolders == nil {
|
|
||||||
info.SystemFolders = make(map[string]string)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DownloadResponse struct is returned by the API for Download request.
|
|
||||||
type DownloadResponse struct {
|
|
||||||
HRef string `json:"href"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Templated bool `json:"templated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download will get specified data from Yandex.Disk supplying the extra headers
|
|
||||||
func (c *Client) Download(remotePath string, headers map[string]string) (io.ReadCloser, error) { //io.Writer
|
|
||||||
ur, err := c.DownloadRequest(remotePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.PerformDownload(ur.HRef, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DownloadRequest will make an download request and return a URL to download data to.
|
|
||||||
func (c *Client) DownloadRequest(remotePath string) (ur *DownloadResponse, err error) {
|
|
||||||
values := url.Values{}
|
|
||||||
values.Add("path", remotePath)
|
|
||||||
|
|
||||||
req, err := c.scopedRequest("GET", "/v1/disk/resources/download?"+values.Encode(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := CheckAPIError(resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
ur, err = ParseDownloadResponse(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ur, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseDownloadResponse tries to read and parse DownloadResponse struct.
|
|
||||||
func ParseDownloadResponse(data io.Reader) (*DownloadResponse, error) {
|
|
||||||
dec := json.NewDecoder(data)
|
|
||||||
var ur DownloadResponse
|
|
||||||
|
|
||||||
if err := dec.Decode(&ur); err == io.EOF {
|
|
||||||
// ok
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if there is any trash data after JSON and crash if there is.
|
|
||||||
|
|
||||||
return &ur, nil
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// EmptyTrash will permanently delete all trashed files/folders from Yandex Disk
|
|
||||||
func (c *Client) EmptyTrash() error {
|
|
||||||
fullURL := RootAddr
|
|
||||||
fullURL += "/v1/disk/trash/resources"
|
|
||||||
|
|
||||||
return c.PerformDelete(fullURL)
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
//from yadisk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrorResponse represents erroneous API response.
|
|
||||||
// Implements go's built in `error`.
|
|
||||||
type ErrorResponse struct {
|
|
||||||
ErrorName string `json:"error"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
|
|
||||||
StatusCode int `json:""`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrorResponse) Error() string {
|
|
||||||
return fmt.Sprintf("[%d - %s] %s (%s)", e.StatusCode, e.ErrorName, e.Description, e.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProccessErrorResponse tries to represent data passed as
|
|
||||||
// an ErrorResponse object.
|
|
||||||
func ProccessErrorResponse(data io.Reader) (*ErrorResponse, error) {
|
|
||||||
dec := json.NewDecoder(data)
|
|
||||||
var errorResponse ErrorResponse
|
|
||||||
|
|
||||||
if err := dec.Decode(&errorResponse); err == io.EOF {
|
|
||||||
// ok
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if there is any trash data after JSON and crash if there is.
|
|
||||||
|
|
||||||
return &errorResponse, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckAPIError is a convenient function to turn erroneous
|
|
||||||
// API response into go error. It closes the Body on error.
|
|
||||||
func CheckAPIError(resp *http.Response) (err error) {
|
|
||||||
if resp.StatusCode >= 200 && resp.StatusCode < 400 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
errorResponse, err := ProccessErrorResponse(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
errorResponse.StatusCode = resp.StatusCode
|
|
||||||
|
|
||||||
return errorResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProccessErrorString tries to represent data passed as
|
|
||||||
// an ErrorResponse object.
|
|
||||||
func ProccessErrorString(data string) (*ErrorResponse, error) {
|
|
||||||
var errorResponse ErrorResponse
|
|
||||||
if err := json.Unmarshal([]byte(data), &errorResponse); err == nil {
|
|
||||||
// ok
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if there is any trash data after JSON and crash if there is.
|
|
||||||
|
|
||||||
return &errorResponse, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseAPIError Parse json error response from API
|
|
||||||
func (c *Client) ParseAPIError(jsonErr string) (string, error) { //ErrorName
|
|
||||||
errorResponse, err := ProccessErrorString(jsonErr)
|
|
||||||
if err != nil {
|
|
||||||
return err.Error(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorResponse.ErrorName, nil
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
//DiskClientError struct
|
|
||||||
type DiskClientError struct {
|
|
||||||
Description string `json:"Description"`
|
|
||||||
Code string `json:"Error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e DiskClientError) Error() string {
|
|
||||||
b, _ := json.Marshal(e)
|
|
||||||
return string(b)
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// FilesResourceListResponse struct is returned by the API for requests.
|
|
||||||
type FilesResourceListResponse struct {
|
|
||||||
Items []ResourceInfoResponse `json:"items"`
|
|
||||||
Limit *uint64 `json:"limit"`
|
|
||||||
Offset *uint64 `json:"offset"`
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FlatFileListRequest struct client for FlatFileList Request
|
|
||||||
type FlatFileListRequest struct {
|
|
||||||
client *Client
|
|
||||||
HTTPRequest *HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlatFileListRequestOptions struct - options for request
|
|
||||||
type FlatFileListRequestOptions struct {
|
|
||||||
MediaType []MediaType
|
|
||||||
Limit *uint32
|
|
||||||
Offset *uint32
|
|
||||||
Fields []string
|
|
||||||
PreviewSize *PreviewSize
|
|
||||||
PreviewCrop *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request get request
|
|
||||||
func (req *FlatFileListRequest) Request() *HTTPRequest {
|
|
||||||
return req.HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFlatFileListRequest create new FlatFileList Request
|
|
||||||
func (c *Client) NewFlatFileListRequest(options ...FlatFileListRequestOptions) *FlatFileListRequest {
|
|
||||||
var parameters = make(map[string]interface{})
|
|
||||||
if len(options) > 0 {
|
|
||||||
opt := options[0]
|
|
||||||
if opt.Limit != nil {
|
|
||||||
parameters["limit"] = *opt.Limit
|
|
||||||
}
|
|
||||||
if opt.Offset != nil {
|
|
||||||
parameters["offset"] = *opt.Offset
|
|
||||||
}
|
|
||||||
if opt.Fields != nil {
|
|
||||||
parameters["fields"] = strings.Join(opt.Fields, ",")
|
|
||||||
}
|
|
||||||
if opt.PreviewSize != nil {
|
|
||||||
parameters["preview_size"] = opt.PreviewSize.String()
|
|
||||||
}
|
|
||||||
if opt.PreviewCrop != nil {
|
|
||||||
parameters["preview_crop"] = *opt.PreviewCrop
|
|
||||||
}
|
|
||||||
if opt.MediaType != nil {
|
|
||||||
var strMediaTypes = make([]string, len(opt.MediaType))
|
|
||||||
for i, t := range opt.MediaType {
|
|
||||||
strMediaTypes[i] = t.String()
|
|
||||||
}
|
|
||||||
parameters["media_type"] = strings.Join(strMediaTypes, ",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &FlatFileListRequest{
|
|
||||||
client: c,
|
|
||||||
HTTPRequest: createGetRequest(c, "/resources/files", parameters),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec run FlatFileList Request
|
|
||||||
func (req *FlatFileListRequest) Exec() (*FilesResourceListResponse, error) {
|
|
||||||
data, err := req.Request().run(req.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var info FilesResourceListResponse
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if cap(info.Items) == 0 {
|
|
||||||
info.Items = []ResourceInfoResponse{}
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// HTTPRequest struct
|
|
||||||
type HTTPRequest struct {
|
|
||||||
Method string
|
|
||||||
Path string
|
|
||||||
Parameters map[string]interface{}
|
|
||||||
Headers map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func createGetRequest(client *Client, path string, params map[string]interface{}) *HTTPRequest {
|
|
||||||
return createRequest(client, "GET", path, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createRequest(client *Client, method string, path string, parameters map[string]interface{}) *HTTPRequest {
|
|
||||||
var headers = make(map[string][]string)
|
|
||||||
headers["Authorization"] = []string{"OAuth " + client.token}
|
|
||||||
return &HTTPRequest{
|
|
||||||
Method: method,
|
|
||||||
Path: path,
|
|
||||||
Parameters: parameters,
|
|
||||||
Headers: headers,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// LastUploadedResourceListResponse struct
|
|
||||||
type LastUploadedResourceListResponse struct {
|
|
||||||
Items []ResourceInfoResponse `json:"items"`
|
|
||||||
Limit *uint64 `json:"limit"`
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LastUploadedResourceListRequest struct
|
|
||||||
type LastUploadedResourceListRequest struct {
|
|
||||||
client *Client
|
|
||||||
HTTPRequest *HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// LastUploadedResourceListRequestOptions struct
|
|
||||||
type LastUploadedResourceListRequestOptions struct {
|
|
||||||
MediaType []MediaType
|
|
||||||
Limit *uint32
|
|
||||||
Fields []string
|
|
||||||
PreviewSize *PreviewSize
|
|
||||||
PreviewCrop *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request return request
|
|
||||||
func (req *LastUploadedResourceListRequest) Request() *HTTPRequest {
|
|
||||||
return req.HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLastUploadedResourceListRequest create new LastUploadedResourceList Request
|
|
||||||
func (c *Client) NewLastUploadedResourceListRequest(options ...LastUploadedResourceListRequestOptions) *LastUploadedResourceListRequest {
|
|
||||||
var parameters = make(map[string]interface{})
|
|
||||||
if len(options) > 0 {
|
|
||||||
opt := options[0]
|
|
||||||
if opt.Limit != nil {
|
|
||||||
parameters["limit"] = opt.Limit
|
|
||||||
}
|
|
||||||
if opt.Fields != nil {
|
|
||||||
parameters["fields"] = strings.Join(opt.Fields, ",")
|
|
||||||
}
|
|
||||||
if opt.PreviewSize != nil {
|
|
||||||
parameters["preview_size"] = opt.PreviewSize.String()
|
|
||||||
}
|
|
||||||
if opt.PreviewCrop != nil {
|
|
||||||
parameters["preview_crop"] = opt.PreviewCrop
|
|
||||||
}
|
|
||||||
if opt.MediaType != nil {
|
|
||||||
var strMediaTypes = make([]string, len(opt.MediaType))
|
|
||||||
for i, t := range opt.MediaType {
|
|
||||||
strMediaTypes[i] = t.String()
|
|
||||||
}
|
|
||||||
parameters["media_type"] = strings.Join(strMediaTypes, ",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &LastUploadedResourceListRequest{
|
|
||||||
client: c,
|
|
||||||
HTTPRequest: createGetRequest(c, "/resources/last-uploaded", parameters),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec run LastUploadedResourceList Request
|
|
||||||
func (req *LastUploadedResourceListRequest) Exec() (*LastUploadedResourceListResponse, error) {
|
|
||||||
data, err := req.Request().run(req.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var info LastUploadedResourceListResponse
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if cap(info.Items) == 0 {
|
|
||||||
info.Items = []ResourceInfoResponse{}
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// MediaType struct - media types
|
|
||||||
type MediaType struct {
|
|
||||||
mediaType string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio - media type
|
|
||||||
func (m *MediaType) Audio() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "audio",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backup - media type
|
|
||||||
func (m *MediaType) Backup() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "backup",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Book - media type
|
|
||||||
func (m *MediaType) Book() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "book",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compressed - media type
|
|
||||||
func (m *MediaType) Compressed() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "compressed",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data - media type
|
|
||||||
func (m *MediaType) Data() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "data",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Development - media type
|
|
||||||
func (m *MediaType) Development() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "development",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diskimage - media type
|
|
||||||
func (m *MediaType) Diskimage() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "diskimage",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Document - media type
|
|
||||||
func (m *MediaType) Document() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "document",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encoded - media type
|
|
||||||
func (m *MediaType) Encoded() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "encoded",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executable - media type
|
|
||||||
func (m *MediaType) Executable() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "executable",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flash - media type
|
|
||||||
func (m *MediaType) Flash() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "flash",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Font - media type
|
|
||||||
func (m *MediaType) Font() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "font",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image - media type
|
|
||||||
func (m *MediaType) Image() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "image",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings - media type
|
|
||||||
func (m *MediaType) Settings() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "settings",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spreadsheet - media type
|
|
||||||
func (m *MediaType) Spreadsheet() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "spreadsheet",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text - media type
|
|
||||||
func (m *MediaType) Text() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "text",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unknown - media type
|
|
||||||
func (m *MediaType) Unknown() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Video - media type
|
|
||||||
func (m *MediaType) Video() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "video",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web - media type
|
|
||||||
func (m *MediaType) Web() *MediaType {
|
|
||||||
return &MediaType{
|
|
||||||
mediaType: "web",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String - media type
|
|
||||||
func (m *MediaType) String() string {
|
|
||||||
return m.mediaType
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mkdir will make specified folder on Yandex Disk
|
|
||||||
func (c *Client) Mkdir(remotePath string) (int, string, error) {
|
|
||||||
|
|
||||||
values := url.Values{}
|
|
||||||
values.Add("path", remotePath) // only one current folder will be created. Not all the folders in the path.
|
|
||||||
urlPath := "/v1/disk/resources?" + values.Encode()
|
|
||||||
fullURL := RootAddr
|
|
||||||
if urlPath[:1] != "/" {
|
|
||||||
fullURL += "/" + urlPath
|
|
||||||
} else {
|
|
||||||
fullURL += urlPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.PerformMkdir(fullURL)
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PerformDelete does the actual delete via DELETE request.
|
|
||||||
func (c *Client) PerformDelete(url string) error {
|
|
||||||
req, err := http.NewRequest("DELETE", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//set access token and headers
|
|
||||||
c.setRequestScope(req)
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//204 - resource deleted.
|
|
||||||
//202 - folder not empty, content will be deleted soon (async delete).
|
|
||||||
if resp.StatusCode != 204 && resp.StatusCode != 202 {
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return errors.Errorf("delete error [%d]: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PerformDownload does the actual download via unscoped GET request.
|
|
||||||
func (c *Client) PerformDownload(url string, headers map[string]string) (out io.ReadCloser, err error) {
|
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set any extra headers
|
|
||||||
for k, v := range headers {
|
|
||||||
req.Header.Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
//c.setRequestScope(req)
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, isRanging := req.Header["Range"]
|
|
||||||
if !(resp.StatusCode == http.StatusOK || (isRanging && resp.StatusCode == http.StatusPartialContent)) {
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, errors.Errorf("download error [%d]: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
return resp.Body, err
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PerformMkdir does the actual mkdir via PUT request.
|
|
||||||
func (c *Client) PerformMkdir(url string) (int, string, error) {
|
|
||||||
req, err := http.NewRequest("PUT", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
//set access token and headers
|
|
||||||
c.setRequestScope(req)
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != 201 {
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return 0, "", err
|
|
||||||
}
|
|
||||||
//third parameter is the json error response body
|
|
||||||
return resp.StatusCode, string(body), errors.Errorf("create folder error [%d]: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
return resp.StatusCode, "", nil
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
//from yadisk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PerformUpload does the actual upload via unscoped PUT request.
|
|
||||||
func (c *Client) PerformUpload(url string, data io.Reader, contentType string) (err error) {
|
|
||||||
req, err := http.NewRequest("PUT", url, data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", contentType)
|
|
||||||
|
|
||||||
//c.setRequestScope(req)
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
if resp.StatusCode != 201 {
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Errorf("upload error [%d]: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// PreviewSize struct
|
|
||||||
type PreviewSize struct {
|
|
||||||
size string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeS - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeS() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "S",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeM - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeM() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "M",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeL - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeL() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "L",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeXL - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeXL() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "XL",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeXXL - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeXXL() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "XXL",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PredefinedSizeXXXL - set preview size
|
|
||||||
func (s *PreviewSize) PredefinedSizeXXXL() *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: "XXXL",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactWidth - set preview size
|
|
||||||
func (s *PreviewSize) ExactWidth(width uint32) *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: fmt.Sprintf("%dx", width),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactHeight - set preview size
|
|
||||||
func (s *PreviewSize) ExactHeight(height uint32) *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: fmt.Sprintf("x%d", height),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactSize - set preview size
|
|
||||||
func (s *PreviewSize) ExactSize(width uint32, height uint32) *PreviewSize {
|
|
||||||
return &PreviewSize{
|
|
||||||
size: fmt.Sprintf("%dx%d", width, height),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PreviewSize) String() string {
|
|
||||||
return s.size
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
//ResourceInfoResponse struct is returned by the API for metedata requests.
|
|
||||||
type ResourceInfoResponse struct {
|
|
||||||
PublicKey string `json:"public_key"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Created string `json:"created"`
|
|
||||||
CustomProperties map[string]interface{} `json:"custom_properties"`
|
|
||||||
Preview string `json:"preview"`
|
|
||||||
PublicURL string `json:"public_url"`
|
|
||||||
OriginPath string `json:"origin_path"`
|
|
||||||
Modified string `json:"modified"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Md5 string `json:"md5"`
|
|
||||||
ResourceType string `json:"type"`
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
Size uint64 `json:"size"`
|
|
||||||
Embedded *ResourceListResponse `json:"_embedded"`
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// ResourceInfoRequest struct
|
|
||||||
type ResourceInfoRequest struct {
|
|
||||||
client *Client
|
|
||||||
HTTPRequest *HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request of ResourceInfoRequest
|
|
||||||
func (req *ResourceInfoRequest) Request() *HTTPRequest {
|
|
||||||
return req.HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResourceInfoRequest create new ResourceInfo Request
|
|
||||||
func (c *Client) NewResourceInfoRequest(path string, options ...ResourceInfoRequestOptions) *ResourceInfoRequest {
|
|
||||||
return &ResourceInfoRequest{
|
|
||||||
client: c,
|
|
||||||
HTTPRequest: createResourceInfoRequest(c, "/resources", path, options...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec run ResourceInfo Request
|
|
||||||
func (req *ResourceInfoRequest) Exec() (*ResourceInfoResponse, error) {
|
|
||||||
data, err := req.Request().run(req.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var info ResourceInfoResponse
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if info.CustomProperties == nil {
|
|
||||||
info.CustomProperties = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if info.Embedded != nil {
|
|
||||||
if cap(info.Embedded.Items) == 0 {
|
|
||||||
info.Embedded.Items = []ResourceInfoResponse{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
func createResourceInfoRequest(c *Client,
|
|
||||||
apiPath string,
|
|
||||||
path string,
|
|
||||||
options ...ResourceInfoRequestOptions) *HTTPRequest {
|
|
||||||
var parameters = make(map[string]interface{})
|
|
||||||
parameters["path"] = path
|
|
||||||
if len(options) > 0 {
|
|
||||||
opt := options[0]
|
|
||||||
if opt.SortMode != nil {
|
|
||||||
parameters["sort"] = opt.SortMode.String()
|
|
||||||
}
|
|
||||||
if opt.Limit != nil {
|
|
||||||
parameters["limit"] = *opt.Limit
|
|
||||||
}
|
|
||||||
if opt.Offset != nil {
|
|
||||||
parameters["offset"] = *opt.Offset
|
|
||||||
}
|
|
||||||
if opt.Fields != nil {
|
|
||||||
parameters["fields"] = strings.Join(opt.Fields, ",")
|
|
||||||
}
|
|
||||||
if opt.PreviewSize != nil {
|
|
||||||
parameters["preview_size"] = opt.PreviewSize.String()
|
|
||||||
}
|
|
||||||
if opt.PreviewCrop != nil {
|
|
||||||
parameters["preview_crop"] = *opt.PreviewCrop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return createGetRequest(c, apiPath, parameters)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// ResourceInfoRequestOptions struct
|
|
||||||
type ResourceInfoRequestOptions struct {
|
|
||||||
SortMode *SortMode
|
|
||||||
Limit *uint32
|
|
||||||
Offset *uint32
|
|
||||||
Fields []string
|
|
||||||
PreviewSize *PreviewSize
|
|
||||||
PreviewCrop *bool
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
// ResourceListResponse struct
|
|
||||||
type ResourceListResponse struct {
|
|
||||||
Sort *SortMode `json:"sort"`
|
|
||||||
PublicKey string `json:"public_key"`
|
|
||||||
Items []ResourceInfoResponse `json:"items"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Limit *uint64 `json:"limit"`
|
|
||||||
Offset *uint64 `json:"offset"`
|
|
||||||
Total *uint64 `json:"total"`
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// SortMode struct - sort mode
|
|
||||||
type SortMode struct {
|
|
||||||
mode string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default - sort mode
|
|
||||||
func (m *SortMode) Default() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByName - sort mode
|
|
||||||
func (m *SortMode) ByName() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "name",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByPath - sort mode
|
|
||||||
func (m *SortMode) ByPath() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "path",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByCreated - sort mode
|
|
||||||
func (m *SortMode) ByCreated() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "created",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByModified - sort mode
|
|
||||||
func (m *SortMode) ByModified() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "modified",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BySize - sort mode
|
|
||||||
func (m *SortMode) BySize() *SortMode {
|
|
||||||
return &SortMode{
|
|
||||||
mode: "size",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse - sort mode
|
|
||||||
func (m *SortMode) Reverse() *SortMode {
|
|
||||||
if strings.HasPrefix(m.mode, "-") {
|
|
||||||
return &SortMode{
|
|
||||||
mode: m.mode[1:],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &SortMode{
|
|
||||||
mode: "-" + m.mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SortMode) String() string {
|
|
||||||
return m.mode
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON sort mode
|
|
||||||
func (m *SortMode) UnmarshalJSON(value []byte) error {
|
|
||||||
if value == nil || len(value) == 0 {
|
|
||||||
m.mode = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
m.mode = string(value)
|
|
||||||
if strings.HasPrefix(m.mode, "\"") && strings.HasSuffix(m.mode, "\"") {
|
|
||||||
m.mode = m.mode[1 : len(m.mode)-1]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// TrashResourceInfoRequest struct
|
|
||||||
type TrashResourceInfoRequest struct {
|
|
||||||
client *Client
|
|
||||||
HTTPRequest *HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request of TrashResourceInfoRequest struct
|
|
||||||
func (req *TrashResourceInfoRequest) Request() *HTTPRequest {
|
|
||||||
return req.HTTPRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTrashResourceInfoRequest create new TrashResourceInfo Request
|
|
||||||
func (c *Client) NewTrashResourceInfoRequest(path string, options ...ResourceInfoRequestOptions) *TrashResourceInfoRequest {
|
|
||||||
return &TrashResourceInfoRequest{
|
|
||||||
client: c,
|
|
||||||
HTTPRequest: createResourceInfoRequest(c, "/trash/resources", path, options...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec run TrashResourceInfo Request
|
|
||||||
func (req *TrashResourceInfoRequest) Exec() (*ResourceInfoResponse, error) {
|
|
||||||
data, err := req.Request().run(req.client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var info ResourceInfoResponse
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if info.CustomProperties == nil {
|
|
||||||
info.CustomProperties = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if info.Embedded != nil {
|
|
||||||
if cap(info.Embedded.Items) == 0 {
|
|
||||||
info.Embedded.Items = []ResourceInfoResponse{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
157
backend/yandex/api/types.go
Normal file
157
backend/yandex/api/types.go
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiskInfo contains disk metadata
|
||||||
|
type DiskInfo struct {
|
||||||
|
TotalSpace int64 `json:"total_space"`
|
||||||
|
UsedSpace int64 `json:"used_space"`
|
||||||
|
TrashSize int64 `json:"trash_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceInfoRequestOptions struct
|
||||||
|
type ResourceInfoRequestOptions struct {
|
||||||
|
SortMode *SortMode
|
||||||
|
Limit uint64
|
||||||
|
Offset uint64
|
||||||
|
Fields []string
|
||||||
|
}
|
||||||
|
|
||||||
|
//ResourceInfoResponse struct is returned by the API for metedata requests.
|
||||||
|
type ResourceInfoResponse struct {
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Created string `json:"created"`
|
||||||
|
CustomProperties map[string]interface{} `json:"custom_properties"`
|
||||||
|
Preview string `json:"preview"`
|
||||||
|
PublicURL string `json:"public_url"`
|
||||||
|
OriginPath string `json:"origin_path"`
|
||||||
|
Modified string `json:"modified"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Md5 string `json:"md5"`
|
||||||
|
ResourceType string `json:"type"`
|
||||||
|
MimeType string `json:"mime_type"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Embedded *ResourceListResponse `json:"_embedded"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceListResponse struct
|
||||||
|
type ResourceListResponse struct {
|
||||||
|
Sort *SortMode `json:"sort"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
Items []ResourceInfoResponse `json:"items"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Limit *uint64 `json:"limit"`
|
||||||
|
Offset *uint64 `json:"offset"`
|
||||||
|
Total *uint64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsyncInfo struct is returned by the API for various async operations.
|
||||||
|
type AsyncInfo struct {
|
||||||
|
HRef string `json:"href"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Templated bool `json:"templated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsyncStatus is returned when requesting the status of an async operations. Possble values in-progress, success, failure
|
||||||
|
type AsyncStatus struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//CustomPropertyResponse struct we send and is returned by the API for CustomProperty request.
|
||||||
|
type CustomPropertyResponse struct {
|
||||||
|
CustomProperties map[string]interface{} `json:"custom_properties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SortMode struct - sort mode
|
||||||
|
type SortMode struct {
|
||||||
|
mode string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default - sort mode
|
||||||
|
func (m *SortMode) Default() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByName - sort mode
|
||||||
|
func (m *SortMode) ByName() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "name",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByPath - sort mode
|
||||||
|
func (m *SortMode) ByPath() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "path",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCreated - sort mode
|
||||||
|
func (m *SortMode) ByCreated() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "created",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByModified - sort mode
|
||||||
|
func (m *SortMode) ByModified() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "modified",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BySize - sort mode
|
||||||
|
func (m *SortMode) BySize() *SortMode {
|
||||||
|
return &SortMode{
|
||||||
|
mode: "size",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse - sort mode
|
||||||
|
func (m *SortMode) Reverse() *SortMode {
|
||||||
|
if strings.HasPrefix(m.mode, "-") {
|
||||||
|
return &SortMode{
|
||||||
|
mode: m.mode[1:],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &SortMode{
|
||||||
|
mode: "-" + m.mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SortMode) String() string {
|
||||||
|
return m.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON sort mode
|
||||||
|
func (m *SortMode) UnmarshalJSON(value []byte) error {
|
||||||
|
if value == nil || len(value) == 0 {
|
||||||
|
m.mode = ""
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.mode = string(value)
|
||||||
|
if strings.HasPrefix(m.mode, "\"") && strings.HasSuffix(m.mode, "\"") {
|
||||||
|
m.mode = m.mode[1 : len(m.mode)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorResponse represents erroneous API response.
|
||||||
|
// Implements go's built in `error`.
|
||||||
|
type ErrorResponse struct {
|
||||||
|
ErrorName string `json:"error"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
|
||||||
|
StatusCode int `json:""`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorResponse) Error() string {
|
||||||
|
return fmt.Sprintf("[%d - %s] %s (%s)", e.StatusCode, e.ErrorName, e.Description, e.Message)
|
||||||
|
}
|
|
@ -1,71 +0,0 @@
|
||||||
package src
|
|
||||||
|
|
||||||
//from yadisk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UploadResponse struct is returned by the API for upload request.
|
|
||||||
type UploadResponse struct {
|
|
||||||
HRef string `json:"href"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Templated bool `json:"templated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload will put specified data to Yandex.Disk.
|
|
||||||
func (c *Client) Upload(data io.Reader, remotePath string, overwrite bool, contentType string) error {
|
|
||||||
ur, err := c.UploadRequest(remotePath, overwrite)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.PerformUpload(ur.HRef, data, contentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadRequest will make an upload request and return a URL to upload data to.
|
|
||||||
func (c *Client) UploadRequest(remotePath string, overwrite bool) (ur *UploadResponse, err error) {
|
|
||||||
values := url.Values{}
|
|
||||||
values.Add("path", remotePath)
|
|
||||||
values.Add("overwrite", strconv.FormatBool(overwrite))
|
|
||||||
|
|
||||||
req, err := c.scopedRequest("GET", "/v1/disk/resources/upload?"+values.Encode(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.HTTPClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := CheckAPIError(resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer CheckClose(resp.Body, &err)
|
|
||||||
|
|
||||||
ur, err = ParseUploadResponse(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ur, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseUploadResponse tries to read and parse UploadResponse struct.
|
|
||||||
func ParseUploadResponse(data io.Reader) (*UploadResponse, error) {
|
|
||||||
dec := json.NewDecoder(data)
|
|
||||||
var ur UploadResponse
|
|
||||||
|
|
||||||
if err := dec.Decode(&ur); err == io.EOF {
|
|
||||||
// ok
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check if there is any trash data after JSON and crash if there is.
|
|
||||||
|
|
||||||
return &ur, nil
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue