Mercurial > lbo > hg > goe_bot
changeset 21:08faa7039be7
Add infrastructure for callback handling
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 10 Dec 2016 09:37:36 +0100 |
parents | 851d4eaa877e |
children | 9e7757101e75 |
files | api_schema.go handler_todo.go handlers.go http.go pull.go status.go webhook.go |
diffstat | 7 files changed, 102 insertions(+), 36 deletions(-) [+] |
line wrap: on
line diff
--- a/api_schema.go Fri Dec 09 22:35:19 2016 +0100 +++ b/api_schema.go Sat Dec 10 09:37:36 2016 +0100 @@ -27,38 +27,29 @@ Forward_From_Chat chat } -type inlineQuery struct { +type callbackQuery struct { ID string From user - // Location - Query string - Offset string -} - -type callbackQuery struct { - ID string - From string // Message that this callback originated from Message message // Callback data Data string } +type update struct { + Update_ID uint64 + Message message + Channel_Post message + Callback_Query callbackQuery +} + +// Reply from getUpdates type updateReply struct { OK bool Result []update } -type update struct { - Update_ID uint64 - Message message - Edited_Message message - Channel_Post message - Edited_Channel_Post message - Inline_Query inlineQuery - Callback_Query callbackQuery -} - +// Reply from getWebhookInfo type webhookInfoReply struct { OK bool Result webhookInfo @@ -71,6 +62,7 @@ Last_Error_Message string } +// Body type for sendMessage and webhook reply type sendMessage struct { Chat_ID uint64 `json:"chat_id"` Text string `json:"text"`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/handler_todo.go Sat Dec 10 09:37:36 2016 +0100 @@ -0,0 +1,16 @@ +package main + +func todoButtonTest(msg message) (replyContent, error) { + buttonRows := [][]inlineKeyboardButton{} + + for _, b := range []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"} { + buttonRows = append(buttonRows, []inlineKeyboardButton{inlineKeyboardButton{Callback_Data: b, Text: b}}) + } + + return replyContent{text: "Please select", buttons: inlineKeyboardMarkup{buttonRows}}, nil +} + +func todoDoneHandler(token string) error { + + return nil +}
--- a/handlers.go Fri Dec 09 22:35:19 2016 +0100 +++ b/handlers.go Sat Dec 10 09:37:36 2016 +0100 @@ -2,6 +2,7 @@ import ( "bytes" + "errors" "fmt" "log" "strings" @@ -16,6 +17,8 @@ statusCmd = "status" todoCmd = "todo" todoTestCmd = "todo-" + + todoDoneCallback = "markdone" ) type handler struct { @@ -23,6 +26,9 @@ desc string } +// A handler taking the callback data. `data` only contains the token, not the callback type. +type callbackHandler (func(data string) error) + var ( handlers = map[string]handler{ echoCmd: {echoHandler, "Anfrage zurücksenden"}, @@ -33,6 +39,10 @@ todoCmd: {missingHandler, "Aufgabenliste"}, todoTestCmd: {todoButtonTest, "TODO test (internal)"}, } + + callbackHandlers = map[string]callbackHandler{ + todoDoneCallback: todoDoneHandler, + } ) type replyContent struct { @@ -70,17 +80,48 @@ return replyContent{text: srvStatus.String()}, nil } -func todoButtonTest(msg message) (replyContent, error) { - buttonRows := [][]inlineKeyboardButton{} +func dispatch(upd update) (sendMessage, error) { + if upd.Message.Message_ID > 0 { + srvStatus.commands++ + + msg, err := dispatchMessage(upd.Message) + + if err != nil { + srvStatus.errors++ + } - for _, b := range []string{"1", "2", "3"} { - buttonRows = append(buttonRows, []inlineKeyboardButton{inlineKeyboardButton{Callback_Data: b, Text: b}}) + return msg, err + } else if upd.Callback_Query.ID != "" { + srvStatus.callbacks++ + dispatchCallback(upd.Callback_Query) + + return sendMessage{}, nil + } else { + + reply := sendMessage{ + Chat_ID: upd.Message.Chat.ID, + Parse_Mode: "Markdown", + Text: "", + } + + return reply, nil } - - return replyContent{text: "Please select", buttons: inlineKeyboardMarkup{buttonRows}}, nil } -func dispatch(msg message) (sendMessage, error) { +// Dispatches an incoming callbackQuery. The data field has the format callback_type:token. +func dispatchCallback(cbq callbackQuery) error { + parts := strings.Split(cbq.Data, ":") // callback:token + + if handler, ok := callbackHandlers[parts[0]]; ok { + handler(parts[1]) + return nil + } else { + log.Println("Didn't find callback handler for type", parts[0]) + return errors.New("handler not found") + } +} + +func dispatchMessage(msg message) (sendMessage, error) { var rp replyContent var err error
--- a/http.go Fri Dec 09 22:35:19 2016 +0100 +++ b/http.go Sat Dec 10 09:37:36 2016 +0100 @@ -54,9 +54,9 @@ debugChat := chat{ID: 1, Type: "private", Title: "__debug", First_Name: "debug"} msg := message{Chat: debugChat, From: debugUser, Message_ID: 1, Date: uint64(time.Now().Unix()), Text: string(body)} - srvStatus.numCommands++ + srvStatus.commands++ - reply, err := dispatch(msg) + reply, err := dispatch(update{Message: msg, Update_ID: 12345}) if err != nil { srvStatus.errors++
--- a/pull.go Fri Dec 09 22:35:19 2016 +0100 +++ b/pull.go Sat Dec 10 09:37:36 2016 +0100 @@ -45,13 +45,15 @@ } for u := range upds.Result { - srvStatus.numCommands++ - - sM, err := dispatch(upds.Result[u].Message) + sM, err := dispatch(upds.Result[u]) if err != nil { log.Println(err) - srvStatus.errors++ + } + + // Empty reply, e.g. for callback handlers + if sM.Chat_ID == 0 { + continue } err = sendReply(sM) @@ -79,12 +81,16 @@ url := buildURL(sendMessageMethod) + srvStatus.apiCalls++ + rp, err := defaultClient.Post(url, jsonBodyType, bytes.NewBuffer(body)) if err != nil { + srvStatus.apiErrors++ log.Println(err) return err } else if rp.StatusCode != http.StatusOK { + srvStatus.apiErrors++ log.Println("Error:", rp.StatusCode, rp.Status) }
--- a/status.go Fri Dec 09 22:35:19 2016 +0100 +++ b/status.go Sat Dec 10 09:37:36 2016 +0100 @@ -9,13 +9,15 @@ ok bool dbConnected bool database string - numCommands uint + commands uint + callbacks uint errors uint apiErrors uint + apiCalls uint } func (ss serverStatus) String() string { webhookInfo, _ := getWebhookInfo() - return fmt.Sprintf("ok=%t db=%t dbname=%s cmds=%d errs=%d api-errs=%d %s", - ss.ok, ss.dbConnected, ss.database, ss.numCommands, ss.errors, ss.apiErrors, webhookInfo) + return fmt.Sprintf("ok=%t db=%t dbname=%s cmds=%d callbacks=%d errs=%d api-errs=%d api-calls=%d %s", + ss.ok, ss.dbConnected, ss.database, ss.commands, ss.callbacks, ss.errors, ss.apiErrors, ss.apiCalls, webhookInfo) }
--- a/webhook.go Fri Dec 09 22:35:19 2016 +0100 +++ b/webhook.go Sat Dec 10 09:37:36 2016 +0100 @@ -52,6 +52,8 @@ } func getWebhookInfo() (string, error) { + srvStatus.apiCalls++ + rp, err := defaultClient.Get(buildURL(getWebhookInfoMethod)) if err != nil { @@ -76,6 +78,7 @@ return fmt.Sprintf("pending=%d last-error='%s'", info.Pending_Update_Count, info.Last_Error_Message), nil } else { + srvStatus.apiErrors++ log.Println("Couldn't getWebhookInfo:", rp.StatusCode) return "", errors.New("Bad response code") } @@ -109,7 +112,7 @@ return } - responseMsg, err := dispatch(upd.Message) + responseMsg, err := dispatch(upd) if err != nil { rp.WriteHeader(http.StatusInternalServerError) @@ -117,6 +120,12 @@ return } + // Empty response, e.g. for callback handlers + if responseMsg.Chat_ID == 0 { + rp.WriteHeader(http.StatusOK) + return + } + responseMsg.Method = sendMessageMethod responseBody, err := json.Marshal(responseMsg)