diff --git a/request.go b/request.go index 1723468..a837781 100644 --- a/request.go +++ b/request.go @@ -1,6 +1,7 @@ package alice import ( + "encoding/json" "errors" "strings" ) @@ -49,6 +50,10 @@ type Request struct { UserID string `json:"user_id"` } `json:"session"` + State struct { + Session interface{} `json:"session,omitempty"` + } `json:"state,omitempty"` + Version string `json:"version"` Bearer string } @@ -190,6 +195,24 @@ func (req *Request) Ver() string { return req.Version } +// State.Session Состояние сессии. +func (req *Request) StateSession(key string) interface{} { + if req.State.Session == nil { + return nil + } + session := req.State.Session.(map[string]interface{}) + + return session[key] +} + +// State.Session Состояние сессии json строкой +func (req *Request) StateSessionAsJson() (string, error) { + data, err := json.Marshal(req.State.Session) + + return string(data), err +} + + // AuthToken токен, полученный при связке аккаунтов. func (req *Request) AuthToken() string { if req.Bearer != "" { diff --git a/request_test.go b/request_test.go index d743484..f780d80 100644 --- a/request_test.go +++ b/request_test.go @@ -487,12 +487,58 @@ func TestRequest_Ver(t *testing.T) { } } +func TestRequest_StateSession(t *testing.T) { + tests := map[string]struct { + request *alice.Request + want interface{} + }{ + "when state is empty 0": { + request: getReq(0), + want: nil, + }, + "when state is empty 1":{ + request: getReq(1), + want: nil, + }, + "when state is empty 2":{ + request: getReq(2), + want: nil, + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + req := tt.request + got := req.StateSession(""); + if !assert.Equal(t, tt.want, got) { + t.Errorf("Request.StateSession() = %v, want %v", got, tt.want) + } + + }) + } + t.Run("when state is struct", func(t *testing.T) { + req := getReq(3) + want := make(map[string]interface{}) + want["int_value"] = 42 + + assert.Equal(t, 42.0, req.StateSession("int_value")) + assert.Equal(t, "exampleString", req.StateSession("string_value")) + assert.Equal(t, []interface{}{1.0,2.0,3.0,4.0}, req.StateSession("array_value")) + assert.Equal(t, map[string]interface{}{"one":"one"}, req.StateSession("struct_value")) + stateJson, err := req.StateSessionAsJson() + if assert.NoError(t, err) { + assert.Equal(t, `{"array_value":[1,2,3,4],"int_value":42,"string_value":"exampleString","struct_value":{"one":"one"}}`, stateJson) + } + }) +} + func getReq(n int) *alice.Request { source := []string{`{"meta":{"client_id":"ru.yandex.searchplugin/7.16 (none none; android 4.4.2)","interfaces":{"account_linking":{},"payments":{},"screen":{}},"locale":"ru-RU","timezone":"UTC"},"request":{"command":"съешь еще этих мягких французских булок","nlu":{"entities":[],"tokens":["съешь","еще","этих","мягких","французских","булок"]},"original_utterance":"съешь еще этих мягких французских булок","type":"SimpleUtterance"},"session":{"message_id":0,"new":true,"session_id":"e19e8eee-ae065e8-36e3f907-567a814b","skill_id":"e03f8d5b-35ef-4d57-9450-b721ca17a6c3","user_id":"03B1D487CAA1C7EBF80A195491B78ACA0AC9934CDFB12A29D063A8329BC42BF0"},"version":"1.0"}`, `{"meta":{"client_id":"ru.yandex.searchplugin/7.16 (none none; android 4.4.2)","interfaces":{"account_linking":{},"payments":{}},"locale":"ru-RU","timezone":"UTC"},"request":{"nlu":{"entities":[],"tokens":[]},"payload":{"msg":"ok"},"type":"ButtonPressed"},"session":{"message_id":1,"new":false,"session_id":"eeb9fa7f-940e2502-1fbf9dfb-9448a1a9","skill_id":"e03f8d5b-35ef-4d57-9450-b721ca17a6c3","user_id":"03B1D487CAA1C7EBF80A195491B78ACA0AC9934CDFB12A29D063A8329BC42BF0"},"version":"1.0"}`, `{"meta":{"client_id":"ru.yandex.searchplugin/7.16 (none none; android 4.4.2)","interfaces":{"account_linking":{},"payments":{}},"locale":"ru-RU","timezone":"UTC"},"request":{"nlu":{"entities":[],"tokens":[]},"payload":"msg","type":"ButtonPressed"},"session":{"message_id":1,"new":false,"session_id":"eeb9fa7f-940e2502-1fbf9dfb-9448a1a9","skill_id":"e03f8d5b-35ef-4d57-9450-b721ca17a6c3","user_id":"03B1D487CAA1C7EBF80A195491B78ACA0AC9934CDFB12A29D063A8329BC42BF0"},"version":"1.0"}`, + + `{"meta":{"client_id":"ru.yandex.searchplugin/7.16 (none none; android 4.4.2)","interfaces":{"account_linking":{},"payments":{}},"locale":"ru-RU","timezone":"UTC"},"request":{"nlu":{"entities":[],"tokens":[]},"payload":"msg","type":"ButtonPressed"},"session":{"message_id":1,"new":false,"session_id":"eeb9fa7f-940e2502-1fbf9dfb-9448a1a9","skill_id":"e03f8d5b-35ef-4d57-9450-b721ca17a6c3","user_id":"03B1D487CAA1C7EBF80A195491B78ACA0AC9934CDFB12A29D063A8329BC42BF0"},"state":{"session":{"array_value":[1,2,3,4],"int_value":42,"string_value":"exampleString","struct_value":{"one":"one"}}},"version":"1.0"}`, } var req = new(alice.Request) diff --git a/response.go b/response.go index 7f89fca..d6168c6 100644 --- a/response.go +++ b/response.go @@ -1,6 +1,7 @@ package alice import ( + "errors" "fmt" "math/rand" "strings" @@ -26,6 +27,8 @@ type Response struct { UserID string `json:"user_id"` } `json:"session"` + SessionState interface{} `json:"session_state,omitempty"` + Version string `json:"version"` } @@ -38,6 +41,7 @@ func (resp *Response) clean() *Response { EndSession bool `json:"end_session"` }{} resp.StartAccountLinking = nil + resp.SessionState = nil return resp } @@ -218,3 +222,19 @@ func (resp *Response) RandomPhrase(p ...Phrase) *Response { resp.Response.TTS += p[ix].TTS return resp } + +// AddSessionState добавляет па +func (resp *Response) AddSessionState(key string, data interface{}) error { + if resp.SessionState == nil { + resp.SessionState = make(map[string]interface{}) + } + + if stateBag, ok := resp.SessionState.(map[string]interface{}); ok { + stateBag[key] = data + resp.SessionState = stateBag + } else { + return errors.New(fmt.Sprintf("session_state: can't set data because session_state have type %T", + resp.SessionState)) + } + return nil +} diff --git a/response_test.go b/response_test.go index b9e486a..431e55d 100644 --- a/response_test.go +++ b/response_test.go @@ -703,6 +703,22 @@ func TestResponse_RandomPhrase(t *testing.T) { } } +func TestResponse_AddSessionState(t *testing.T) { + wantResp := getResp(0) + state := make(map[string]interface{}) + state["one"] = struct{}{} + state["two"] = "twotwo" + wantResp.SessionState = state + + resp := getResp(0) + err := resp.AddSessionState("one", struct{}{}) + assert.NoError(t, err) + err = resp.AddSessionState("two", "twotwo") + if assert.NoError(t, err) { + assert.Equal(t, wantResp, resp) + } +} + func getResp(n int) *alice.Response { source := []string{`{"response":{"text":"","end_session":true},"session":{"message_id":0,"session_id":"","user_id":""},"version":"1.0"}`,