1
0
mirror of synced 2024-11-22 04:46:05 +03:00
messenger/messenger.go
2016-04-14 10:25:48 +10:00

151 lines
3.8 KiB
Go

package messenger
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
const (
// WebhookURL is where the Messenger client should listen for webhook events.
WebhookURL = "/webhook"
)
// Options are the settings used when creating a Messenger client.
type Options struct {
// Verify sets whether or not to be in the "verify" mode. Used for
// verifying webhooks on the Facebook Developer Portal.
Verify bool
// VerifyToken is the token to be used when verifying the webhook. Is set
// when the webhook is created.
VerifyToken string
// Token is the access token of the Facebook page to send messages from.
Token string
}
// MessageHandler is a handler used for responding to a message containing text.
type MessageHandler func(Message, *Response)
// DeliveryHandler is a handler used for responding to a read receipt.
type DeliveryHandler func(Delivery, *Response)
// Messenger is the client which manages communication with the Messenger Platform API.
type Messenger struct {
mux *http.ServeMux
messageHandlers []MessageHandler
deliveryHandlers []DeliveryHandler
token string
}
// New creates a new Messenger. You pass in Options in order to affect settings.
func New(mo Options) *Messenger {
m := &Messenger{
mux: http.NewServeMux(),
token: mo.Token,
}
if mo.Verify {
m.mux.HandleFunc(WebhookURL, newVerifyHandler(mo.VerifyToken))
} else {
m.mux.HandleFunc(WebhookURL, m.handle)
}
return m
}
// HandleMessage adds a new MessageHandler to the Messenger which will be triggered
// when a message is recieved by the client.
func (m *Messenger) HandleMessage(f MessageHandler) {
m.messageHandlers = append(m.messageHandlers, f)
}
// HandleDelivery adds a new DeliveryHandler to the Messenger which will be triggered
// when a previously sent message is read by the recipient.
func (m *Messenger) HandleDelivery(f DeliveryHandler) {
m.deliveryHandlers = append(m.deliveryHandlers, f)
}
// Handler returns the Messenger in HTTP client form.
func (m *Messenger) Handler() http.Handler {
return m.mux
}
// handle is the internal HTTP handler for the webhooks.
func (m *Messenger) handle(w http.ResponseWriter, r *http.Request) {
var rec Receive
err := json.NewDecoder(r.Body).Decode(&rec)
if err != nil {
fmt.Println(err)
fmt.Fprintln(w, `{status: 'not ok'}`)
return
}
if rec.Object != "page" {
fmt.Println("Object is not page, undefined behaviour. Got", rec.Object)
}
m.dispatch(rec)
fmt.Fprintln(w, `{status: 'ok'}`)
}
// dispatch triggers all of the relevant handlers when a webhook event is received.
func (m *Messenger) dispatch(r Receive) {
for _, entry := range r.Entry {
for _, info := range entry.Messaging {
a := m.classify(info, entry)
if a == UnknownAction {
fmt.Println("Unknown action:", info)
continue
}
resp := &Response{
to: Recipient{info.Sender.ID},
token: m.token,
}
switch a {
case TextAction:
for _, f := range m.messageHandlers {
message := *info.Message
message.Sender = info.Sender
message.Recipient = info.Recipient
message.Time = time.Unix(info.Timestamp, 0)
f(message, resp)
}
case DeliveryAction:
for _, f := range m.deliveryHandlers {
f(*info.Delivery, resp)
}
}
}
}
}
// classify determines what type of message a webhook event is.
func (m *Messenger) classify(info MessageInfo, e Entry) Action {
if info.Message != nil {
return TextAction
} else if info.Delivery != nil {
return DeliveryAction
}
return UnknownAction
}
// newVerifyHandler returns a function which can be used to handle webhook verification
func newVerifyHandler(token string) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if r.FormValue("hub.verify_token") == token {
fmt.Fprintln(w, r.FormValue("hub.challenge"))
return
}
fmt.Fprintln(w, "Incorrect verify token.")
}
}