package main import ( "fmt" "log" "net/http" "net/http/httputil" "net/url" "strconv" "time" ) //PathsConfig all system available pathes type PathsConfig struct { Angular2App string `json:"angular2_app"` SinglePageEdit string `json:"singlePageEdit"` } //GlobalPath all global pathes configurations // TODO: setup GlobalPath Config, from reading file var GlobalPath = PathsConfig{ "dist/", "/mnt/data/workspace/go/src/wechat_hitxy/spa/", } //KFUsers info cache about current customer service var KFUsers kfCache func main() { err := readConfig() //wechat API config if err != nil { log.Println(err) log.Fatal("unable to read server_config.json, program quit") return } err = readCRMConfig() if err != nil { log.Println(err) log.Fatal("unable to read crm_config.json, program quit") } err = IntraAPIConfig.readConfig() if err != nil { log.Println(err) log.Fatal("unable to read intra-api-config, program quit") } initAllProc() setupRootFileServer() startSessionManager(2048) KFUsers.kfRenewList() //always the last one setupHTTPHandler() } func setupHTTPHandler() { //setup handler //http.HandleFunc("/", webrootHandler) http.HandleFunc("/api", apiV1Main) http.HandleFunc("/upload", uploadHandler) http.HandleFunc("/crmfiles/", crmAttachmentHandler) http.HandleFunc("/dumprequest", dumpReuestHandler) http.HandleFunc("/MP_verify_6JqVkftKr39GMakA.txt", mpDomainAuthSecret) http.HandleFunc("/redirect", setTrackingCookieAndRecirect) http.HandleFunc("/iapi/getAccessToken", supplyAccessToken) http.HandleFunc("/iapi/createWechatQr", iapiCreateWechatQrCode) http.HandleFunc("/crmpixel.png", crmpixel) //tracking pixel. http.HandleFunc("/crmcache", crmcache) http.HandleFunc("/spa/editprofile", spaEditProfile) http.ListenAndServe(":65500", nil) } func startSessionManager(concurrent int) { m := SessionManager{} AllInMessage = make(chan *InWechatMsg, concurrent) go m.startSessionManager(AllInMessage) } func setupRootFileServer() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, GlobalPath.Angular2App+r.URL.Path[1:]) }) fs := http.FileServer(http.Dir(GlobalPath.SinglePageEdit)) http.Handle("/spa/", http.StripPrefix("/spa", fs)) //fs := http.FileServer(http.Dir("/mnt/data/workspace/angular.ts/wechat/ng2-admin/dist")) //http.Handle("/", fs) } func dumpReuestHandler(w http.ResponseWriter, r *http.Request) { logRequestDebug(httputil.DumpRequest(r, true)) w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Access-Control-Allow-Origin", "http://192.168.1.39:4200") w.Header().Set("Access-Control-Allow-Headers", "Authorziation11,Authorziation12") w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Expose-Headers", "Set-Cookie,myheader,*") w.Header().Set("myheader", "myheader-data") expiration := time.Now().Add(10 * 365 * 24 * time.Hour) str := time.Now().String() cookie := http.Cookie{Name: "username", Value: str, Expires: expiration} http.SetCookie(w, &cookie) fmt.Fprintf(w, `{"status":"OK"}`) for _, c := range r.Cookies() { log.Println(c.Name) log.Println(c.Value) } } func supplyAccessToken(w http.ResponseWriter, r *http.Request) { //logRequestDebug(httputil.DumpRequest(r, true)) if checkSignatureByToken(r, IntraAPIConfig.CRMSecrete) { atk, _ := GetAccessToken() fmt.Fprint(w, atk) } else { w.WriteHeader(401) fmt.Fprint(w, "unauthorized") } } func iapiCreateWechatQrCode(w http.ResponseWriter, r *http.Request) { logRequestDebug(httputil.DumpRequest(r, true)) if !checkSignatureByToken(r, IntraAPIConfig.CRMSecrete) { w.WriteHeader(http.StatusUnauthorized) fmt.Fprint(w, "unauthorized") return } rq := r.URL.RawQuery m, _ := url.ParseQuery(rq) qrValue, qok := m["qrValue"] expire, eok := m["expire"] if !qok || !eok { w.WriteHeader(http.StatusUnprocessableEntity) fmt.Fprintf(w, "parameter not correct, bad api call %s", time.Now().Format(getCrmTimeLayout())) return } if isStrInt(qrValue[0]) && isStrInt(expire[0]) { intVal, _ := strconv.Atoi(qrValue[0]) intExpire, _ := strconv.Atoi(expire[0]) jsonB, err := iapiCreateTempQr(int32(intVal), int32(intExpire)) if err == nil { w.Write(jsonB) } else { fmt.Fprintf(w, "%s", err) } return } if !isStrInt(qrValue[0]) && expire[0] == "0" { jsonB, err := isapiCreatePermQr(qrValue[0]) if err == nil { w.Write(jsonB) } else { fmt.Fprintf(w, "%s", err) } return } } func isStrInt(v string) bool { if _, err := strconv.Atoi(v); err == nil { return true } return false } // 用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠。 // 注意事项: // 1、回调页面域名或路径需使用字母、数字及“-”的组合(例:wx.qq.com或wx.qq.com/mp),不支持IP地址、端口号及短链域名。填写的域名或路径需与实际回调URL中的域名或路径相同。 // 2、填写的域名须通过ICP备案的验证。 // 3、将文件MP_verify_6JqVkftKr39GMakA.txt(点击下载)上传至填写域名或路径指向的web服务器(或虚拟主机)的目录(若填写域名,将文件放置在域名根目录下,例如wx.qq.com/MP_verify_6JqVkftKr39GMakA.txt;若填写路径,将文件放置在路径目录下,例如wx.qq.com/mp/MP_verify_6JqVkftKr39GMakA.txt),并确保可以访问。 func mpDomainAuthSecret(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "6JqVkftKr39GMakA") //由于需要什么ICP备案,这个功能不能使用 }