package wechat import ( "encoding/hex" "encoding/json" "fmt" "net/url" "time" "git.chuangxin1.com/myth/sacred/cache" "git.chuangxin1.com/myth/sacred/hash" ) // NewClient new client func NewClient(appID, appSecret, token, encodingAESKey string) *Client { key := keyC(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 } // TokenFromCache token from cache func (wc *Client) TokenFromCache(ok bool) { wc.UseCacheToken = ok } // getToken get token func (wc *Client) getToken() (token string, err error) { key := keyToken(wc.AppID) if wc.UseCacheToken { var ct ClientToken s := `` s, err = cache.RedisGet(key) if err != nil { return } err = json.Unmarshal([]byte(s), &ct) if err != nil { return } token = ct.AccessToken return } now := time.Now().Unix() if wc.LastTokenTime > 0 { if now-wc.LastTokenTime < TokenExpires { token = wc.AccessToken return } } token, err = wc.RefreshToken(now) return } // RefreshToken refresh token, now current timestamp func (wc *Client) RefreshToken(now int64) (token string, err error) { key := keyToken(wc.AppID) 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 ResponseToken _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() if err != nil { return } wc.LastTokenTime = now wc.AccessToken = res.AccessToken cache.Store(keyC(wc.AppID), wc) ct := ClientToken{AppID: wc.AppID, AccessToken: wc.AccessToken, LastTokenTime: now} bs, _ := json.Marshal(ct) cache.RedisSet(key, string(bs), 0) token = res.AccessToken return } func (wc *Client) getTicket(now int64) (ticket string, err error) { key := keyTicket(wc.AppID) if wc.UseCacheToken { var ct ClientTicket s := `` s, err = cache.RedisGet(key) if err != nil { return } err = json.Unmarshal([]byte(s), &ct) if err != nil { return } ticket = ct.Ticket return } if wc.LastTicketTime > 0 { if now-wc.LastTicketTime < TicketExpires { ticket = wc.Ticket return } } ticket, err = wc.RefreshTicket(now) return } // RefreshTicket refresh tocket, now current timestamp func (wc *Client) RefreshTicket(now int64) (ticket string, err error) { key := keyTicket(wc.AppID) args := url.Values{} args.Add("access_token", wc.AccessToken) args.Add("type", "jsapi") uri := BaseURL + "/cgi-bin/ticket/getticket?" uri += args.Encode() var res ResponseTicket _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() if err != nil { return } wc.LastTicketTime = now wc.Ticket = res.Ticket cache.Store(keyC(wc.AppID), wc) ct := ClientTicket{AppID: wc.AppID, LastTicketTime: now, Ticket: res.Ticket} bs, _ := json.Marshal(ct) cache.RedisSet(key, string(bs), 0) ticket = res.Ticket return } // Info client info func (wc Client) Info() (c *Client, ct ClientToken, ct1 ClientTicket, err error) { key := keyC(wc.AppID) if v, ok := cache.Load(key); ok { c = v.(*Client) } s := `` s, err = cache.RedisGet(keyToken(wc.AppID)) if err != nil { return } err = json.Unmarshal([]byte(s), &ct) if err != nil { return } s, err = cache.RedisGet(keyTicket(wc.AppID)) if err != nil { return } err = json.Unmarshal([]byte(s), &ct1) if err != nil { return } 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() _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() 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() _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() 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() _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() return } // GetMenu 查询自定义菜单 func (wc Client) GetMenu() (res Menu, err error) { uri := BaseURL + "/cgi-bin/get_current_selfmenu_info?" if wc.AccessToken, err = wc.getToken(); err != nil { return } args := url.Values{} args.Add("access_token", wc.AccessToken) uri += args.Encode() _, err = getJSON(uri, &res) if err != nil { return } err = res.Check() return } // CreateMenu 创建自定义菜单 func (wc Client) CreateMenu(menu FormMenu) (err error) { uri := BaseURL + "/cgi-bin/menu/create?" if wc.AccessToken, err = wc.getToken(); err != nil { return } args := url.Values{} args.Add("access_token", wc.AccessToken) uri += args.Encode() var res ResponseMsg _, err = postJSON(&res, uri, menu) if err != nil { return } err = res.Check() 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 hs, _ := hash.SHA1([]byte(s)) sign.AppID = wc.AppID sign.NonceStr = nonceStr sign.Signature = hex.EncodeToString(hs) sign.Timestamp = unix sign.Ticket = wc.Ticket 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 TemplateResponse, 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() _, err = postJSON(&res, uri, template) if err != nil { return } err = res.Check() return }