From 0295eba4aa3dee834d08f38db2ee30756ac0ae02 Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Tue, 10 Jul 2018 15:03:41 +0300 Subject: [PATCH] add processing response from facebook add processing response from facebook --- messenger.go | 32 +++++++++++++----------- response.go | 70 +++++++++++++++++++++++++++------------------------- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/messenger.go b/messenger.go index 61a0b04..ab049e2 100644 --- a/messenger.go +++ b/messenger.go @@ -187,7 +187,9 @@ func (m *Messenger) ProfileByID(id int64) (Profile, error) { } // GreetingSetting sends settings for greeting -func (m *Messenger) GreetingSetting(text string) error { +func (m *Messenger) GreetingSetting(text string) (QueryResponse, error) { + var qr QueryResponse + d := GreetingSetting{ SettingType: "greeting", Greeting: GreetingInfo{ @@ -197,12 +199,12 @@ func (m *Messenger) GreetingSetting(text string) error { data, err := json.Marshal(d) if err != nil { - return err + return qr, err } req, err := http.NewRequest("POST", SendSettingsURL, bytes.NewBuffer(data)) if err != nil { - return err + return qr, err } req.Header.Set("Content-Type", "application/json") @@ -212,15 +214,17 @@ func (m *Messenger) GreetingSetting(text string) error { resp, err := client.Do(req) if err != nil { - return err + return qr, err } defer resp.Body.Close() - return checkFacebookError(resp.Body) + return getFacebookQueryResponse(resp.Body) } // CallToActionsSetting sends settings for Get Started or Persist Menu -func (m *Messenger) CallToActionsSetting(state string, actions []CallToActionsItem) error { +func (m *Messenger) CallToActionsSetting(state string, actions []CallToActionsItem) (QueryResponse, error) { + var qr QueryResponse + d := CallToActionsSetting{ SettingType: "call_to_actions", ThreadState: state, @@ -229,12 +233,12 @@ func (m *Messenger) CallToActionsSetting(state string, actions []CallToActionsIt data, err := json.Marshal(d) if err != nil { - return err + return qr, err } req, err := http.NewRequest("POST", SendSettingsURL, bytes.NewBuffer(data)) if err != nil { - return err + return qr, err } req.Header.Set("Content-Type", "application/json") @@ -244,11 +248,11 @@ func (m *Messenger) CallToActionsSetting(state string, actions []CallToActionsIt resp, err := client.Do(req) if err != nil { - return err + return qr, err } defer resp.Body.Close() - return checkFacebookError(resp.Body) + return getFacebookQueryResponse(resp.Body) } // handle is the internal HTTP handler for the webhooks. @@ -402,12 +406,12 @@ func (m *Messenger) Response(to int64) *Response { } // Send will send a textual message to a user. This user must have previously initiated a conversation with the bot. -func (m *Messenger) Send(to Recipient, message string, messagingType MessagingType, tags ...string) error { +func (m *Messenger) Send(to Recipient, message string, messagingType MessagingType, tags ...string) (QueryResponse, error) { return m.SendWithReplies(to, message, nil, messagingType, tags...) } // SendGeneralMessage will send the GenericTemplate message -func (m *Messenger) SendGeneralMessage(to Recipient, elements *[]StructuredMessageElement, messagingType MessagingType, tags ...string) error { +func (m *Messenger) SendGeneralMessage(to Recipient, elements *[]StructuredMessageElement, messagingType MessagingType, tags ...string) (QueryResponse, error) { r := &Response{ token: m.token, to: to, @@ -416,7 +420,7 @@ func (m *Messenger) SendGeneralMessage(to Recipient, elements *[]StructuredMessa } // SendWithReplies sends a textual message to a user, but gives them the option of numerous quick response options. -func (m *Messenger) SendWithReplies(to Recipient, message string, replies []QuickReply, messagingType MessagingType, tags ...string) error { +func (m *Messenger) SendWithReplies(to Recipient, message string, replies []QuickReply, messagingType MessagingType, tags ...string) (QueryResponse, error) { response := &Response{ token: m.token, to: to, @@ -426,7 +430,7 @@ func (m *Messenger) SendWithReplies(to Recipient, message string, replies []Quic } // Attachment sends an image, sound, video or a regular file to a given recipient. -func (m *Messenger) Attachment(to Recipient, dataType AttachmentType, url string, messagingType MessagingType, tags ...string) error { +func (m *Messenger) Attachment(to Recipient, dataType AttachmentType, url string, messagingType MessagingType, tags ...string) (QueryResponse, error) { response := &Response{ token: m.token, to: to, diff --git a/response.go b/response.go index bc094b1..a3a3a02 100644 --- a/response.go +++ b/response.go @@ -44,8 +44,9 @@ const ( // QueryResponse is the response sent back by Facebook when setting up things // like greetings or call-to-actions type QueryResponse struct { - Error *QueryError `json:"error,omitempty"` - Result string `json:"result,omitempty"` + Error *QueryError `json:"error,omitempty"` + RecipientID string `json:"recipient_id"` + MessageID string `json:"message_id"` } // QueryError is representing an error sent back by Facebook @@ -56,17 +57,17 @@ type QueryError struct { FBTraceID string `json:"fbtrace_id"` } -func checkFacebookError(r io.Reader) error { - var err error - +func getFacebookQueryResponse(r io.Reader) (QueryResponse, error) { qr := QueryResponse{} - err = json.NewDecoder(r).Decode(&qr) + err := json.NewDecoder(r).Decode(&qr) + if err != nil { + return qr, err + } if qr.Error != nil { err = fmt.Errorf("Facebook error : %s", qr.Error.Message) - return err + return qr, err } - - return nil + return qr, nil } // Response is used for responding to events with messages. @@ -76,14 +77,14 @@ type Response struct { } // Text sends a textual message. -func (r *Response) Text(message string, messagingType MessagingType, tags ...string) error { +func (r *Response) Text(message string, messagingType MessagingType, tags ...string) (QueryResponse, error) { return r.TextWithReplies(message, nil, messagingType, tags...) } // TextWithReplies sends a textual message with some replies // messagingType should be one of the following: "RESPONSE","UPDATE","MESSAGE_TAG","NON_PROMOTIONAL_SUBSCRIPTION" // only supply tags when messagingType == "MESSAGE_TAG" (see https://developers.facebook.com/docs/messenger-platform/send-messages#messaging_types for more) -func (r *Response) TextWithReplies(message string, replies []QuickReply, messagingType MessagingType, tags ...string) error { +func (r *Response) TextWithReplies(message string, replies []QuickReply, messagingType MessagingType, tags ...string) (QueryResponse, error) { var tag string if len(tags) > 0 { tag = tags[0] @@ -103,7 +104,7 @@ func (r *Response) TextWithReplies(message string, replies []QuickReply, messagi } // AttachmentWithReplies sends a attachment message with some replies -func (r *Response) AttachmentWithReplies(attachment *StructuredMessageAttachment, replies []QuickReply, messagingType MessagingType, tags ...string) error { +func (r *Response) AttachmentWithReplies(attachment *StructuredMessageAttachment, replies []QuickReply, messagingType MessagingType, tags ...string) (QueryResponse, error) { var tag string if len(tags) > 0 { tag = tags[0] @@ -122,18 +123,20 @@ func (r *Response) AttachmentWithReplies(attachment *StructuredMessageAttachment } // Image sends an image. -func (r *Response) Image(im image.Image) error { +func (r *Response) Image(im image.Image) (QueryResponse, error) { + var qr QueryResponse + imageBytes := new(bytes.Buffer) err := jpeg.Encode(imageBytes, im, nil) if err != nil { - return err + return qr, err } return r.AttachmentData(ImageAttachment, "meme.jpg", imageBytes) } // Attachment sends an image, sound, video or a regular file to a chat. -func (r *Response) Attachment(dataType AttachmentType, url string, messagingType MessagingType, tags ...string) error { +func (r *Response) Attachment(dataType AttachmentType, url string, messagingType MessagingType, tags ...string) (QueryResponse, error) { var tag string if len(tags) > 0 { tag = tags[0] @@ -174,11 +177,12 @@ func createFormFile(filename string, w *multipart.Writer, contentType string) (i } // AttachmentData sends an image, sound, video or a regular file to a chat via an io.Reader. -func (r *Response) AttachmentData(dataType AttachmentType, filename string, filedata io.Reader) error { +func (r *Response) AttachmentData(dataType AttachmentType, filename string, filedata io.Reader) (QueryResponse, error) { + var qr QueryResponse filedataBytes, err := ioutil.ReadAll(filedata) if err != nil { - return err + return qr, err } contentType := http.DetectContentType(filedataBytes[:512]) fmt.Println("Content-type detected:", contentType) @@ -187,12 +191,12 @@ func (r *Response) AttachmentData(dataType AttachmentType, filename string, file multipartWriter := multipart.NewWriter(&body) data, err := createFormFile(filename, multipartWriter, contentType) if err != nil { - return err + return qr, err } _, err = bytes.NewBuffer(filedataBytes).WriteTo(data) if err != nil { - return err + return qr, err } multipartWriter.WriteField("recipient", fmt.Sprintf(`{"id":"%v"}`, r.to.ID)) @@ -200,7 +204,7 @@ func (r *Response) AttachmentData(dataType AttachmentType, filename string, file req, err := http.NewRequest("POST", SendMessageURL, &body) if err != nil { - return err + return qr, err } req.URL.RawQuery = "access_token=" + r.token @@ -210,14 +214,14 @@ func (r *Response) AttachmentData(dataType AttachmentType, filename string, file client := &http.Client{} resp, err := client.Do(req) if err != nil { - return err + return qr, err } - return checkFacebookError(resp.Body) + return getFacebookQueryResponse(resp.Body) } // ButtonTemplate sends a message with the main contents being button elements -func (r *Response) ButtonTemplate(text string, buttons *[]StructuredMessageButton, messagingType MessagingType, tags ...string) error { +func (r *Response) ButtonTemplate(text string, buttons *[]StructuredMessageButton, messagingType MessagingType, tags ...string) (QueryResponse, error) { var tag string if len(tags) > 0 { tag = tags[0] @@ -244,7 +248,7 @@ func (r *Response) ButtonTemplate(text string, buttons *[]StructuredMessageButto } // GenericTemplate is a message which allows for structural elements to be sent -func (r *Response) GenericTemplate(elements *[]StructuredMessageElement, messagingType MessagingType, tags ...string) error { +func (r *Response) GenericTemplate(elements *[]StructuredMessageElement, messagingType MessagingType, tags ...string) (QueryResponse, error) { var tag string if len(tags) > 0 { tag = tags[0] @@ -269,7 +273,7 @@ func (r *Response) GenericTemplate(elements *[]StructuredMessageElement, messagi } // SenderAction sends a info about sender action -func (r *Response) SenderAction(action string) error { +func (r *Response) SenderAction(action string) (QueryResponse, error) { m := SendSenderAction{ Recipient: r.to, SenderAction: action, @@ -278,15 +282,16 @@ func (r *Response) SenderAction(action string) error { } // DispatchMessage posts the message to messenger, return the error if there's any -func (r *Response) DispatchMessage(m interface{}) error { +func (r *Response) DispatchMessage(m interface{}) (QueryResponse, error) { + var res QueryResponse data, err := json.Marshal(m) if err != nil { - return err + return res, err } req, err := http.NewRequest("POST", SendMessageURL, bytes.NewBuffer(data)) if err != nil { - return err + return res, err } req.Header.Set("Content-Type", "application/json") @@ -294,13 +299,12 @@ func (r *Response) DispatchMessage(m interface{}) error { resp, err := http.DefaultClient.Do(req) if err != nil { - return err + return res, err } + defer resp.Body.Close() - if resp.StatusCode == 200 { - return nil - } - return checkFacebookError(resp.Body) + + return getFacebookQueryResponse(resp.Body) } // SendMessage is the information sent in an API request to Facebook.