| @@ -21,4 +21,127 @@ X-Forwarded-Server: wechat.hitxy.org.au | |||
| <Event><![CDATA[unsubscribe]]></Event> | |||
| <EventKey><![CDATA[]]></EventKey> | |||
| <Encrypt><![CDATA[brFRc2b7iWU+sxTJfQ1Alp+GcR69Wkeh6Bb88z6XP/q8feWBbvo1odwZ97WrPV5UE2ctrzY88F0J5gt1ECX6OgcKMtZQiZgucXwsh53N9jyDRV+j6zJ1kpJiAf0UxUV7B0Q6OEX830Exoaylj9ZwoR1iQL84eB8CSVmUHRGNxqMK5hg6frE65guh9WysbIs2MWvHVXo7FsXj7ipK9s2VNqawR0VctKPxSnjAPjIxu2Q9MQXnhegePbuLnjTfW2YyY0cKx4XU+tvKlnQbwGgw4rxmcOjuF5lkknxK6JefeHtnKXTiXgcRmEtcbVneWxfW5FsUQkIDQa62IuTs/m4THZDc4opvLmOFXgUR9+BBnIVXyUNvt8zm9DDUUTd+rGz0SDx6sQ3S6WxITp7HKAR6wEHf+eSEwquzmSrGfgAR9Vs=]]></Encrypt> | |||
| </xml> | |||
| </xml> | |||
| Receive : text | |||
| POST /api?signature=3335bc3514757c602e6b1630cd84812caacb43d5×tamp=1492791675&nonce=515316134&openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=c73e7c78c10c0b87846a422cce275ec0d2894ef9 HTTP/1.1 | |||
| Host: wechat.hitxy.org.au | |||
| Accept: */* | |||
| Cache-Control: no-cache | |||
| Connection: Keep-Alive | |||
| Content-Length: 765 | |||
| Content-Type: text/xml | |||
| Pragma: no-cache | |||
| User-Agent: Mozilla/4.0 | |||
| X-Forwarded-For: 103.7.30.105 | |||
| X-Forwarded-Host: wechat.hitxy.org.au | |||
| X-Forwarded-Server: wechat.hitxy.org.au | |||
| <xml> | |||
| <ToUserName><![CDATA[gh_f09231355c68]]></ToUserName> | |||
| <FromUserName><![CDATA[oUN420bxqFqlx0ZQHciUOesZO3PE]]></FromUserName> | |||
| <CreateTime>1492791675</CreateTime> | |||
| <MsgType><![CDATA[text]]></MsgType> | |||
| <Content><![CDATA[13]]></Content> | |||
| <MsgId>6411491424278595449</MsgId> | |||
| <Encrypt><![CDATA[02dtsmvIHONkhxYtyPivtKCkKSQ/ly8UDxxlJPecQFNZGeBMYyMtBq0ufgXJkF5AJYEa5SwSXHeJe7mSsrq5GbNbbUVzLiRERhYK7iVaQuacF/WPY1qOwbTAOHFsZfsUD1oNf64GdKh5Evx5mzXfynmonFinCDUTloWX5M8EW323XNtHcGi2eF11+KMOL9HBdQdG4kSoM/OxaSeXls+D+Co08ZNt9pMDlUvlpHzeYVhudiamxja0+FWSLDlitYENHWNN+LnXyqqfAnAb82dhzKRRSw1c+d/TGFVOYgU1NWt9fZ036qY6/JIwyFNwbFkDdYa0QAzkPJU36zxYesnGUWmu5xHjnrFpfmwG+eZSUuWbNcnu81VbrYhkaD0/4vJwk/EvFySA0Fa/r+B3Lav/d762KhZ2D+at6BD1oWRHFYA=]]></Encrypt> | |||
| </xml> | |||
| Create menu | |||
| { | |||
| "button":[ | |||
| { | |||
| "type":"click", | |||
| "name":"今日歌曲", | |||
| "key":"V1001_TODAY_MUSIC" | |||
| }, | |||
| { | |||
| "name":"菜单", | |||
| "sub_button":[ | |||
| { | |||
| "type":"view", | |||
| "name":"搜索", | |||
| "url":"http://www.soso.com/" | |||
| }, | |||
| { | |||
| "type":"miniprogram", | |||
| "name":"wxa", | |||
| "url":"http://mp.weixin.qq.com", | |||
| "appid":"wx286b93c14bbf93aa", | |||
| "pagepath":"pages/lunar/index.html" | |||
| }, | |||
| { | |||
| "type":"click", | |||
| "name":"赞一下我们", | |||
| "key":"V1001_GOOD" | |||
| }] | |||
| }] | |||
| } | |||
| { | |||
| "button": [ | |||
| { | |||
| "name": "扫码", | |||
| "sub_button": [ | |||
| { | |||
| "type": "scancode_waitmsg", | |||
| "name": "扫码带提示", | |||
| "key": "rselfmenu_0_0", | |||
| "sub_button": [ ] | |||
| }, | |||
| { | |||
| "type": "scancode_push", | |||
| "name": "扫码推事件", | |||
| "key": "rselfmenu_0_1", | |||
| "sub_button": [ ] | |||
| } | |||
| ] | |||
| }, | |||
| { | |||
| "name": "发图", | |||
| "sub_button": [ | |||
| { | |||
| "type": "pic_sysphoto", | |||
| "name": "系统拍照发图", | |||
| "key": "rselfmenu_1_0", | |||
| "sub_button": [ ] | |||
| }, | |||
| { | |||
| "type": "pic_photo_or_album", | |||
| "name": "拍照或者相册发图", | |||
| "key": "rselfmenu_1_1", | |||
| "sub_button": [ ] | |||
| }, | |||
| { | |||
| "type": "pic_weixin", | |||
| "name": "微信相册发图", | |||
| "key": "rselfmenu_1_2", | |||
| "sub_button": [ ] | |||
| } | |||
| ] | |||
| }, | |||
| { | |||
| "name": "发送位置", | |||
| "type": "location_select", | |||
| "key": "rselfmenu_2_0" | |||
| }, | |||
| { | |||
| "type": "media_id", | |||
| "name": "图片", | |||
| "media_id": "MEDIA_ID1" | |||
| }, | |||
| { | |||
| "type": "view_limited", | |||
| "name": "图文消息", | |||
| "media_id": "MEDIA_ID2" | |||
| } | |||
| ] | |||
| } | |||
| @@ -21,10 +21,19 @@ type authToken struct { | |||
| Time time.Time `json:"created_at"` | |||
| } | |||
| func main2() { | |||
| e, _ := renewAuthtoken() | |||
| t, _ := readTokenFromFile("/tmp/wechat_hitxy_token") | |||
| fmt.Println(isAuthTokenExpired(t), e) | |||
| //GetAccessToken returns a valid access_token for wechat_api | |||
| // the token is auomatically renewed if it's about to expire | |||
| // if error happens, return empty string and error | |||
| // if success, return token string and nil | |||
| func GetAccessToken() (string, error) { | |||
| t, err := readTokenFromFile("/tmp/wechat_hitxy_token") | |||
| if isAuthTokenExpired(t) { | |||
| t, err = renewAuthtoken() | |||
| if err != nil { | |||
| return "", err // cannot get token | |||
| } | |||
| } | |||
| return t.AccessToken, nil | |||
| } | |||
| func isAuthTokenExpired(t authToken) bool { | |||
| @@ -34,11 +43,13 @@ func isAuthTokenExpired(t authToken) bool { | |||
| return time.Now().After(expire) | |||
| } | |||
| //save token to perminant storage | |||
| func writeTokenToFile(body []byte, path string) { | |||
| log.Printf("writing authtoke to %s\r\n", path) | |||
| ioutil.WriteFile(path, body, 0600) | |||
| } | |||
| //read token from permenant storage | |||
| func readTokenFromFile(path string) (authToken, error) { | |||
| var m authToken | |||
| log.Printf("read authtoke from %s\r\n", path) | |||
| @@ -47,6 +58,7 @@ func readTokenFromFile(path string) (authToken, error) { | |||
| return m, err | |||
| } | |||
| //issue web request to get token from wechat | |||
| func renewAuthtoken() (authToken, error) { | |||
| //url := "http://vimeo.com/api/v2/brad/info.json" | |||
| url := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx876e233fde456b7b&secret=4a91aa328569b10a9fb97adeb8b0af58" | |||
| @@ -8,17 +8,15 @@ import ( | |||
| "net/url" | |||
| ) | |||
| func handler(w http.ResponseWriter, r *http.Request) { | |||
| fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) | |||
| rq := r.URL.RawQuery | |||
| m, _ := url.ParseQuery(rq) | |||
| for index, element := range m { | |||
| fmt.Fprintf(w, "<br>%s => %s", index, element) | |||
| } | |||
| fmt.Fprintf(w, m["k"][0]) | |||
| logRequestDebug(httputil.DumpRequest(r, true)) | |||
| func main() { | |||
| http.HandleFunc("/", webrootHandler) | |||
| http.HandleFunc("/api", apiV1Main) | |||
| //http.ListenAndServe("127.0.0.1:65500", nil) | |||
| http.ListenAndServe(":65500", nil) | |||
| } | |||
| //apiV1Main version 1 main entry for all wechat callbacks | |||
| // | |||
| func apiV1Main(w http.ResponseWriter, r *http.Request) { | |||
| logRequestDebug(httputil.DumpRequest(r, true)) | |||
| rq := r.URL.RawQuery | |||
| @@ -26,11 +24,18 @@ func apiV1Main(w http.ResponseWriter, r *http.Request) { | |||
| fmt.Fprintf(w, m["echostr"][0]) | |||
| } | |||
| func main() { | |||
| http.HandleFunc("/", handler) | |||
| http.HandleFunc("/api", apiV1Main) | |||
| //http.ListenAndServe("127.0.0.1:65500", nil) | |||
| http.ListenAndServe(":65500", nil) | |||
| //webrootHandler sending contents to client when request "/" | |||
| // essentially to prove the webserver is still alive | |||
| // echo query string to the client | |||
| func webrootHandler(w http.ResponseWriter, r *http.Request) { | |||
| fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) | |||
| rq := r.URL.RawQuery | |||
| m, _ := url.ParseQuery(rq) | |||
| for index, element := range m { | |||
| fmt.Fprintf(w, "\r\n%s => %s", index, element) | |||
| } | |||
| logRequestDebug(httputil.DumpRequest(r, true)) | |||
| } | |||
| func logRequestDebug(data []byte, err error) { | |||