使用Golang串接哈哈姆特
文章最下面有原碼
首先建立一個http server
先定義用來裝json東西的struct,用法跟gson差不多
先看看他們給的json長什麼樣子
拆解成這些struct bean
定義struct bean
接下來都有註解了 自己看吧= =
而傳圖片稍微有點複雜,可以看看這篇
豬腳的文章也說得很清楚
接下來去用Dep來控制專案,要使用到cmd指令,用Vs code內建的就好了
下載dep
接著佈署到平台上面,範例是heroku
下載 Heroku command line
登入
func main() { //開啟伺服器 http.HandleFunc("/", handler) port := os.Getenv("PORT") if port == "" { log.Fatal("$PORT must be set") } address := ":" + port log.Println("Starting server on address", address) err := http.ListenAndServe(address, nil) if err != nil { panic(err) } }根據Golang的HandleFunc的官方文件,建立一個handler
func handler(w http.ResponseWriter, r *http.Request) { // Do: 結束後執行 關閉httpRequest defer r.Body.Close() // Do: Read body b, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), 500) return } // Do: 傳回200 request200(w) // Do: 驗證簽章 err = verifyWebhook(r, b) if err != nil { http.Error(w, err.Error(), 500) return } // Do: Decode body 的東西 var msg Message err = json.Unmarshal(b, &msg) if err != nil { http.Error(w, err.Error(), 500) return } // Do: 剩下靠自己 fmt.Println("bot_id=", msg.BotID) fmt.Println("time=", msg.Time) fmt.Println("senderid=", msg.Messaging[0].SenderID) fmt.Println("text=", msg.Messaging[0].Message.Text) handleMessage(w, msg.Messaging[0].Message.Text, msg.Messaging[0].SenderID) }哈哈姆特需要我們傳回一個status ok,傳回200,也可以用http內建的StatusOK的const
func request200(w http.ResponseWriter) { w.WriteHeader(200) }接下來需要驗證webhook,需要使用hmac-sha1,我們使用golang內建的crypto包裡的函式來雜湊伺服器端傳來的body和bot的APP_SECRET來雜湊比對和伺服器傳來的密鑰是否一樣 這裡我採用判斷後不符合傳回一個error來判斷
type VerifyError struct { When time.Time What string } func (e *VerifyError) Error() string { fmt.Println("Error:", e.What) return fmt.Sprintf("at %v, %s", e.When, e.What) } func verifyWebhook(r *http.Request, body []byte) error { //Note: 取得x-baha-data-signature開頭的Header headerget := r.Header.Get("x-baha-data-signature") key := []byte(headerget[5:]) fmt.Println("key=", key) //Note: 使用HMAC-SHA1雜湊APP_SECRET和傳來的Body mac := hmac.New(sha1.New, []byte(APP_SECRET)) mac.Write(body) fmt.Printf("%x\n", mac.Sum(nil)) //轉為字串比較 str1 := string(key[:]) str2 := fmt.Sprintf("%x", mac.Sum(nil)) fmt.Println("str1=", str1) fmt.Println("str2=", str2) if str1 != str2 { return &VerifyError{ time.Now(), "Verify error", } } else { return nil } }接下來就能開心的接收和傳訊息惹!
先定義用來裝json東西的struct,用法跟gson差不多
先看看他們給的json長什麼樣子
拆解成這些struct bean
type Text struct { Text string `json:"text"` } type Messaging struct { SenderID string `json:"sender_id"` Message Text `json:"message"` } type Message struct { BotID string `json:"botid"` Time int `json:"time"` Messaging []Messaging `json:"messaging"` }把伺服器端傳來的Body的Json字串用Golang內建的包來解析放入struct
var msg Message err = json.Unmarshal(b, &msg) if err != nil { http.Error(w, err.Error(), 500) return }接下來就能大大方方的用啦!
fmt.Println("bot_id=", msg.BotID) fmt.Println("time=", msg.Time) fmt.Println("senderid=", msg.Messaging[0].SenderID) fmt.Println("text=", msg.Messaging[0].Message.Text)而傳訊息也沒有很難!先定義好使用者傳送什麼字觸發什麼功能
func handleMessage(w http.ResponseWriter, msg string, senderid string) { switch msg { case "打招呼": sendMsg(w, senderid, "嗨嗨OwO") case "發貼圖": sendSticker(w, senderid, "28", "09") case "發圖片": sendImg(w, senderid, "src/img/ralsei.png") default: sendMsg(w, senderid, "我聽不懂==") } }先看傳訊息的json包的內容
定義struct bean
type Recipient struct { ID string `json:"id"` } type MessageingSend struct { Type string `json:"type"` Text string `json:"text"` } type MessageSend struct { MyRecipient Recipient `json:"recipient"` MyMessageingSend MessageingSend `json:"message"` }
接下來都有註解了 自己看吧= =
func sendMsg(w http.ResponseWriter, senderID string, msg string) { // 包成json r := Recipient{senderID} m := MessageingSend{"text", msg} ms := MessageSend{r, m} json, err := json.Marshal(ms) if err != nil { http.Error(w, err.Error(), 500) return } // 請求Post req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", POST_URL, ACCESS_TOKEN), bytes.NewBuffer(json)) if err != nil { http.Error(w, err.Error(), 500) return } // 設置header req.Header.Set("X-Custom-Header", "badfox-sender") req.Header.Set("Content-Type", "application/json") // For control over HTTP client headers client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } //取得哈哈的伺服器取得狀態 body, _ := ioutil.ReadAll(resp.Body) fmt.Println("Response Status:", resp.Status) fmt.Println("Response Headers:", resp.Header) fmt.Println("Response Body:", string(body)) }傳貼圖也是相同的道理,就不再貼了
而傳圖片稍微有點複雜,可以看看這篇
豬腳的文章也說得很清楚
接下來去用Dep來控制專案,要使用到cmd指令,用Vs code內建的就好了
下載dep
$go get -u github.com/golang/dep/cmd/dep初始化
$dep init資料夾會出現 Gopkg.toml 和 Gopkg.lock
接著佈署到平台上面,範例是heroku
下載 Heroku command line
登入
$heroku loginclone 專案
$heroku git:clone -a Easy-hahamut-bot移到clone的專案資料夾
$cd Easy-hahamut-botgit 到緩存區
$git add .提交 git
$git commit -am "my first hahamut bot"佈署到heroku
$git push heroku masterGithub源碼連結
留言
張貼留言