Skip to content

OptimizedWechatApp #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions backend/handler/share/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ func NewShareAppHandler(
})
share.GET("/web/info", h.GetWebAppInfo)

share.GET("/wechat/app", h.VerifiyUrl)
share.POST("/wechat/app", h.WechatHandler)
share.GET("/wechat/app", h.VerifyUrl_APP)
share.POST("/wechat/app", h.WechatHandler_APP)

return h
}
Expand All @@ -72,7 +72,7 @@ func (h *ShareAppHandler) GetWebAppInfo(c echo.Context) error {
return h.NewResponseWithData(c, appInfo)
}

func (h *ShareAppHandler) VerifiyUrl(c echo.Context) error {
func (h *ShareAppHandler) VerifyUrl_APP(c echo.Context) error {
signature := c.QueryParam("msg_signature")
timestamp := c.QueryParam("timestamp")
nonce := c.QueryParam("nonce")
Expand All @@ -86,22 +86,22 @@ func (h *ShareAppHandler) VerifiyUrl(c echo.Context) error {

if signature == "" || timestamp == "" || nonce == "" || echostr == "" {
return h.NewResponseWithError(
c, "Verifiy Wechat failed", nil,
c, "Verifiy Wechat_APP failed", nil,
)
}

ctx := c.Request().Context()

req, err := h.usecase.VerifiyUrl(ctx, signature, timestamp, nonce, echostr, kbID)
req, err := h.usecase.VerifyUrl_APP(ctx, signature, timestamp, nonce, echostr, kbID)
if err != nil {
return h.NewResponseWithError(c, "VerifyURL failed", err)
return h.NewResponseWithError(c, "VerifyURL_APP failed", err)
}

// success
return c.String(http.StatusOK, string(req))
}

func (h *ShareAppHandler) WechatHandler(c echo.Context) error {
func (h *ShareAppHandler) WechatHandler_APP(c echo.Context) error {

signature := c.QueryParam("msg_signature")
timestamp := c.QueryParam("timestamp")
Expand All @@ -113,8 +113,6 @@ func (h *ShareAppHandler) WechatHandler(c echo.Context) error {
return h.NewResponseWithError(c, "kb_id is required", nil)
}

RemoteIP := ""

body, err := io.ReadAll(c.Request().Body)
if err != nil {
h.logger.Error("get request failed", log.Error(err))
Expand All @@ -130,13 +128,13 @@ func (h *ShareAppHandler) WechatHandler(c echo.Context) error {
return h.NewResponseWithError(c, "Failed to send immediate response", err)
}

go func(signature, timestamp, nonce string, body []byte, KbId string, remoteip string) {
go func(signature, timestamp, nonce string, body []byte, kbID string) {
ctx := context.Background()
err := h.usecase.Wechat(ctx, signature, timestamp, nonce, body, KbId, remoteip)
err := h.usecase.Wechat(ctx, signature, timestamp, nonce, body, kbID)
if err != nil {
h.logger.Error("wechat async failed")
}
}(signature, timestamp, nonce, body, kbID, RemoteIP)
}(signature, timestamp, nonce, body, kbID)

return c.XMLBlob(http.StatusOK, []byte(immediateResponse))
}
44 changes: 29 additions & 15 deletions backend/pkg/bot/wechat/wechat.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
"errors"
"fmt"
"io"
"log"
"net/http"
"sync"
"time"

"github.com/chaitin/panda-wiki/log"
"github.com/sbzhu/weworkapi_golang/wxbizmsgcrypt"
)

Expand All @@ -22,11 +23,18 @@ type WechatConfig struct {
EncodingAESKey string
kbID string
Secret string
AccessToken string
TokenExpire time.Time
AgentID string
logger *log.Logger
}

type TokenCahe struct {
AccessToken string
TokenExpire time.Time
Mutex sync.Mutex
}

var TokenCache *TokenCahe = &TokenCahe{}

type ReceivedMessage struct {
ToUserName string `xml:"ToUserName"`
FromUserName string `xml:"FromUserName"`
Expand Down Expand Up @@ -62,7 +70,7 @@ type BackendResponse struct {
} `json:"data"`
}

func NewWechatConfig(ctx context.Context, CorpID, Token, EncodingAESKey string, kbid string, secret string, againtid string) (*WechatConfig, error) {
func NewWechatConfig(ctx context.Context, CorpID, Token, EncodingAESKey string, kbid string, secret string, againtid string, logger *log.Logger) (*WechatConfig, error) {
return &WechatConfig{
Ctx: ctx,
CorpID: CorpID,
Expand All @@ -71,10 +79,11 @@ func NewWechatConfig(ctx context.Context, CorpID, Token, EncodingAESKey string,
kbID: kbid,
Secret: secret,
AgentID: againtid,
logger: logger,
}, nil
}

func (cfg *WechatConfig) VerifiyUrl(signature, timestamp, nonce, echostr string) ([]byte, error) {
func (cfg *WechatConfig) VerifyUrl(signature, timestamp, nonce, echostr string) ([]byte, error) {
wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(
cfg.Token,
cfg.EncodingAESKey,
Expand Down Expand Up @@ -115,7 +124,7 @@ func (cfg *WechatConfig) Wechat(signature, timestamp, nonce string, body []byte,

err = cfg.Processmessage(msg, getQA, token)
if err != nil {
log.Printf("send to ai failed! : %v", err)
cfg.logger.Error("send to ai failed!")
return err
}

Expand Down Expand Up @@ -154,7 +163,7 @@ func (cfg *WechatConfig) Processmessage(msg ReceivedMessage, GetQA func(ctx cont
resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))

if err != nil {
return fmt.Errorf("post to we failed: %w", err)
return fmt.Errorf("post to wechatAPP failed: %w", err)
}
defer resp.Body.Close()

Expand Down Expand Up @@ -190,7 +199,7 @@ func (cfg *WechatConfig) SendResponse(msg ReceivedMessage, content string) ([]by
// XML
responseXML, err := xml.Marshal(responseMsg)
if err != nil {
log.Printf("xml Marshal failed: %v", err)
cfg.logger.Error("xml Marshal failed")
return nil, err
}

Expand All @@ -208,12 +217,16 @@ func (cfg *WechatConfig) SendResponse(msg ReceivedMessage, content string) ([]by

func (cfg *WechatConfig) GetAccessToken() (string, error) {

if cfg.AccessToken != "" && time.Now().Before(cfg.TokenExpire) {
return cfg.AccessToken, nil
TokenCache.Mutex.Lock()
defer TokenCache.Mutex.Unlock()

if TokenCache.AccessToken != "" && time.Now().Before(TokenCache.TokenExpire) {
cfg.logger.Info("access token has existed and valid")
return TokenCache.AccessToken, nil
}

if cfg.Secret == "" {
return "", errors.New("secret is not right")
if cfg.Secret == "" || cfg.CorpID == "" {
return "", errors.New("secret or corpid is not right")
}

// get AccessToken
Expand All @@ -240,9 +253,10 @@ func (cfg *WechatConfig) GetAccessToken() (string, error) {
}

// succcess
cfg.logger.Info("wechatapp get accesstoken success", log.Any("info", tokenResp.AccessToken))

cfg.AccessToken = tokenResp.AccessToken
cfg.TokenExpire = time.Now().Add(time.Duration(tokenResp.ExpiresIn-300) * time.Second)
TokenCache.AccessToken = tokenResp.AccessToken
TokenCache.TokenExpire = time.Now().Add(time.Duration(tokenResp.ExpiresIn-300) * time.Second)

return cfg.AccessToken, nil
return TokenCache.AccessToken, nil
}
27 changes: 0 additions & 27 deletions backend/usecase/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,33 +108,6 @@ func (u *AppUsecase) getQAFunc(kbID string, appType domain.AppType) func(ctx con
}
}

func (u *AppUsecase) wechatQAFunc(kbID string, appType domain.AppType, remoteip string) func(ctx context.Context, msg string) (chan string, error) {
return func(ctx context.Context, msg string) (chan string, error) {
eventCh, err := u.chatUsecase.Chat(ctx, &domain.ChatRequest{
Message: msg,
KBID: kbID,
AppType: appType,
RemoteIP: remoteip,
})
if err != nil {
return nil, err
}
contentCh := make(chan string, 10)
go func() {
defer close(contentCh)
for event := range eventCh { // get content from eventch
if event.Type == "done" || event.Type == "error" {
break
}
if event.Type == "data" {
contentCh <- event.Content
}
}
}()
return contentCh, nil
}
}

func (u *AppUsecase) updateFeishuBot(app *domain.App) {
u.feishuMutex.Lock()
defer u.feishuMutex.Unlock()
Expand Down
82 changes: 40 additions & 42 deletions backend/usecase/wechatApp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,107 +4,92 @@ import (
"context"
"encoding/xml"
"fmt"
"time"

"github.com/chaitin/panda-wiki/domain"
"github.com/chaitin/panda-wiki/log"
"github.com/chaitin/panda-wiki/pkg/bot/wechat"
"github.com/sbzhu/weworkapi_golang/wxbizmsgcrypt"
)

func (u *AppUsecase) VerifiyUrl(ctx context.Context, signature, timestamp, nonce, echostr, KbId string) ([]byte, error) {
func (u *AppUsecase) VerifyUrl_APP(ctx context.Context, signature, timestamp, nonce, echostr, kbID string) ([]byte, error) {
// 只有5秒的校验时间(符合企业微信)
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

// find wechat-bot
appres, err := u.GetAppDetailByKBIDAndAppType(ctx, KbId, domain.AppTypeWechatBot)
appres, err := u.GetAppDetailByKBIDAndAppType(ctx, kbID, domain.AppTypeWechatBot)
if err != nil {
u.logger.Error("find Appdetail failed")
u.logger.Error("find Appdetail failed", log.Error(err))
return nil, err
}

u.logger.Debug("wechat app info", log.Any("info", appres))

wc, err := wechat.NewWechatConfig(
ctx,
appres.Settings.WeChatAppCorpID,
appres.Settings.WeChatAppToken,
appres.Settings.WeChatAppEncodingAESKey,
KbId,
appres.Settings.WeChatAppSecret,
appres.Settings.WeChatAppAgentID,
)
WechatConf, err := u.newWechatConfig(ctx, appres, kbID)

if err != nil {
u.logger.Error("failed to create WechatConfig", log.Error(err))
return nil, err
}

body, err := wc.VerifiyUrl(signature, timestamp, nonce, echostr)
body, err := WechatConf.VerifyUrl(signature, timestamp, nonce, echostr)
if err != nil {
u.logger.Error("wc verifiyUrl failed", log.Error(err))
u.logger.Error("WechatConf verifiyUrl failed", log.Error(err))
return nil, err
}
return body, nil
}

func (u *AppUsecase) Wechat(ctx context.Context, signature, timestamp, nonce string, body []byte, KbId string, remoteip string) error {
func (u *AppUsecase) Wechat(ctx context.Context, signature, timestamp, nonce string, body []byte, kbID string) error {

// find wechat-bot
appres, err := u.GetAppDetailByKBIDAndAppType(ctx, KbId, domain.AppTypeWechatBot)
appres, err := u.GetAppDetailByKBIDAndAppType(ctx, kbID, domain.AppTypeWechatBot)

if err != nil {
u.logger.Error("find Appdetail failed")
}

wc, err := wechat.NewWechatConfig(
ctx,
appres.Settings.WeChatAppCorpID,
appres.Settings.WeChatAppToken,
appres.Settings.WeChatAppEncodingAESKey,
KbId,
appres.Settings.WeChatAppSecret,
appres.Settings.WeChatAppAgentID,
)
u.logger.Info("wechatapp bot found: ", log.Any("info", appres))
WechatConf, err := u.newWechatConfig(ctx, appres, kbID)

if err != nil {
u.logger.Error("failed to create WechatConfig", log.Error(err))
return err
}
u.logger.Info("remote ip", log.String("ip", remoteip))

// u.logger.Info("create wc success", wc)

// use ai
getQA := u.wechatQAFunc(KbId, appres.Type, remoteip)
getQA := u.getQAFunc(kbID, appres.Type)

err = wc.Wechat(signature, timestamp, nonce, body, getQA)
err = WechatConf.Wechat(signature, timestamp, nonce, body, getQA)

if err != nil {
u.logger.Error("wc wechat failed", log.Error(err))
u.logger.Error("WechatConf wechat failed", log.Error(err))
return err
}
return nil
}

func (u *AppUsecase) SendImmediateResponse(ctx context.Context, signature, timestamp, nonce string, body []byte, kbID string) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()

appres, err := u.GetAppDetailByKBIDAndAppType(ctx, kbID, domain.AppTypeWechatBot)

if err != nil {
return nil, err
}

wc, err := wechat.NewWechatConfig(
ctx,
appres.Settings.WeChatAppCorpID,
appres.Settings.WeChatAppToken,
appres.Settings.WeChatAppEncodingAESKey,
kbID,
appres.Settings.WeChatAppSecret,
appres.Settings.WeChatAppAgentID,
)
WechatConf, err := u.newWechatConfig(ctx, appres, kbID)

u.logger.Debug("wechat app info", log.Any("app", appres))

if err != nil {
return nil, err
}

wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(wc.Token, wc.EncodingAESKey, wc.CorpID, wxbizmsgcrypt.XmlType)
// 解密消息
wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(WechatConf.Token, WechatConf.EncodingAESKey, WechatConf.CorpID, wxbizmsgcrypt.XmlType)
decryptMsg, errCode := wxcpt.DecryptMsg(signature, timestamp, nonce, body)

if errCode != nil {
Expand All @@ -117,5 +102,18 @@ func (u *AppUsecase) SendImmediateResponse(ctx context.Context, signature, times
}

// send response "正在思考"
return wc.SendResponse(msg, "正在思考您的问题,请稍候...")
return WechatConf.SendResponse(msg, "正在思考您的问题,请稍候...")
}

func (u *AppUsecase) newWechatConfig(ctx context.Context, appres *domain.AppDetailResp, kbID string) (*wechat.WechatConfig, error) {
return wechat.NewWechatConfig(
ctx,
appres.Settings.WeChatAppCorpID,
appres.Settings.WeChatAppToken,
appres.Settings.WeChatAppEncodingAESKey,
kbID,
appres.Settings.WeChatAppSecret,
appres.Settings.WeChatAppAgentID,
u.logger,
)
}