diff --git a/.gitignore b/.gitignore index 318dc65..ac37619 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ demo.php -show.php \ No newline at end of file +show.php +.DS_Store \ No newline at end of file diff --git a/go-scf/.gitignore b/go-scf/.gitignore new file mode 100644 index 0000000..bb1bbbf --- /dev/null +++ b/go-scf/.gitignore @@ -0,0 +1,8 @@ +.vscode/ +main +msg_notice +*.exe +*.zip +*_test.go +*.zip +.DS_Store \ No newline at end of file diff --git a/go-scf/README.md b/go-scf/README.md new file mode 100644 index 0000000..b91de37 --- /dev/null +++ b/go-scf/README.md @@ -0,0 +1,2 @@ +# 腾讯云云函数部署 + diff --git a/go-scf/build.sh b/go-scf/build.sh new file mode 100755 index 0000000..4c4d63b --- /dev/null +++ b/go-scf/build.sh @@ -0,0 +1,4 @@ +set -ex + + +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main \ No newline at end of file diff --git a/go-scf/consts/consts.go b/go-scf/consts/consts.go new file mode 100644 index 0000000..ee7583a --- /dev/null +++ b/go-scf/consts/consts.go @@ -0,0 +1,15 @@ +package consts + +const ( + SENDKEY = "set_a_sendkey" + WECOM_CID = "企业微信公司ID" + WECOM_SECRET = "企业微信应用Secret" + WECOM_AID = "企业微信应用ID" + WECOM_TOUID = "@all" +) + +// 微信发消息API +const ( + WeComMsgSendURL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s" + WeComAccessTokenURL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s" +) diff --git a/go-scf/go.mod b/go-scf/go.mod new file mode 100644 index 0000000..80bed7d --- /dev/null +++ b/go-scf/go.mod @@ -0,0 +1,8 @@ +module github.com/riba2534/wecomchan/go-scf + +go 1.16 + +require ( + github.com/json-iterator/go v1.1.11 + github.com/tencentyun/scf-go-lib v0.0.0-20200624065115-ba679e2ec9c9 +) diff --git a/go-scf/go.sum b/go-scf/go.sum new file mode 100644 index 0000000..e6e7262 --- /dev/null +++ b/go-scf/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tencentyun/scf-go-lib v0.0.0-20200624065115-ba679e2ec9c9 h1:JdeXp/XPi7lBmpQNSUxElMAvwppMlFSiamTtXYRFuUc= +github.com/tencentyun/scf-go-lib v0.0.0-20200624065115-ba679e2ec9c9/go.mod h1:K3DbqPpP2WE/9MWokWWzgFZcbgtMb9Wd5CYk9AAbEN8= diff --git a/go-scf/main.go b/go-scf/main.go new file mode 100644 index 0000000..5744ec3 --- /dev/null +++ b/go-scf/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "context" + "strings" + + "github.com/riba2534/wecomchan/go-scf/service" + "github.com/riba2534/wecomchan/go-scf/utils" + "github.com/tencentyun/scf-go-lib/cloudfunction" + "github.com/tencentyun/scf-go-lib/events" +) + +func HTTPHandler(ctx context.Context, event events.APIGatewayRequest) (events.APIGatewayResponse, error) { + path := event.Path + var result interface{} + if strings.HasPrefix(path, "/wecomchan") { + result = service.WeComChanService + } else { + // 匹配失败返回原始HTTP请求 + result = event + } + return events.APIGatewayResponse{ + IsBase64Encoded: false, + StatusCode: 200, + Headers: map[string]string{}, + Body: utils.MarshalToStringParam(result), + }, nil +} + +func main() { + cloudfunction.Start(HTTPHandler) +} diff --git a/go-scf/model/model.go b/go-scf/model/model.go new file mode 100644 index 0000000..1a470b7 --- /dev/null +++ b/go-scf/model/model.go @@ -0,0 +1,27 @@ +package model + +type AssesTokenResp struct { + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` +} + +type MsgText struct { + Content string `json:"content"` +} + +// https://work.weixin.qq.com/api/doc/90002/90151/90854 +type WechatMsg struct { + ToUser string `json:"touser"` + AgentId string `json:"agentid"` + MsgType string `json:"msgtype"` + Text *MsgText `json:"text"` + DuplicateCheckInterval int `json:"duplicate_check_interval"` +} + +type PostResp struct { + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` + Invaliduser string `json:"invaliduser"` +} diff --git a/go-scf/service/wecomchan.go b/go-scf/service/wecomchan.go new file mode 100644 index 0000000..c3aea84 --- /dev/null +++ b/go-scf/service/wecomchan.go @@ -0,0 +1,106 @@ +package service + +import ( + "bytes" + "context" + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" + + jsoniter "github.com/json-iterator/go" + "github.com/riba2534/wecomchan/go-scf/consts" + "github.com/riba2534/wecomchan/go-scf/model" + "github.com/riba2534/wecomchan/go-scf/utils" + "github.com/tencentyun/scf-go-lib/events" +) + +func WeComChanService(ctx context.Context, event events.APIGatewayRequest) interface{} { + accessToken, err := getAccessToken() + if err != nil { + return utils.MakeResp(-1, "get accessToken error") + } + sendKey := getQuery("sendkey", event.QueryString) + msgType := getQuery("msg_type", event.QueryString) + msg := getQuery("msg", event.QueryString) + if accessToken == "" || msgType == "" || msg == "" { + return utils.MakeResp(-1, "param error") + } + if sendKey != consts.SENDKEY { + return utils.MakeResp(-1, "sendkey error") + } + if err := postWechatMsg(accessToken, msg, msgType); err != nil { + return utils.MakeResp(0, err.Error()) + } + return utils.MakeResp(0, "success") +} + +func getAccessToken() (string, error) { + client := http.Client{Timeout: 10 * time.Second} + req, _ := http.NewRequest("GET", fmt.Sprintf(consts.WeComAccessTokenURL, consts.WECOM_CID, consts.WECOM_SECRET), nil) + resp, err := client.Do(req) + if err != nil { + fmt.Println("getAccessToken err=", err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + fmt.Println("getAccessToken statusCode is not 200") + } + respBodyBytes, _ := ioutil.ReadAll(resp.Body) + assesTokenResp := &model.AssesTokenResp{} + if err := jsoniter.Unmarshal(respBodyBytes, assesTokenResp); err != nil { + fmt.Println("getAccessToken json Unmarshal failed, err=", err) + return "", err + } + if assesTokenResp.Errcode != 0 { + fmt.Println("getAccessToken assesTokenResp.Errcode != 0, err=", assesTokenResp.Errmsg) + return "", errors.New(assesTokenResp.Errmsg) + } + return assesTokenResp.AccessToken, nil +} + +func postWechatMsg(accessToken, msg, msgType string) error { + content := &model.WechatMsg{ + ToUser: consts.WECOM_TOUID, + AgentId: consts.WECOM_AID, + MsgType: msgType, + DuplicateCheckInterval: 600, + Text: &model.MsgText{ + Content: msg, + }, + } + b, _ := jsoniter.Marshal(content) + client := http.Client{Timeout: 10 * time.Second} + req, _ := http.NewRequest("POST", fmt.Sprintf(consts.WeComMsgSendURL, accessToken), bytes.NewBuffer(b)) + req.Header.Set("Content-type", "application/json") + resp, err := client.Do(req) + if err != nil { + fmt.Println("[postWechatMsg] failed, err=", err) + return nil + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + fmt.Println("postWechatMsg statusCode is not 200") + return errors.New("statusCode is not 200") + } + respBodyBytes, _ := ioutil.ReadAll(resp.Body) + postResp := &model.PostResp{} + if err := jsoniter.Unmarshal(respBodyBytes, postResp); err != nil { + fmt.Println("postWechatMsg json Unmarshal failed, err=", err) + return err + } + if postResp.Errcode != 0 { + fmt.Println("postWechatMsg postResp.Errcode != 0, err=", postResp.Errmsg) + return errors.New(postResp.Errmsg) + } + return nil +} + +func getQuery(key string, query events.APIGatewayQueryString) string { + value := query[key] + if len(value) > 0 && value[0] != "" { + return value[0] + } + return "" +} diff --git a/go-scf/utils/utils.go b/go-scf/utils/utils.go new file mode 100644 index 0000000..30bac9b --- /dev/null +++ b/go-scf/utils/utils.go @@ -0,0 +1,19 @@ +package utils + +import jsoniter "github.com/json-iterator/go" + +func MarshalToStringParam(param interface{}) string { + s, err := jsoniter.MarshalToString(param) + if err != nil { + return "{}" + } + return s +} + + +func MakeResp(code int, msg string) map[string]interface{} { + return map[string]interface{}{ + "code": code, + "msg": msg, + } +}