package main import ( "context" "encoding/json" "encoding/xml" "errors" "flag" "fmt" "io/ioutil" stdlog "log" "math/rand" "net/http" "os" "os/signal" "runtime" "syscall" "time" "xiaoniaokuaiyan.com/xiaoniao/pay/ali" "gopkg.in/guregu/null.v3" "github.com/go-kit/kit/log" "github.com/go-zoo/bone" "github.com/smartwalle/alipay/v3" "xiaoniaokuaiyan.com/xiaoniao/config" dal "xiaoniaokuaiyan.com/xiaoniao/dal" "xiaoniaokuaiyan.com/xiaoniao/pay/wx" "xiaoniaokuaiyan.com/xiaoniao/retry" "xiaoniaokuaiyan.com/xiaoniao/search" "xiaoniaokuaiyan.com/xiaoniao/server" service "xiaoniaokuaiyan.com/xiaoniao/service" "xiaoniaokuaiyan.com/xiaoniao/util" ) func checkRuntimeErr(err error) bool { if err != nil { stdlog.Fatalf("error: %v", err) return true } return false } func wxScanPaycbHandler(w http.ResponseWriter, req *http.Request) { if req.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } xmlDec := xml.NewDecoder(req.Body) defer req.Body.Close() payResult := &wx.UnionPayResult{} err := xmlDec.Decode(payResult) stdlog.Println("wxpaycb:", payResult) if err != nil { stdlog.Println("wxpaycb_err:", err) w.Write([]byte(err.Error())) return } db := util.GetWriteSqlDB() tcwp := struct { ThirdPNO null.String `db:"third_pay_no"` Source null.String `db:"usefor"` Remark null.String `db:"remark"` }{} db.Get(&tcwp, "select usefor,third_pay_no,remark from t_custom_wxscan_pay where id = ?", payResult.OutTradeNo) if tcwp.ThirdPNO.Valid { writeWxPayCbOk(w) return } //thirdPNO := null.String{} //db.Get(&thirdPNO, "select third_pay_no from t_custom_wxscan_pay where id = ?", payResult.OutTradeNo) //if thirdPNO.Valid { // writeWxPayCbOk(w) // return //} kv, _ := util.StructToMap(payResult) delete(kv, "sign") jssdk := wx.NewJsSdk() csign := jssdk.ComputePaySignature(kv, config.IniConf.Section("weixin").Key("wx.apikey").Value()) if csign != payResult.Sign { stdlog.Println("wxpaycb_err: wrong sign") _, err = util.SendMail(util.MailList{ {"liuguiqi", "liugq@xniao.com.cn"}, {"guoxiaozhou", "43572650@qq.com"}, {"houyoufang", "houyf@xniao.com.cn"}, }, "您的商户订单号为:"+payResult.OutTradeNo+"由于签名校验错误导致订单信息", "微信支付回调错误消息提醒") if err != nil { stdlog.Println("SEND_MAIL_ERROR:", err) } w.Write([]byte("wrong sign")) return } if payResult.ReturnCode == "SUCCESS" && payResult.ResultCode == "SUCCESS" { payTime, _ := time.Parse("20060102150405", payResult.TimeEnd) actualPay := payResult.TotalFee _, err = db.Exec("update t_custom_wxscan_pay set third_pay_no = ?, actual_payment = ?, payment_time = ? where id = ?", payResult.TransactionId, actualPay, payTime.Format("2006-01-02 15:04:05"), payResult.OutTradeNo) if err != nil { stdlog.Println("UPDATE_SCANPAY_STATUS:", err) } else { client := util.GetRedis() msg := map[string]interface{}{ "user": "system", "channel": "SCANPAY-INFORM", "data": map[string]interface{}{ "id": payResult.OutTradeNo, "total_fee": payResult.TotalFee, }, } buf, _ := json.Marshal(msg) client.Publish("xn-message", string(buf)) } } writeWxPayCbOk(w) if tcwp.Source.ValueOrZero() == "jsl" && tcwp.Remark.ValueOrZero() != "" { go orderSrv.JinShuiLianServer(tcwp.Remark.ValueOrZero()) } } func writeWxPayCbOk(w http.ResponseWriter) { okXml := ` ` w.Write([]byte(okXml)) } func wxPaycbHandler(w http.ResponseWriter, req *http.Request) { if req.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } //xmlDec := xml.NewDecoder(req.Body) buf, _ := ioutil.ReadAll(req.Body) defer req.Body.Close() payResult := &wx.UnionPayResult{} err := xml.Unmarshal(buf, payResult) //err := xmlDec.Decode(payResult) stdlog.Println("wxpaycb:", payResult) if err != nil { stdlog.Println("wxpaycb_err:", err) w.Write([]byte(err.Error())) return } db := util.GetWriteSqlDB() thirdPNO := null.String{} db.Get(&thirdPNO, "select third_pay_no from t_order where pay_no = ?", payResult.OutTradeNo) if thirdPNO.Valid { writeWxPayCbOk(w) return } kv, _ := util.StructToMap(payResult) delete(kv, "sign") jssdk := wx.NewJsSdk() csign := jssdk.ComputePaySignature(kv, config.IniConf.Section("weixin").Key("wx.apikey").Value()) if csign != payResult.Sign { fmt.Println(string(buf)) stdlog.Println("wxpaycb_err: wrong sign", csign) go func() { retry.Run(&retry.Policy{Attempts: 3, Sleep: time.Second, Factor: 2}, func() error { rt, _ := orderSrv.WxPayQuery(map[string]string{"out_trade_no": payResult.OutTradeNo}) if rt != nil && rt["status"] == "SUCCESS" { return retry.Stop(errors.New("success")) } return errors.New("OUT_TIMES") }) }() _, err = util.SendMail(util.MailList{ {"liuguiqi", "liugq@xniao.com.cn"}, {"guoxiaozhou", "43572650@qq.com"}, {"houyoufang", "houyf@xniao.com.cn"}, }, "您的商户订单号为:"+payResult.OutTradeNo+"由于签名校验错误导致订单信息", "微信支付回调错误消息提醒") if err != nil { stdlog.Println("SEND_MAIL_ERROR:", err) } w.Write([]byte("wrong sign")) return } if payResult.ReturnCode == "SUCCESS" && payResult.ResultCode == "SUCCESS" { orderSrv.WxPayCB(kv) /*db := util.GetWriteSqlDB() payTime, _ := time.Parse("20060102150405", payResult.TimeEnd) actualPay := payResult.TotalFee _, err = db.Exec("update t_order set status = ?, third_pay_no = ?, actual_payment = ?, payment_time = ?, pay_type = ? where pay_no = ?", 2, payResult.TransactionId, actualPay, payTime.Format("2006-01-02 15:04:05"), constants.PAYMENTTYPE_WEIXIN, payResult.OutTradeNo) if err != nil { stdlog.Println("UPDATE_PAY_STATUS:", err) } else { go func() { strSql := "select id, mobile, custom_mobile from t_order where pay_no = ?" var orderItem = &entity.OrderDB{} err = db.Get(orderItem, strSql, payResult.OutTradeNo) if err == nil { sms := &service.SMSService{dal.DefaultSMSCodeDal} sms.SendSMS(orderItem.Mobile, int(constants.SMS_ORDER_PAID_INFORM), map[string]string{"orderId": orderItem.Id}) } //inform admin client := util.GetRedis() client.Select(12) msg := map[string]interface{}{ "user": "system", "orderid": orderItem.Id, "status": constants.ORDERSTATUS_UNRECEIVE, } buf, _ := json.Marshal(msg) client.Publish("order-status-change", string(buf)) client.HDel("order_unpay", orderItem.Id) }() var wxType = "" if payResult.AppId == config.IniConf.Section("weixin").Key("wx.mp.appid").Value() { wxType = "mp" } _, err = orderSrv.SendWxPaySuccessMsg(map[string]string{ "pay_no": payResult.OutTradeNo, "openid": payResult.OpenId, "money": fmt.Sprintf("%.2f元", float32(payResult.TotalFee)/100), "wx_type": wxType, }) if err != nil { stdlog.Println(err) } }*/ } writeWxPayCbOk(w) } func aliPayHandler(w http.ResponseWriter, req *http.Request) { if req.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) return } payResult, err := ali.GetAliClient().GetTradeNotification(req) if err != nil { fmt.Fprint(w, err.Error()) return } defer fmt.Fprint(w, "success") db := util.GetWriteSqlDB() thirdPNO := null.String{} db.Get(&thirdPNO, "select third_pay_no from t_order where pay_no = ?", payResult.OutTradeNo) if thirdPNO.Valid { return } if payResult.TradeStatus == alipay.TradeStatusSuccess { //成功 kv := map[string]string{ "gmt_payment": payResult.GmtPayment, "total_amount": payResult.TotalAmount, "out_trade_no": payResult.OutTradeNo, "trade_no": payResult.TradeNo, } orderSrv.AliPayCB(kv) } else { //去主动查询 } } var orderSrv *service.OrderService var Version string func main() { runtime.GOMAXPROCS(runtime.NumCPU() * 2) fs := flag.NewFlagSet("", flag.ExitOnError) var ( httpAddr = fs.String("http.addr", ":8000", "Address for HTTP (JSON) server") //grpcAddr = fs.String("grpc.addr", ":8001", "Address for grpc server") configFile = fs.String("f", "config.ini", "app config file") version = fs.Bool("version", false, "print app version") ) fs.Parse(os.Args[1:]) if *version { fmt.Println(Version) return } config.Reload(*configFile) port := ":" + config.IniConf.Section("server").Key("Listen").String() if port != ":" { httpAddr = &port } var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "ts", log.DefaultTimestamp) logger = log.With(logger, "caller", log.DefaultCaller) stdlog.SetFlags(0) // flags are handled by Go kit's logger stdlog.SetOutput(log.NewStdlibAdapter(logger)) // redirect anything using stdlib log to us } // Business domain //var svc interface{} //{ userSvc := &service.UserService{ IUser: dal.DefaultUserDal, } smsSvc := &service.SMSService{ ISMSCode: dal.DefaultSMSCodeDal, } authSvc := &service.AuthService{} fileSvc := &service.FileService{} searchSrv := &service.SearchService{} cartSrv := &service.CartService{ ICart: dal.DefaultCartDal, } couponSrv := &service.CouponService{ ICoupon: dal.DefaultCouponDal, } ptSrv := &service.ProductivityService{} wxSrv := &service.WeixinService{ Weixin: wx.NewWeixin(config.IniConf.Section("weixin").Key("wx.appid").Value(), config.IniConf.Section("weixin").Key("wx.secret").Value()), WeixinMp: wx.NewWeixin(config.IniConf.Section("weixin").Key("wx.mp.appid").Value(), config.IniConf.Section("weixin").Key("wx.mp.secret").Value()), JsSdk: wx.NewJsSdk(), } orderSrv = &service.OrderService{ IOrder: dal.DefaultOrderDal, WeixinService: wxSrv, } citySrv := &service.CityService{ ICity: dal.DefaultCityDal, } ulSrv := &service.UserLinkerService{ IUserLinker: dal.DefaultUserLinkerDal, } productSrv := &service.ProductService{ IProduct: dal.DefaultProductDal, } duSrv := &service.DeliverUserService{ IDeliverUserDal: dal.DefaultDeliverUserDal, WeixinService: wxSrv, } sysSrv := &service.SystemService{} actSrv := &service.ActivityService{ WeixinService: wxSrv, } gbSrv := &service.GroupBloodService{ WeixinService: wxSrv, } paySrv := &service.PayService{} jdlSrv := &service.JDLService{} svc := loggingMiddleware{ UserService: userSvc, AuthService: authSvc, SearchService: searchSrv, FileService: fileSvc, OrderService: orderSrv, SMSService: smsSvc, CartService: cartSrv, CouponService: couponSrv, ProductivityService: ptSrv, WeixinService: wxSrv, CityService: citySrv, UserLinkerService: ulSrv, ProductService: productSrv, DeliverUserService: duSrv, SystemService: sysSrv, ActivityService: actSrv, GroupBloodService: gbSrv, PayService: paySrv, JDLService: jdlSrv, Logger: logger, } //svc := loggingMiddleware{userSvc, authSvc, searchSrv, fileSvc, orderSrv, smsSvc, cartSrv, couponSrv, ptSrv, wxSrv, citySrv, ulSrv, productSrv, duSrv, sysSrv, thirdSrv, actSrv, gbSrv, paySrv, jdlSrv, logger} //} // Mechanical stuff rand.Seed(time.Now().UnixNano()) errc := make(chan error) var mServer *http.Server go func() { errc <- interrupt() mServer.Shutdown(context.Background()) }() // Transport: gRPC /*go func() { transportLogger := log.NewContext(logger).With("transport", "gRPC") ln, err := net.Listen("tcp", *grpcAddr) if err != nil { errc <- err return } s := grpc.NewServer() // uses its own, internal context pb.RegisterUserServiceServer(s, grpcBinding{svc}) transportLogger.Log("addr", *grpcAddr) errc <- s.Serve(ln) }()*/ // Transport: HTTP/JSON //root := context.Background() go func() { var ( transportLogger = log.With(logger, "transport", "HTTP/JSON") mux = bone.New() ) mux.HandleFunc("/wx/paycb", wxPaycbHandler) mux.HandleFunc("/wx/scanpaycb", wxScanPaycbHandler) //mux.HandleFunc("/wx/paycb", wxPaycbHandlerV2) //mux.HandleFunc("/wx/scanpaycb", wxScanPaycbHandlerV2) mux.HandleFunc("/zfb/paycb", aliPayHandler) mux.GetFunc("/version", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "current app version is %s", Version) }) RegistService(svc, mux) transportLogger.Log("addr", *httpAddr) mServer = &http.Server{Addr: *httpAddr, Handler: mux} //errc <- http.ListenAndServe(*httpAddr, mux) errc <- mServer.ListenAndServe() }() go search.UpdateIndex() go util.TimingTask() go func() { ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGUSR2) //syscall.SIGHUP for { <-ch config.Reload("") } }() logger.Log("fatal", <-errc) } func interrupt() error { c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGKILL) return fmt.Errorf("%s", <-c) } func RegistService(svc server.Service, mux *bone.Mux) { handlers := svc.GetMeta() for uri, handler := range handlers { mux.Handle(uri, handler) } }