Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
AlekSi committed Aug 25, 2019
1 parent 24dfe97 commit 0829cc9
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 23 deletions.
2 changes: 2 additions & 0 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
req.Body = ioutil.NopCloser(&body)
req.ContentLength = int64(body.Len())
req.TransferEncoding = nil
}

b, err := httputil.DumpRequest(req, true)
Expand Down
184 changes: 167 additions & 17 deletions resources/client.go
Original file line number Diff line number Diff line change
@@ -1,54 +1,204 @@
package resources

import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/http/httputil"
"os"
"path/filepath"
"time"

"github.com/AlekSi/alice"
)

type Quota struct {
Total int
Used int
}

type Sound struct {
ID string
SkillID string
Size *int
OriginalName string
CreatedAt time.Time
IsProcessed bool
Error *string
}

type Client struct {
SkillID string
OAuthToken string
HTTPClient *http.Client

// debugging options
Debugf alice.Printf // debug logger
Indent bool // indent requests and responses
StrictDecoder bool // disallow unexpected fields in responses
}

func (c *Client) do(req *http.Request, respBody interface{}) error {
httpClient := c.HTTPClient
if httpClient == nil {
httpClient = http.DefaultClient
}

var jsonRequst bool
if c.OAuthToken != "" {
req.Header.Set("Authorization", "OAuth "+c.OAuthToken)
}
if req.Body != nil && req.Header.Get("Content-Type") == "" {
jsonRequst = true
req.Header.Set("Content-Type", "application/json; charset=utf-8")
}

if c.Debugf != nil {
if c.Indent && jsonRequst {
b, err := ioutil.ReadAll(req.Body)
if err != nil {
return err
}

var body bytes.Buffer
if err = json.Indent(&body, b, "", " "); err != nil {
return err
}
req.Body = ioutil.NopCloser(&body)
req.ContentLength = int64(body.Len())
req.TransferEncoding = nil
}

b, err := httputil.DumpRequestOut(req, jsonRequst)
if err != nil {
return err
}
c.debugf("Request:\n%s", b)
}

resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close() //nolint:errcheck

if c.Debugf != nil {
if c.Indent {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}

var body bytes.Buffer
if err = json.Indent(&body, b, "", " "); err != nil {
return err
}
resp.Body = ioutil.NopCloser(&body)
resp.ContentLength = int64(body.Len())
resp.TransferEncoding = nil
}

b, err := httputil.DumpResponse(resp, true)
if err != nil {
return err
}
c.debugf("Response:\n%s", b)
}

if resp.StatusCode/100 != 2 {
return fmt.Errorf("status code %d", resp.StatusCode)
}

d := json.NewDecoder(resp.Body)
if c.StrictDecoder {
d.DisallowUnknownFields()
}
return d.Decode(&respBody)
}

func (c *Client) http() *http.Client {
if c.HTTPClient != nil {
return c.HTTPClient
func (c *Client) debugf(format string, a ...interface{}) {
if c.Debugf != nil {
c.Debugf(format, a...)
}
return http.DefaultClient
}

type StatusResponse struct {
Total int
Used int
Images struct {
Quota Quota
}
Sounds struct {
Quota Quota
}
}

func (c *Client) Status() (*StatusResponse, error) {
req, err := http.NewRequest("GET", "https://dialogs.yandex.net/api/v1/status", nil)
if err != nil {
return nil, err
}
if c.OAuthToken != "" {
req.Header.Set("Authorization", "OAuth "+c.OAuthToken)

var res StatusResponse
if err = c.do(req, &res); err != nil {
return nil, err
}
return &res, nil
}

resp, err := c.http().Do(req)
func (c *Client) UploadSound(name string, r io.Reader) (*Sound, error) {
var buf bytes.Buffer
mw := multipart.NewWriter(&buf)
fw, err := mw.CreateFormFile("file", name)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode/100 != 2 {
return nil, fmt.Errorf("status code %d", resp.StatusCode)
if _, err = io.Copy(fw, r); err != nil {
return nil, err
}
if err = mw.Close(); err != nil {
return nil, err
}

req, err := http.NewRequest("POST", "https://dialogs.yandex.net/api/v1/skills/"+c.SkillID+"/sounds", &buf)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", mw.FormDataContentType())

var res struct {
Images struct {
Quota StatusResponse
}
Sound Sound
}
if err = c.do(req, &res); err != nil {
return nil, err
}
return &res.Sound, nil
}

func (c *Client) UploadSoundFile(filename string) (*Sound, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close() //nolint:errcheck

return c.UploadSound(filepath.Base(filename), f)
}

func (c *Client) ListSounds() ([]Sound, error) {
req, err := http.NewRequest("GET", "https://dialogs.yandex.net/api/v1/skills/"+c.SkillID+"/sounds", nil)
if err != nil {
return nil, err
}

var res struct {
Sounds []Sound
Total int
}
if err = json.NewDecoder(resp.Body).Decode(&res); err != nil {
if err = c.do(req, &res); err != nil {
return nil, err
}
return &res.Images.Quota, nil
return res.Sounds, nil
}
40 changes: 34 additions & 6 deletions resources/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package resources

import (
"os"
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -13,20 +15,46 @@ func TestClient(t *testing.T) {
t.Skip("-short is passed, skipping integration test")
}

skill := os.Getenv("ALICE_TEST_SKILL_ID")
token := os.Getenv("ALICE_TEST_OAUTH_TOKEN")
if skill == "" || token == "" {
skillID := os.Getenv("ALICE_TEST_SKILL_ID")
oAuthToken := os.Getenv("ALICE_TEST_OAUTH_TOKEN")
if skillID == "" || oAuthToken == "" {
t.Skip("`ALICE_TEST_SKILL_ID` or `ALICE_TEST_OAUTH_TOKEN` is not set, skipping integration test")
}

c := Client{
OAuthToken: token,
SkillID: skill,
SkillID: skillID,
OAuthToken: oAuthToken,
Indent: true,
StrictDecoder: true,
}

t.Run("Status", func(t *testing.T) {
c.Debugf = t.Logf

status, err := c.Status()
require.NoError(t, err)
assert.Equal(t, 104857600, status.Total)
assert.Equal(t, 104857600, status.Images.Quota.Total)
assert.Equal(t, 1073741824, status.Sounds.Quota.Total)
})

t.Run("Sound", func(t *testing.T) {
t.Run("UploadSoundFile", func(t *testing.T) {
c.Debugf = t.Logf

sound, err := c.UploadSoundFile(filepath.Join("..", "testdata", "go.wav"))
require.NoError(t, err)
require.NotEmpty(t, sound)
assert.NotEmpty(t, skillID, sound.ID)
assert.Equal(t, skillID, sound.SkillID)
assert.Empty(t, sound.Size)
assert.Equal(t, "go.wav", sound.OriginalName)
assert.WithinDuration(t, time.Now(), sound.CreatedAt, 5*time.Second)
assert.False(t, sound.IsProcessed)
assert.Nil(t, sound.Error)

sounds, err := c.ListSounds()
require.NoError(t, err)
assert.Empty(t, sounds)
})
})
}

0 comments on commit 0829cc9

Please sign in to comment.