From 5006304edfbad67a8a1e93fbf4a2cda8dc3fe3cf Mon Sep 17 00:00:00 2001 From: Harrison Shoebridge Date: Wed, 13 Apr 2016 16:14:23 +1000 Subject: [PATCH] Add handling receiving messages --- .gitignore | 3 +++ actions.go | 8 ++++++ cmd/bot/main.go | 6 +++++ message.go | 10 ++++++++ messenger.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++-- receiving.go | 33 +++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 actions.go create mode 100644 message.go create mode 100644 receiving.go diff --git a/.gitignore b/.gitignore index daf913b..ac5a2b7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ _testmain.go *.exe *.test *.prof + +# Configuration +cmd/bot/config.json diff --git a/actions.go b/actions.go new file mode 100644 index 0000000..e535d71 --- /dev/null +++ b/actions.go @@ -0,0 +1,8 @@ +package messenger + +type Action int + +const ( + UnknownAction Action = iota - 1 + TextAction +) diff --git a/cmd/bot/main.go b/cmd/bot/main.go index 4a17639..4535ed0 100644 --- a/cmd/bot/main.go +++ b/cmd/bot/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "net/http" + "time" "github.com/paked/configure" "github.com/paked/messenger" @@ -26,6 +27,11 @@ func main() { VerifyToken: *verifyToken, }) + m.Handle(messenger.TextAction, func(m messenger.Message) { + fmt.Printf("%v (Sent, %v)\n", m.Text, m.Time.Format(time.UnixDate)) + }) + fmt.Println("Serving messenger bot on localhost:8080") + http.ListenAndServe("localhost:8080", m.Handler()) } diff --git a/message.go b/message.go new file mode 100644 index 0000000..28228fb --- /dev/null +++ b/message.go @@ -0,0 +1,10 @@ +package messenger + +import "time" + +type Message struct { + Sender int64 + Recipient int64 + Time time.Time + Text string +} diff --git a/messenger.go b/messenger.go index 0bca0ea..88ca5ae 100644 --- a/messenger.go +++ b/messenger.go @@ -1,8 +1,10 @@ package messenger import ( + "encoding/json" "fmt" "net/http" + "time" ) const ( @@ -14,26 +16,85 @@ type MessengerOptions struct { VerifyToken string } +type MessageHandler func(Message) + type Messenger struct { - mux *http.ServeMux + mux *http.ServeMux + handlers map[Action]MessageHandler } func New(mo MessengerOptions) *Messenger { m := &Messenger{ - mux: http.NewServeMux(), + mux: http.NewServeMux(), + handlers: make(map[Action]MessageHandler), } if mo.Verify { m.mux.HandleFunc(WebhookURL, newVerifyHandler(mo.VerifyToken)) + } else { + m.mux.HandleFunc(WebhookURL, m.handle) } return m } +func (m *Messenger) Handle(a Action, f MessageHandler) { + m.handlers[a] = f +} + func (m *Messenger) Handler() http.Handler { return m.mux } +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'}`) +} + +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 + } + + if f := m.handlers[a]; f != nil { + f(Message{ + Sender: info.Sender.ID, + Recipient: info.Recipient.ID, + Time: time.Unix(info.Timestamp, 0), + Text: info.Message.Text, + }) + } + } + } +} + +func (m *Messenger) classify(info MessageInfo, e Entry) Action { + if info.Message != nil { + return TextAction + } + + return UnknownAction +} + 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 { diff --git a/receiving.go b/receiving.go new file mode 100644 index 0000000..2548488 --- /dev/null +++ b/receiving.go @@ -0,0 +1,33 @@ +package messenger + +type Receive struct { + Object string `json:"object"` + Entry []Entry `json:"entry"` +} + +type Entry struct { + ID int64 `json:"id"` + Time int64 `json:"time"` + Messaging []MessageInfo `json:"messaging"` +} + +type MessageInfo struct { + Sender Sender `json:"sender"` + Recipient Recipient `json:"recipient"` + Timestamp int64 `json:"timestamp"` + Message *MessageCallback `json:"message"` +} + +type Sender struct { + ID int64 `json:"id"` +} + +type Recipient struct { + ID int64 `json:"id"` +} + +type MessageCallback struct { + Mid string `json:"mid"` + Seq int `json:"seq"` + Text string `json:"text"` +}