Week22 - 用Redis来帮Line bot髒沙发设计一次性功能 - 实作篇 [Server的终局之战系列]

本文章同时发布于:

MediumiT邦帮忙

大家好,继上次Week21 - 用Redis来帮Line bot髒沙发设计一次性功能 - 概念篇后,这次要来说明实作的部分。

你可能是先要先知道

Line bot串接: 可以参考twtrubiks大大的line-bot-tutorialDocker: 也可参考twtrubiks大大的docker-tutorial

因为这篇文章会着重在Redis,所以Line bot的串接细节就不多着墨。

并且为求方便快速,Redis也会透过Docker来直接产生,如果大家不太知道Docker是什么的话,广义简单的来说,他就是一个「秒启动的虚拟机」。

Docker透过把实机的核心挂载至一个隔离环境来当成虚拟机,此虚拟机不用透过Hypervisor与实机沟通,运作成本非常小,所以效能与启动速度跟实机差不多。

听起来很複杂?没关係你可以看twtrubiks大大的文章或者就直接把它当成一个超强超快的虚拟机就对了XD

整体流程与格式

使用者Line-APP传送的讯息与图片,Line-Server都会打一个API给我们指定的My-Server,我们俗称Webhook

所以我们只需实作一个POST API api/WebhookHanlder来接受Line ServerWebhook,即可模拟实际状况。

格式

# POST API api/WebhookHanlder# API-1{  "groupID": "69617aa7-9512-44c3-9e10-1626cc8bf585",  "type": "message",  "data": {    "text": "辨识"  }}# POST API api/WebhookHanlder# API-2{  "groupID": "69617aa7-9512-44c3-9e10-1626cc8bf585",  "type": "image",  "data": {    "imageID": "9b2fcfb3-e39c-4ea2-96a7-a3fb408095d0"  }}# Redis-1key: 3e6e3637-45da-458f-8ade-85b8b9f0af8a:search // 为GroupID+typevalue: true

实作

完整程式码在此: w3school-40-weeks

解释我会在程式码旁边注释。


首先我们先进入week22的资料夹,

$ cd week22

利用docker-compose来启动Redis

$ docker-compose up
version: '3.5'services:  redis:    image: redis:alpine    command: redis-server --appendonly yes    ports:      - 6379:6379 # 将docker内的Redis的6379 port对应到实机6379 port    volumes:      - ./data:/data    restart: always

启动Server

$ go run main.go

主要的main functionRedis初始化,并设置API

func initRedis() *libredis.Client {option, err := libredis.ParseURL("redis://localhost:6379/0")check(err)client := libredis.NewClient(option)return client}func main() {r := gin.Default()redisClient = initRedis() // 初始化Redisr.POST("/api/WebhookHanlder", webhookHanlder) // 新增POST API api/WebhookHanlderr.Run()}

webhookHanlder function来处理POST API api/WebhookHanlder的请求,并且会比对json bodytypemessage还是image来换到textHandler functionimageHandler function来处理。

// Controllerfunc webhookHanlder(c *gin.Context) {var postType PostTypereadBody(c, &postType) // 读取request的body,并把struct套上,这个PostType struct是专门用来解析request type的switch postType.Type { // 如果是message type就以textHandler function处理,如果是image type就以imageHandler function处理case "message":textHandler(c)case "image":imageHandler(c)}}func textHandler(c *gin.Context) {var postMessage PostMessagereadBody(c, &postMessage)                       // 读取request的body,并把struct套上,这个PostMessage struct是专门用来读取message json的key := postMessage.GroupID + ":search"          // 将GroupID+typeerr := redisClient.Set(ctx, key, true, 0).Err() // 设置key为GroupID+type,value为truecheck(err)err = redisClient.Expire(ctx, key, 24*time.Hour).Err() // 设置key-value的过期时间为24小时check(err)c.Status(204) // 回传204 response}func imageHandler(c *gin.Context) {isThereSearchRequest := func(redisGroupResult string, err error) bool {if err != nil || redisGroupResult == "" {return false}redisGroupResultBool, err := strconv.ParseBool(redisGroupResult)check(err)return redisGroupResultBool}var postImage PostImagereadBody(c, &postImage)                                       // 读取request的body,并把struct套上,这个PPostImage struct是专门用来读取image json的key := postImage.GroupID + ":search"                          // 将GroupID+typeif isThereSearchRequest(redisClient.Get(ctx, key).Result()) { // 如果GroupID+type存在就回传女优资讯,不存在就回传「你没有要求辨识」的error messagec.JSON(200, gin.H{"AVStar": "佐仓绊",})return}c.JSON(403, gin.H{"error": "No search requested",})}

谢谢你的阅读,也欢迎分享讨论指正~

参考与引用资料

*Golang: Read from an io.ReadWriter without losing its content

line-bot-tutorialdocker-tutorial

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章