go

微信监控机器人

🙉微信监控机器人设计

Posted by Liangjf on December 31, 2019

🙉微信监控机器人设计

微信监控机器人设计目录

1、背景

此文是我在公司内部的技术分享,在其基础上稍微做了修改。源码地址

细节决定成败,完善的售后服务机制是在众多产品中脱颖而出的关键因素。面对公司众多的客服群,客服人员可能不足,也或许没有及时留意到客服群的问题反馈,有时可能会造成不良的印象,从而影响到公司品牌。

因此一套自动监控微信客服群的系统会大大提高工作效率,及时发现问题和把问题存档。于是,微信监控机器人因此诞生。

2、组件

微信监控机器人的组件如下:

组件图

特别说明的是:

鉴权模块主要是针对第三方应用调用web server 暴露的RESTful API,并不是任何应由有权限调用,而是需要统一申请分配appIdappKey作为调用凭证。

监控模块主要是在wechat Bot掉线,发生错误时发送邮件通知管理员进行处理。

3、架构

微信监控机器人的详细架构如下:

架构图

3.1、web wechat登陆流程

wechat登录流程

3.1.1、协议分析

- 1、getUuid()。请求本次扫码登录的随机uuid,每次登陆都会拥有一个新的uuid,作为此次登录的uuidhttps://login.weixin.qq.com/jslogin

- 2、genQrCode()。请求二维码 - https://login.weixin.qq.com/qrcode/ + uuid

- 3、wait4login()。扫码登陆,得到重定向页面window.redirect_urihttps://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%d&uuid=%s&_=%s

- 4、login()。登陆获取key,wxsid,wxuin,pass_ticket,存cookiewindow.redirect_uri

- 5、init()。初始化数据,得到访问数据秘钥syncKey,syncKeyStrwindow.redirect_uri + /webwxinit

- 6、statusNotify()。通知微信服务端登陆ok - wc.redirectUri[:strings.LastIndex(wc.redirectUri, "/")] + /webwxstatusnotify?lang=zh_CN&pass_ticket=%s

- 7、GetContact()。拉取好友,群列表信息(pass_ticket,skeylogin()请求得到) - wc.redirectUri[:strings.LastIndex(wc.redirectUri, "/")] + /webwxgetcontact?lang=zh_CN&seq=%s&pass_ticket=%s&skey=%s&r=%s

- 8、procMsgLoop()。响应调度循环 - syncCheck(),sync()心跳同步维持连接 - https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=%s&sid=%s&uin=%s&skey=%s&deviceid=%&synckey=%s&_=%shandleMsg()。消息处理 -  wc.redirectUri[:strings.LastIndex(wc.redirectUri, "/")] + /webwxsync?sid=%s&skey=%s&lang=en_US&pass_ticket=%s

3.1.2、协议示例

init接口

sync接口

可以看到代码中wechat登录流程实质是模拟web wechat协议的。

4、核心模块

  • webot模块
  • web server模块
  • 核心业务模块

4.1、webot模块

  • 初始化server
  • 模拟web wechat登陆流程
  • 存储token,存储用户信息到session,存储key凭证,供暴露接口查询和使用
  • 初始化web server,关键goroutine(文本处理,阿里云交互),消息队列和db

webot模块是整个微信机器人的核心组件,主要是接收微信消息,解析消息,然后消息入库,并且push到消息队列,至此,它的一次信息传递就结束了,剩下的工作是核心业务goroutine来处理。

4.2、web server

  • keepalive(防止长时间被踢掉线)
  • RESTful api 暴露发送消息到好友,群接口

web server初始化并启动:

    g := gin.New()
    gin.SetMode(config.Config.ServerConf.Mode)
    g.Use(gin.Recovery())
    g.NoRoute(func(c *gin.Context) {
        c.String(http.StatusNotFound, "The incorrect API route")
    })
    g.GET(config.Config.WxBot4gConf.HeartbeatURL, TextHandle)
    v1 := g.Group("/v1/msg")
    {
        v1.GET("/text", TextHandle)
        v1.POST("/image", ImageHandle)
    }
    go InitHeartbeatCron()
    vslog.Error(http.ListenAndServe(":"+strconv.Itoa(config.Config.ServerConf.Port), g).Error())

项目中的web server是使用了gin这款简洁轻量级,压测结果很优秀的web框架。gin的核心是一个EngineContextEngine是整个gin框架的主控Context是把原生web请求的数据封装,并且带上一些重要的信息。

4.2.1、keepalive

通过定时任务,3分钟左右发送一次,目的是防止长时间无数据交互,被微信后台kill掉。

http://ip:port/v1/msg/text?word=keepalive&appkey=dkjhst89353oinf092yr90hnj&to=文件传输助手

4.2.2、发送消息(文本/图片)

提供RESTful api,供外部调用,提供发送消息到指定好友,群的功能。

http://ip:port/v1/msg/text?word=测试&appkey=dkjhst89353oinf092yr90hnj&to=测试群http://ip:port/v1/msg/image?imgUrl=http://xxxx&appkey=dkjhst89353oinf092yr90hnj&to=测试群

4.3、核心业务模块

  • 文本处理和情感分析 goroutine
  • aliyun oss交互 goroutine

golang的经典语:Don't communicate by sharing memory, share memory by communicating

goroutinechan是Go的特色,goroutine的优点就不必多说了,这两个业务通过goroutine处理,通过nsq消息队列,文本处理和情感分析 goroutine sub订阅文本处理topicaliyun oss交互 goroutine sub订阅图片msg,主要wechat Bot收到微信消息,并pushnsq消息队列,两个goroutine就会得到并处理。

消息队列

通过goroutine和消息队列,把业务处理解耦,借助消息队列的堆积功能,把聊天msg正常的积压在队列中,这样下游和上游不依赖,处理速度可以视下游goroutine的处理能力来决定,避免出现因众多微信群的聊天记录同时到来而处理不过来的情况。

5、系统改良点:

  • 群消息,非好友显示unknow。通过存储启动的用户信息到map,处理消息时通过暂时的UserName查询用户信息得到RemarkName或者DisplayName
  • 通过启动web server的keepalive定时任务,维持长时间的web wechat不掉线
  • 增加自动更新通信录

6、技术栈

6.1、Python版本

  • python2.7
  • 标准库queue,web server
  • mysql
  • aliyun api
  • wechat 协议

6.2、Go版本

  • go1.13
  • mysql数据库
  • nsq消息队列
  • redis
  • gin
  • gorm
  • aliyun api
  • wechat 协议

7、成果展示:

聊天记录效果

词频统计

8、总结

在逐步完善项目的同时,项目已正常跑在线上,实时监控众多客服群,并且提供给内部应用调用发送消息等能力。我认为,自动化的监控系统确实是可以大大提高生产力的,并且能够帮助人们更好的完成工作。