package YaDisk import ( "context" "encoding/json" "errors" "fmt" "golang.org/x/oauth2" "golang.org/x/oauth2/yandex" "io" "net/http" "net/url" "os" "strings" ) const ( BASE_URL = "https://cloud-api.yandex.net" OAUTH_URL = "https://oauth.yandex.ru" ) type Client struct { App *ClientApp HTTPClient *http.Client Token *oauth2.Token } type ClientApp struct { Config *oauth2.Config ServiceUrl string } func NewClientApp(clientID, clientSecret, redirectUri, serviceUrl string) *ClientApp { return &ClientApp{ Config: &oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: yandex.Endpoint, RedirectURL: redirectUri, Scopes: nil, }, ServiceUrl: serviceUrl, } } func (ca *ClientApp) GenerateOAuthUrl() string { return ca.Config.AuthCodeURL( "state-token", oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("display", "popup"), oauth2.SetAuthURLParam("force_confirm", "true"), ) } func (ca *ClientApp) NewClient(ctx context.Context, token *oauth2.Token, code string) (*Client, error) { var err error if code != "" { token, err = ca.Config.Exchange(ctx, code) } // Этот костыль нужен, т.к. Яндекс принимает токены только типа OAuth, хоть и отправляет типа bearer token.TokenType = "OAuth" return &Client{ App: ca, HTTPClient: ca.Config.Client(ctx, token), Token: token, }, err } func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token) (*oauth2.Token, error) { token, err := ca.Config.TokenSource(ctx, oldToken).Token() if err != nil { return nil, err } // Этот костыль нужен, т.к. Яндекс принимает токены только типа OAuth, хоть и отправляет типа bearer token.TokenType = "OAuth" return token, nil } func (c *Client) GetDisk() (*Disk, error) { req, err := http.NewRequest("GET", BASE_URL+"/v1/disk", nil) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err } if resp.StatusCode != 200 { r := Error{} json.NewDecoder(resp.Body).Decode(&r) return nil, errors.New(fmt.Sprintf("api/yaDisk err: %v (%v)", r.Description, r.Error)) } r := Disk{} err = json.NewDecoder(resp.Body).Decode(&r) if err != nil { return nil, err } return &r, nil } func (c *Client) GetUser() (*User, error) { disk, err := c.GetDisk() if err != nil { return nil, err } return &disk.User, nil } func (c *Client) GetResources(path string) (*Resource, error) { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("GET", BASE_URL+"/v1/disk/resources?path="+path, nil) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err } if resp.StatusCode == 404 { fmt.Println("api/yaDisk: 404") return nil, nil } else if resp.StatusCode != 200 { r := Error{} err = json.NewDecoder(resp.Body).Decode(&r) if err != nil { return nil, err } return nil, errors.New(fmt.Sprintf("api/yaDisk err: %v (%v)", r.Description, r.Error)) } r := Resource{} err = json.NewDecoder(resp.Body).Decode(&r) return &r, err } func (c *Client) DownloadResource(path, downloadPath string) error { res, err := c.GetResources(path) if err != nil { return err } resp, err := http.Get(res.File) if err != nil { return err } defer resp.Body.Close() // Create the file out, err := os.Create(downloadPath) if err != nil { return err } defer out.Close() // Write the body to file _, err = io.Copy(out, resp.Body) return err } func (c *Client) PutResources(path string) error { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("PUT", BASE_URL+"/v1/disk/resources?"+data.Encode(), nil) if err != nil { return err } resp, err := c.HTTPClient.Do(req) if err != nil { return err } r := map[string]interface{}{} err = json.NewDecoder(resp.Body).Decode(&r) fmt.Printf("%+v", r) return err } func (c *Client) ResourcesUpload(path, downloadPath string) error { downloadPath = strings.TrimLeft(downloadPath, "..") downloadPath = strings.TrimLeft(downloadPath, ".") data := url.Values{} data.Set("path", path) data.Set("url", c.App.ServiceUrl+downloadPath) req, err := http.NewRequest("POST", BASE_URL+"/v1/disk/resources/upload?"+data.Encode(), nil) if err != nil { return err } resp, err := c.HTTPClient.Do(req) if err != nil { return err } r := map[string]interface{}{} err = json.NewDecoder(resp.Body).Decode(&r) fmt.Printf("%+v", r) return err }