使用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源碼連結
留言
張貼留言