package wechat import ( "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 jq *myth.JSONQuery if jq, err = getJSON(uri); err == nil { wc.LastTokenTime = now var accessToken string accessToken, err = jq.String(`access_token`) wc.AccessToken = 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) (jq *myth.JSONQuery, 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() jq, err = getJSON(uri) return } // GetUserInfo user info func (wc Client) GetUserInfo(openid string) (info 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 msg myth.HTTPMessage msg, err = getBody(uri) if err == nil { err = msg.JSON(&info) } return } // GetUserList user list func (wc Client) GetUserList(nextOpenID string) (list 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 msg myth.HTTPMessage msg, err = getBody(uri) if err == nil { err = msg.JSON(&list) } return } // GetMaterial 永久资料 func (wc Client) GetMaterial(mtype string, offset, count int) (material 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 msg myth.HTTPMessage msg, err = postJSON(uri, data) if err == nil { err = msg.JSON(&material) } return } func (wc *Client) getTicket(now int64) (ticket string, err error) { var jq *myth.JSONQuery 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 jq, err = getJSON(uri); err == nil { ticket, err = jq.String(`ticket`) wc.LastTicketTime = now wc.Ticket = ticket key := key(wc.AppID) cache.Store(key, wc) } 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 } s = `jsapi_ticket=` + wc.Ticket s += `&noncestr=` + nonceStr s += `×tamp=` + fmt.Sprintf("%d", unix) s += `&url=` + uri 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) (jq *myth.JSONQuery, 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() var msg myth.HTTPMessage msg, err = postJSON(uri, template) if err == nil { jq, err = msg.JSONQuery() } return }