|
@@ -0,0 +1,247 @@
|
|
|
+package wechat
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "net/url"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "git.chuangxin1.com/cx/myth"
|
|
|
+)
|
|
|
+
|
|
|
+func key(appid string) string {
|
|
|
+ return "wechat:client:" + appid
|
|
|
+}
|
|
|
+
|
|
|
+// NewClient new client
|
|
|
+func NewClient(appID, appSecret, token, encodingAESKey string) *Client {
|
|
|
+ key := key(appID)
|
|
|
+ if v, ok := cache.Load(key); ok {
|
|
|
+ return v.(*Client)
|
|
|
+ }
|
|
|
+ c := &Client{AppID: appID, AppSecret: appSecret, Token: token, EncodingAESKey: encodingAESKey}
|
|
|
+ cache.Store(key, c)
|
|
|
+ return c
|
|
|
+}
|
|
|
+
|
|
|
+// getToken get token
|
|
|
+func (wc *Client) getToken() (token string, err error) {
|
|
|
+ now := time.Now().Unix()
|
|
|
+ if wc.LastTokenTime > 0 {
|
|
|
+ if now-wc.LastTokenTime < TokenExpires {
|
|
|
+ token = wc.AccessToken
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ uri := BaseURL + "/cgi-bin/token?"
|
|
|
+
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("grant_type", "client_credential")
|
|
|
+ args.Add("appid", wc.AppID)
|
|
|
+ args.Add("secret", wc.AppSecret)
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ var res Response
|
|
|
+ if res, err = getJSON(uri); err == nil {
|
|
|
+ wc.LastTokenTime = now
|
|
|
+ wc.AccessToken = res.AccessToken
|
|
|
+ token = wc.AccessToken
|
|
|
+ key := key(wc.AppID)
|
|
|
+ cache.Store(key, wc)
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetCodeURL get code 授权获取 OpenID URL
|
|
|
+// /connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
|
|
|
+// 转向到
|
|
|
+// redirect_uri/?code=CODE&state=STATE
|
|
|
+func (wc Client) GetCodeURL(redirectURL, state string) (uri string) {
|
|
|
+ uri = OpenURL + "/connect/oauth2/authorize?"
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("appid", wc.AppID)
|
|
|
+ args.Add("redirect_uri", redirectURL)
|
|
|
+ args.Add("response_type", "code")
|
|
|
+ args.Add("scope", "snsapi_base")
|
|
|
+ args.Add("state", state)
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ uri += "#wechat_redirect"
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetOpenID 获取 OpenID
|
|
|
+// /sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
|
|
|
+func (wc Client) GetOpenID(code string) (res Response, err error) {
|
|
|
+ uri := BaseURL + "/sns/oauth2/access_token?"
|
|
|
+
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+ args.Add("appid", wc.AppID)
|
|
|
+ args.Add("secret", wc.AppSecret)
|
|
|
+ args.Add("code", code)
|
|
|
+ args.Add("grant_type", "authorization_code")
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ res, err = getJSON(uri)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetUserInfo user info
|
|
|
+func (wc Client) GetUserInfo(openid string) (res UserInfo, err error) {
|
|
|
+ uri := BaseURL + "/cgi-bin/user/info?"
|
|
|
+
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+ args.Add("openid", openid)
|
|
|
+ args.Add("lang", "zh_CN")
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ var body []byte
|
|
|
+ body, err = getBody(uri)
|
|
|
+ if err == nil {
|
|
|
+ err = json.Unmarshal(body, &res)
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetUserList user list
|
|
|
+func (wc Client) GetUserList(nextOpenID string) (res UserList, err error) {
|
|
|
+ uri := BaseURL + "/cgi-bin/user/get?"
|
|
|
+
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+ args.Add("next_openid", nextOpenID)
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ var body []byte
|
|
|
+ body, err = getBody(uri)
|
|
|
+ if err == nil {
|
|
|
+ err = json.Unmarshal(body, &res)
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetMaterial 永久资料
|
|
|
+func (wc Client) GetMaterial(mtype string, offset, count int) (res Material, err error) {
|
|
|
+ uri := BaseURL + "/cgi-bin/material/batchget_material?"
|
|
|
+
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ args := url.Values{}
|
|
|
+ data := make(map[string]interface{})
|
|
|
+
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+
|
|
|
+ data["type"] = mtype
|
|
|
+ data["offset"] = offset
|
|
|
+ data["count"] = count
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ var body []byte
|
|
|
+
|
|
|
+ params, err := json.Marshal(data)
|
|
|
+ body, err = postJSONBody(uri, params)
|
|
|
+ if err == nil {
|
|
|
+ err = json.Unmarshal(body, &res)
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (wc *Client) getTicket(now int64) (ticket string, err error) {
|
|
|
+ var res Response
|
|
|
+ if wc.LastTicketTime > 0 {
|
|
|
+ if now-wc.LastTokenTime < TokenExpires {
|
|
|
+ ticket = wc.Ticket
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+ args.Add("type", "jsapi")
|
|
|
+
|
|
|
+ uri := BaseURL + "/cgi-bin/ticket/getticket?"
|
|
|
+ uri += args.Encode()
|
|
|
+ if res, err = getJSON(uri); err == nil {
|
|
|
+ fmt.Println(res)
|
|
|
+ wc.LastTicketTime = now
|
|
|
+ wc.Ticket = res.Ticket
|
|
|
+
|
|
|
+ key := key(wc.AppID)
|
|
|
+ cache.Store(key, wc)
|
|
|
+
|
|
|
+ ticket = res.Ticket
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// GetSignPackage JS 签名
|
|
|
+// uri 当前 URL
|
|
|
+// nonceStr 随机字符串
|
|
|
+func (wc Client) GetSignPackage(uri, nonceStr string) (sign SignPackage, err error) {
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var (
|
|
|
+ s string
|
|
|
+ unix int64
|
|
|
+ )
|
|
|
+ unix = time.Now().Unix()
|
|
|
+ if wc.Ticket, err = wc.getTicket(unix); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //fmt.Println(wc.Ticket)
|
|
|
+ s = `jsapi_ticket=` + wc.Ticket
|
|
|
+ s += `&noncestr=` + nonceStr
|
|
|
+ s += `×tamp=` + fmt.Sprintf("%d", unix)
|
|
|
+ s += `&url=` + uri
|
|
|
+
|
|
|
+ //fmt.Println(s)
|
|
|
+ sign.AppID = wc.AppID
|
|
|
+ sign.NonceStr = nonceStr
|
|
|
+ sign.Signature = myth.SHA1(s)
|
|
|
+ sign.Timestamp = unix
|
|
|
+ sign.URL = uri
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// SendTemplateMessage send template message
|
|
|
+// POST /cgi-bin/message/template/send?access_token=ACCESS_TOKEN
|
|
|
+func (wc Client) SendTemplateMessage(template TemplateMessage) (res Response, err error) {
|
|
|
+ uri := BaseURL + "/cgi-bin/message/template/send?"
|
|
|
+
|
|
|
+ if wc.AccessToken, err = wc.getToken(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ args := url.Values{}
|
|
|
+ args.Add("access_token", wc.AccessToken)
|
|
|
+
|
|
|
+ uri += args.Encode()
|
|
|
+ data, err := json.Marshal(template)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ res, err = postJSON(uri, data)
|
|
|
+ return
|
|
|
+}
|