From 603f72e657b085ec512bbeb69b04a17d3bf2d3ce Mon Sep 17 00:00:00 2001 From: jiangyong27 Date: Sun, 9 Apr 2023 02:11:58 +0800 Subject: [PATCH] sync --- base/httputil/httppost.go | 84 +++++ base/util/util.go | 6 + cmd/film.go | 22 +- conf/server.conf.dev | 2 +- conf/server.conf.prod | 3 +- worker/common/processor.go | 18 + worker/dadi.go | 258 -------------- worker/dadi/processor.go | 332 ++++++++++++++++++ worker/dadi/type.go | 43 +++ worker/haha/haha_processor.go | 58 +++ worker/{orders.go => haha/haha_sync_order.go} | 101 +++--- worker/type.go | 46 --- worker/worker.go | 101 ++++++ 13 files changed, 706 insertions(+), 368 deletions(-) create mode 100644 base/httputil/httppost.go create mode 100644 worker/common/processor.go delete mode 100644 worker/dadi.go create mode 100644 worker/dadi/processor.go create mode 100644 worker/dadi/type.go create mode 100644 worker/haha/haha_processor.go rename worker/{orders.go => haha/haha_sync_order.go} (79%) delete mode 100644 worker/type.go create mode 100644 worker/worker.go diff --git a/base/httputil/httppost.go b/base/httputil/httppost.go new file mode 100644 index 0000000..a7653d0 --- /dev/null +++ b/base/httputil/httppost.go @@ -0,0 +1,84 @@ +package httputil + +import ( + "bytes" + "crypto/tls" + "fmt" + "github.com/spf13/cast" + "io" + "net/http" + "net/url" + "time" +) + +func HttpPostForm(requestUrl string, header map[string]interface{}, forms map[string]interface{}) ([]byte, error) { + client := &http.Client{Timeout: 20 * time.Second} + + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + values := url.Values{} + if forms != nil { + for k, v := range forms { + values.Set(k, cast.ToString(v)) + } + } + + req, err := http.NewRequest("POST", requestUrl, bytes.NewBufferString(values.Encode())) + if err != nil { + return nil, err + } + if header != nil { + for k, v := range header { + req.Header.Set(k, cast.ToString(v)) + } + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) + } + return io.ReadAll(resp.Body) +} + +// PostJson 请求 +func HttpPostJson(link string, params map[string]interface{}, header map[string]interface{}, json []byte) ([]byte, error) { + client := &http.Client{Timeout: 20 * time.Second} + //忽略https的证书 + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + p := url.Values{} + u, _ := url.Parse(link) + if params != nil { + for k, v := range params { + p.Set(k, cast.ToString(v)) + } + } + u.RawQuery = p.Encode() + req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(json)) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", "application/json") + if header != nil { + for k, v := range header { + req.Header.Add(k, cast.ToString(v)) + } + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) + } + return io.ReadAll(resp.Body) +} diff --git a/base/util/util.go b/base/util/util.go index c7d8682..1cf88a2 100644 --- a/base/util/util.go +++ b/base/util/util.go @@ -1 +1,7 @@ package util + +import "fmt" + +func MoneyFen(money int64) string { + return fmt.Sprintf("%.2f", float64(money)/100) +} diff --git a/cmd/film.go b/cmd/film.go index e516832..8c66254 100644 --- a/cmd/film.go +++ b/cmd/film.go @@ -55,24 +55,6 @@ func main() { panic(err) } - dadiProcessor := &worker.Dadi{ - Token: cfg.Film.DadiToken, - } - if err := dadiProcessor.Init(); err != nil { - panic(err) - } - - orderWorker := &worker.Orders{ - Token: config.GetConfig().Film.HahaToken, - Dadi: dadiProcessor, - } - - if err := orderWorker.Init(); err != nil { - panic(err) - } - - order, _ := model.GetOrder(582589) - - dadiProcessor.NewOrder(order) - select {} + work := &worker.Worker{} + work.Run() } diff --git a/conf/server.conf.dev b/conf/server.conf.dev index 8428ddd..27e1351 100644 --- a/conf/server.conf.dev +++ b/conf/server.conf.dev @@ -18,4 +18,4 @@ qiye_agent = "1000013" [film] haha_token = "cc5f1d4c36f7e9544d641a174b298f94" -dadi_token = "321566:b891effb-5493-4f26-ac54-bfa5581ca8c3" \ No newline at end of file +dadi_token = "321566:7b84a0b1-832a-4492-a96a-23002d6c8715" \ No newline at end of file diff --git a/conf/server.conf.prod b/conf/server.conf.prod index 6fcf88b..a115fae 100644 --- a/conf/server.conf.prod +++ b/conf/server.conf.prod @@ -19,4 +19,5 @@ qiye_agent = "1000013" [film] haha_token = "cc5f1d4c36f7e9544d641a174b298f94" -dadi_token = "321566:b891effb-5493-4f26-ac54-bfa5581ca8c3" \ No newline at end of file +dadi_token = "321566:7b84a0b1-832a-4492-a96a-23002d6c8715" + diff --git a/worker/common/processor.go b/worker/common/processor.go new file mode 100644 index 0000000..d1fa7eb --- /dev/null +++ b/worker/common/processor.go @@ -0,0 +1,18 @@ +package common + +import "film/model" + +type CheckInfo struct { + TotalPrice int64 + UnitPrice int64 + BillCode string +} + +type OrderInfo struct { +} + +type Processor interface { + CheckOrder(*model.Order) (*CheckInfo, error) + CreateOrder(*model.Order) (*OrderInfo, error) + CancelOrder(*model.Order, *CheckInfo) error +} diff --git a/worker/dadi.go b/worker/dadi.go deleted file mode 100644 index a6c67be..0000000 --- a/worker/dadi.go +++ /dev/null @@ -1,258 +0,0 @@ -package worker - -import ( - "encoding/json" - "film/base/httputil" - "film/config" - "film/model" - "fmt" - log "github.com/sirupsen/logrus" - "github.com/smbrave/goutil" - "github.com/spf13/cast" - "gitlab.com/jiangyong27/gobase/wxapi" - "strings" - "time" -) - -type Dadi struct { - Token string - citys map[string]*DadiCity - qyClient *wxapi.WxQiye -} - -func (d *Dadi) Init() error { - cityUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cbase/cityAndCinemaList" - - params := d.getBaseParam(&DadiCinema{ - Name: "大地影院(北京十里河铭泽店)", - Id: 118, - UnifiedCode: 11050621, - }) - body, err := httputil.HttpGet(cityUrl, params, d.getBaseHeader()) - if err != nil { - log.Errorf(" httputil.HttpGet url : %s error: %s", cityUrl, err.Error()) - return err - } - result, err := d.checkError(body) - if err != nil { - return err - } - - citys := make(map[string]*DadiCity) - datas := cast.ToSlice(result) - - for _, d := range datas { - data := cast.ToStringMap(d) - - cinemas := make([]*DadiCinema, 0) - for _, c := range cast.ToSlice(data["cinemas"]) { - cin := cast.ToStringMap(c) - cinema := new(DadiCinema) - cinema.Name = cast.ToString(cin["name"]) - cinema.Address = cast.ToString(cin["address"]) - cinema.Latitude = cast.ToString(cin["latitude"]) - cinema.Longitude = cast.ToString(cin["longitude"]) - cinema.CityId = cast.ToInt64(cin["cityId"]) - cinema.UnifiedCode = cast.ToInt64(cin["unifiedCode"]) - cinemas = append(cinemas, cinema) - } - cityInfo := cast.ToStringMap(data["cityInfo"]) - city := new(DadiCity) - city.Name = cast.ToString(cityInfo["chName"]) - city.ShortName = cast.ToString(cityInfo["shortName"]) - city.CityId = cast.ToInt64(data["cityId"]) - city.CityCode = cast.ToInt64(data["cityCode"]) - city.Cinemas = cinemas - - citys[city.ShortName] = city - } - - d.citys = citys - log.Infof("load dadi citys : %d", len(d.citys)) - - cfg := config.GetConfig() - d.qyClient = wxapi.NewQiye(&wxapi.QiyeConfig{ - Corpid: cfg.Weixin.QiyeAppid, - Secret: cfg.Weixin.Qiyesecret, - Sender: cfg.Weixin.QiyeAgent, - }) - return nil -} - -func (d *Dadi) UpdateOrder(order *model.Order) { - -} - -func (d *Dadi) NewOrder(order *model.Order) { - - cinema, err := d.getCinema(order) - if err != nil { - log.Errorf("getcinema order : %s error : %s", goutil.EncodeJSON(order), err.Error()) - return - } - hall, err := d.getCinemaFilm(order, cinema) - if err != nil { - log.Errorf("getCinemaFilm order : %s error : %s", goutil.EncodeJSON(order), err.Error()) - return - } - dadiOrder, err := d.holdSeats(order, cinema, hall) - if err != nil { - log.Errorf("holdSeats order : %s error : %s", goutil.EncodeJSON(order), err.Error()) - return - } - - message := make([]string, 0) - message = append(message, "【哈哈票订单信息】") - message = append(message, fmt.Sprintf("城市:%s", order.CityName)) - message = append(message, fmt.Sprintf("影院:%s", order.CinemaName)) - message = append(message, fmt.Sprintf("影厅:%s", order.Ting)) - message = append(message, fmt.Sprintf("影片:%s", order.MovieName)) - message = append(message, fmt.Sprintf("座位:%s,%s,%s", order.Seats, - goutil.If(order.IsSeat == 3, "可以调座", "不可调座"), - goutil.If(order.LoverSeat == 1, "情侣座", "普通座"))) - message = append(message, fmt.Sprintf("订单编号:%s", order.OrderId)) - message = append(message, fmt.Sprintf("订单金额:%.2f", float64(order.TotalPrice)/100)) - message = append(message, fmt.Sprintf("原价:%.2f", float64(order.MaoyanPrice)/100)) - message = append(message, fmt.Sprintf("报价范围:%.2f~%.2f", float64(order.MinPrice)/100, float64(order.MaxPrice)/100)) - message = append(message, fmt.Sprintf("订单时间:%s", time.Unix(order.PayTime, 0).Format("2006-01-02 15:04"))) - message = append(message, fmt.Sprintf("放映时间:%s", time.Unix(order.ShowTime, 0).Format("2006-01-02 15:04"))) - message = append(message, "\n") - message = append(message, "【大地订单信息】") - message = append(message, fmt.Sprintf("订单编号:%s", dadiOrder.OrderId)) - if err := d.qyClient.SendText([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { - log.Errorf("send message error : %s", err.Error()) - } - -} - -func (d *Dadi) checkError(body []byte) (interface{}, error) { - result := make(map[string]interface{}) - if err := json.Unmarshal(body, &result); err != nil { - log.Errorf("json.unmarshal [%s] error : %s", string(body), err.Error()) - return nil, err - } - if cast.ToInt(result["code"]) != 200 || cast.ToBool(result["success"]) != true { - log.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) - return nil, fmt.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) - } - - return result["data"], nil -} - -func (d *Dadi) getBaseHeader() map[string]interface{} { - return map[string]interface{}{ - "User-Agent": "apifox/1.0.0 (https://www.apifox.cn)", - } -} - -func (d *Dadi) getBaseParam(cinema *DadiCinema) map[string]interface{} { - params := map[string]interface{}{ - "channelCode": "SYH-DDZY-DD", - "channelName": "大地自营-大地", - "channelNo": "SYH-DDZY-DD", - "channelUid": "SYH-DDZY-DD", - "cinema": cast.ToString(cinema.UnifiedCode), - "cinemaCode": cast.ToString(cinema.UnifiedCode), - "cinemaUid": cast.ToString(cinema.Id), - "d": "iPhone14,3", - "i": "00000000-0000-0000-0000-000000000000", - "k": d.Token, - "r": "1", - "s": "iOS15.2.1", - "t": "1", - "tenantId": "321566", - "unifiedCinemaId": cast.ToString(cinema.Id), - "unifiedCinemaName": cinema.Name, - "unifiedCode": cast.ToString(cinema.UnifiedCode), - "v": "8.7.3", - } - return params -} - -func (d *Dadi) getCinema(order *model.Order) (*DadiCinema, error) { - if _, ok := d.citys[order.CityName]; !ok { - log.Errorf("city[%s] not exist dadi cinema", order.CityName) - return nil, fmt.Errorf("city[%s] not exist dadi cinema", order.CityName) - } - city := d.citys[order.CityName] - for _, cinema := range city.Cinemas { - if cinema.Name != order.CinemaName { - continue - } - return cinema, nil - } - return nil, fmt.Errorf("city[%s] not[%s]", order.CityName, order.CinemaName) -} - -func (d *Dadi) getCinemaFilm(order *model.Order, cinema *DadiCinema) (*DadiFilmShowHall, error) { - baseReq := d.getBaseParam(cinema) - reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/film/getHitFilmAndFilmSession" - body, err := httputil.HttpGet(reqUrl, baseReq, d.getBaseHeader()) - if err != nil { - log.Errorf("httpGet[%s] error : %s", reqUrl, err.Error()) - return nil, err - } - - result, err := d.checkError(body) - if err != nil { - return nil, err - } - - orderShowDay := time.Unix(order.ShowTime, 0).Format("2006-01-02") - var hall *DadiFilmShowHall = nil - for _, f := range cast.ToSlice(cast.ToStringMap(result)["filmList"]) { - ff := cast.ToStringMap(f) - filmName := cast.ToString(ff["name"]) - if filmName != order.MovieName { - continue - } - for _, s := range cast.ToSlice(ff["showList"]) { - ss := cast.ToStringMap(s) - showDay := cast.ToString(ss["dayStr"]) - if showDay != orderShowDay { - continue - } - for _, p := range cast.ToSlice(ss["plist"]) { - pp := cast.ToStringMap(p) - hallName := cast.ToString(pp["hallName"]) - if hallName != order.Ting { - continue - } - hall = new(DadiFilmShowHall) - hall.FilmName = filmName - hall.ShowDay = showDay - hall.HallName = cast.ToString(pp["hallName"]) - hall.SessionId = cast.ToString(pp["sessionId"]) - hall.StartTime = cast.ToString(pp["startTime"]) - hall.EndTime = cast.ToString(pp["endTime"]) - return hall, nil - } - } - - } - return nil, fmt.Errorf("film[%s] day[%s] ting[%s] nohas", order.MovieName, orderShowDay, order.Ting) -} - -func (d *Dadi) getCinemaSeats(order *model.Order, cinema *DadiCinema, hall *DadiFilmShowHall) error { - baseReq := d.getBaseParam(cinema) - baseReq["sessionId"] = hall.SessionId - reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cticket/getSessionSeat" - body, err := httputil.HttpGet(reqUrl, baseReq, d.getBaseHeader()) - if err != nil { - log.Errorf("http get url: %s, error: %s", reqUrl, err.Error()) - return err - } - _, err = d.checkError(body) - if err != nil { - return err - } - - return nil - //baseReq := d.getBaseParam(cinema) -} - -func (d *Dadi) holdSeats(order *model.Order, cinema *DadiCinema, hall *DadiFilmShowHall) (*DadiFilmOrder, error) { - return &DadiFilmOrder{ - OrderId: "test", - }, nil -} diff --git a/worker/dadi/processor.go b/worker/dadi/processor.go new file mode 100644 index 0000000..c7e98c6 --- /dev/null +++ b/worker/dadi/processor.go @@ -0,0 +1,332 @@ +package dadi + +import ( + "encoding/json" + "film/base/httputil" + "film/base/util" + "film/model" + "film/worker/common" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/smbrave/goutil" + "github.com/spf13/cast" + "strings" +) + +type ProcessorConfig struct { + Token string +} + +type Processor struct { + token string + citys map[string]*City +} + +func NewProcessor(cfg *ProcessorConfig) (common.Processor, error) { + processor := &Processor{ + token: cfg.Token, + } + if err := processor.init(); err != nil { + return nil, err + } + return processor, nil +} + +func (d *Processor) init() error { + cityUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cbase/cityAndCinemaList" + + params := d.getBaseParam(&Cinema{ + Name: "大地影院(北京十里河铭泽店)", + Id: 118, + UnifiedCode: 11050621, + }) + body, err := httputil.HttpGet(cityUrl, params, d.getBaseHeader()) + if err != nil { + log.Errorf(" httputil.HttpGet url : %s error: %s", cityUrl, err.Error()) + return err + } + result, err := d.checkError(body) + if err != nil { + return err + } + + citys := make(map[string]*City) + datas := cast.ToSlice(result) + + for _, d := range datas { + data := cast.ToStringMap(d) + + cinemas := make([]*Cinema, 0) + for _, c := range cast.ToSlice(data["cinemas"]) { + cin := cast.ToStringMap(c) + cinema := new(Cinema) + cinema.Name = cast.ToString(cin["name"]) + cinema.Address = cast.ToString(cin["address"]) + cinema.Latitude = cast.ToString(cin["latitude"]) + cinema.Longitude = cast.ToString(cin["longitude"]) + cinema.CityId = cast.ToInt64(cin["cityId"]) + cinema.UnifiedCode = cast.ToInt64(cin["unifiedCode"]) + cinemas = append(cinemas, cinema) + } + cityInfo := cast.ToStringMap(data["cityInfo"]) + city := new(City) + city.Name = cast.ToString(cityInfo["chName"]) + city.ShortName = cast.ToString(cityInfo["shortName"]) + city.CityId = cast.ToInt64(data["cityId"]) + city.CityCode = cast.ToInt64(data["cityCode"]) + city.Cinemas = cinemas + + citys[city.ShortName] = city + } + + d.citys = citys + log.Infof("load dadi procoessor citys : %d", len(d.citys)) + + return nil +} + +func (d *Processor) checkError(body []byte) (interface{}, error) { + result := make(map[string]interface{}) + if err := json.Unmarshal(body, &result); err != nil { + log.Errorf("json.unmarshal [%s] error : %s", string(body), err.Error()) + return nil, err + } + if cast.ToInt(result["code"]) != 200 { + log.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) + return nil, fmt.Errorf("code[%d] message[%s]", cast.ToInt(result["code"]), cast.ToString(result["msg"])) + } + + return result["data"], nil +} + +func (d *Processor) getBaseHeader() map[string]interface{} { + return map[string]interface{}{ + "User-Agent": "DaDiCinemaApp/8.7.3 (iPhone; iOS 15.2.1; Scale/3.00)", + "c-User-Token": d.token, + "c-tenantId": strings.Split(d.token, ":")[0], + } +} + +func (p *Processor) getBaseParam(cinema *Cinema) map[string]interface{} { + params := map[string]interface{}{ + "channelCode": "SYH-DDZY-DD", + "channelName": "大地自营-大地", + "channelNo": "SYH-DDZY-DD", + "channelUid": "SYH-DDZY-DD", + "cinema": cast.ToString(cinema.UnifiedCode), + "cinemaCode": cast.ToString(cinema.UnifiedCode), + "cinemaUid": cast.ToString(cinema.Id), + "d": "iPhone14,3", + "i": "00000000-0000-0000-0000-000000000000", + "k": p.token, + "r": "1", + "s": "iOS15.2.1", + "t": "1", + "tenantId": "321566", + "unifiedCinemaId": cast.ToString(cinema.Id), + "unifiedCinemaName": cinema.Name, + "unifiedCode": cast.ToString(cinema.UnifiedCode), + "v": "8.7.3", + } + return params +} + +func (p *Processor) getCinema(cityName, cinemaName string) (*Cinema, error) { + if _, ok := p.citys[cityName]; !ok { + log.Errorf("city[%s] not exist dadi cinema", cityName) + return nil, fmt.Errorf("city[%s] not exist dadi cinema", cityName) + } + city := p.citys[cityName] + for _, cinema := range city.Cinemas { + if cinema.Name != cinemaName { + continue + } + return cinema, nil + } + return nil, fmt.Errorf("city[%s] not[%s]", cityName, cinemaName) +} + +func (d *Processor) getCinemaFilmShowHall(cinema *Cinema, filmName, startTime, hallName string) (*FilmShowHall, error) { + baseReq := d.getBaseParam(cinema) + reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/film/getHitFilmAndFilmSession" + body, err := httputil.HttpGet(reqUrl, baseReq, d.getBaseHeader()) + if err != nil { + log.Errorf("httpGet[%s] error : %s", reqUrl, err.Error()) + return nil, err + } + + result, err := d.checkError(body) + if err != nil { + return nil, err + } + + var hall *FilmShowHall = nil + for _, f := range cast.ToSlice(cast.ToStringMap(result)["filmList"]) { + ff := cast.ToStringMap(f) + moveName := cast.ToString(ff["name"]) + if moveName != filmName { + continue + } + for _, s := range cast.ToSlice(ff["showList"]) { + ss := cast.ToStringMap(s) + day := cast.ToString(ss["dayStr"]) + for _, p := range cast.ToSlice(ss["plist"]) { + pp := cast.ToStringMap(p) + hName := cast.ToString(pp["hallName"]) + sTime := cast.ToString(pp["startTime"]) + if startTime != sTime || hName != hallName { + continue + } + hall = new(FilmShowHall) + hall.FilmName = filmName + hall.ShowDay = day + hall.HallName = cast.ToString(pp["hallName"]) + hall.SessionId = cast.ToString(pp["sessionId"]) + hall.StartTime = cast.ToString(pp["startTime"]) + hall.EndTime = cast.ToString(pp["endTime"]) + return hall, nil + } + } + } + return nil, fmt.Errorf("film[%s] startTime[%s] ting[%s] nohas", filmName, startTime, hallName) +} + +func (p *Processor) getSeatGoods(cinema *Cinema, sessionId, seats string) ([]*SeatGoods, error) { + baseReq := p.getBaseParam(cinema) + baseReq["sessionId"] = sessionId + reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/cinema/cbticket/cticket/getSessionSeat" + body, err := httputil.HttpGet(reqUrl, baseReq, p.getBaseHeader()) + if err != nil { + log.Errorf("http get url: %s, error: %s", reqUrl, err.Error()) + return nil, err + } + data, err := p.checkError(body) + if err != nil { + return nil, err + } + existMap := make(map[string]bool) + for _, s := range strings.Split(seats, "|") { + existMap[s] = true + } + + allSeatGoods := make([]*SeatGoods, 0) + for _, s := range cast.ToSlice(cast.ToStringMap(data)["seats"]) { + seat := cast.ToStringMap(s) + key := fmt.Sprintf("%d:%d", cast.ToInt(seat["phyRowId"]), cast.ToInt(seat["phyColId"])) + if _, ok := existMap[key]; !ok { + continue + } + areanInfo := cast.ToStringMap(seat["areaInfo"]) + ticketPriceInfo := cast.ToStringMap(areanInfo["ticketPriceInfo"]) + seatGoods := new(SeatGoods) + seatGoods.SeatCode = cast.ToString(seat["seatCode"]) + seatGoods.PlanCode = sessionId + seatGoods.LevelCode = "" + seatGoods.StandPrice = cast.ToString(ticketPriceInfo["standPrice"]) + seatGoods.AddPrice = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["addPrice"])) + seatGoods.ServiceFee = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["servicePrice"])) + seatGoods.PlatServiceFee = fmt.Sprintf("%.2f", cast.ToFloat64(ticketPriceInfo["platServicePrice"])) + allSeatGoods = append(allSeatGoods, seatGoods) + } + return allSeatGoods, nil +} + +func (p *Processor) prevOrderInfo(cinema *Cinema, seatGoods []*SeatGoods) (*PreviewOrder, error) { + // 座位下单 + reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/order/trade/order/ticket" + baseReq := p.getBaseParam(cinema) + baseReq["seatGoodsAddList"] = seatGoods + baseReq["existsAreasPrice"] = false + baseReq["phoneNo"] = "17610351227" + reqBody := goutil.EncodeJSON(baseReq) + baseHeader := p.getBaseHeader() + baseHeader["Cookie"] = "HWWAFSESID=d527bdc7a4a18b8e40; HWWAFSESTIME=1680956218712" + body, err := httputil.HttpPostJson(reqUrl, nil, baseHeader, []byte(reqBody)) + if err != nil { + log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) + return nil, err + } + data, err := p.checkError(body) + if err != nil { + return nil, err + } + billCode := cast.ToString(data) + + // 计算价格 + reqUrl = "https://appapi.dadicinema.com/app-web/v1/web/order/newPriceCalculate" + baseReq = p.getBaseParam(cinema) + baseReq["billCode"] = billCode + baseReq["firstPriceCalculateFlag"] = 1 + reqBody = goutil.EncodeJSON(baseReq) + body, err = httputil.HttpPostJson(reqUrl, nil, p.getBaseHeader(), []byte(reqBody)) + if err != nil { + log.Errorf("httpPost url[%s] error : %s", reqUrl, err.Error()) + return nil, err + } + data, err = p.checkError(body) + if err != nil { + return nil, err + } + totalRealPrice := cast.ToFloat64(cast.ToStringMap(data)["totalRealPrice"]) + + previewOrder := new(PreviewOrder) + previewOrder.TotalPrice = int64(totalRealPrice * 100) + previewOrder.BillCode = billCode + + return previewOrder, nil +} + +func (p *Processor) CheckOrder(order *model.Order) (*common.CheckInfo, error) { + cinema, err := p.getCinema(order.CityName, order.CinemaName) + if err != nil { + return nil, err + } + showHall, err := p.getCinemaFilmShowHall(cinema, order.MovieName, goutil.TimeToDateTime(order.ShowTime), order.Ting) + if err != nil { + return nil, err + } + seatGoods, err := p.getSeatGoods(cinema, showHall.SessionId, order.Seats) + if err != nil { + return nil, err + } + previewOrder, err := p.prevOrderInfo(cinema, seatGoods) + if err != nil { + return nil, err + } + + result := new(common.CheckInfo) + result.UnitPrice = previewOrder.TotalPrice / int64(order.SeatNum) + result.TotalPrice = previewOrder.TotalPrice + result.BillCode = previewOrder.BillCode + log.Infof("check order[%s][%s] totalPrice[%s] [%s][%s][%s] success", + order.OrderId, result.BillCode, util.MoneyFen(previewOrder.TotalPrice), + order.CityName, order.CinemaName, order.MovieName) + return result, nil +} + +func (p *Processor) CreateOrder(*model.Order) (*common.OrderInfo, error) { + return nil, nil +} + +func (p *Processor) CancelOrder(order *model.Order, checkInfo *common.CheckInfo) error { + cinema, err := p.getCinema(order.CityName, order.CinemaName) + if err != nil { + return err + } + reqUrl := "https://appapi.dadicinema.com/app-web/v1/web/order/cancel" + baseReq := p.getBaseParam(cinema) + baseReq["billCode"] = checkInfo.BillCode + + body, err := httputil.HttpPostJson(reqUrl, nil, p.getBaseHeader(), []byte(goutil.EncodeJSON(baseReq))) + if err != nil { + log.Errorf("http request url[%s] error[%s]", reqUrl, err.Error()) + return err + } + _, err = p.checkError(body) + if err != nil { + return err + } + log.Infof("cancel order[%s][%s] [%s][%s][%s] success", + order.OrderId, checkInfo.BillCode, order.CityName, order.CinemaName, order.MovieName) + return nil +} diff --git a/worker/dadi/type.go b/worker/dadi/type.go new file mode 100644 index 0000000..e822691 --- /dev/null +++ b/worker/dadi/type.go @@ -0,0 +1,43 @@ +package dadi + +type PreviewOrder struct { + BillCode string + TotalPrice int64 +} + +type SeatGoods struct { + StandPrice string `json:"standPrice"` + SeatCode string `json:"seatCode"` + PlanCode string `json:"planCode"` + LevelCode string `json:"levelCode"` + AddPrice string `json:"addPrice"` + PlatServiceFee string `json:"platServiceFee"` + ServiceFee string `json:"serviceFee"` +} + +type FilmShowHall struct { + ShowDay string + FilmName string + HallName string + StartTime string + EndTime string + SessionId string +} + +type Cinema struct { + Id int64 + UnifiedCode int64 + Name string + Address string + Latitude string + Longitude string + CityId int64 +} + +type City struct { + Name string + ShortName string + CityCode int64 + CityId int64 + Cinemas []*Cinema +} diff --git a/worker/haha/haha_processor.go b/worker/haha/haha_processor.go new file mode 100644 index 0000000..10439c8 --- /dev/null +++ b/worker/haha/haha_processor.go @@ -0,0 +1,58 @@ +package haha + +import ( + "encoding/json" + "film/base/httputil" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/spf13/cast" +) + +type ProcessorConfig struct { + Token string +} +type Processor struct { + token string +} + +func NewProcessor(cfg *ProcessorConfig) *Processor { + return &Processor{ + token: cfg.Token, + } +} + +func (p *Processor) checkError(body []byte) (interface{}, error) { + result := make(map[string]interface{}) + if err := json.Unmarshal(body, &result); err != nil { + log.Errorf("json.unmarshal [%s] error : %s", string(body), err.Error()) + return nil, err + } + if cast.ToInt(result["status"]) != 200 || cast.ToInt(result["code"]) != 200 { + log.Errorf("status[%d] code[%d] message[%s]", cast.ToInt(result["status"]), cast.ToInt(result["code"]), cast.ToString(result["msg"])) + return nil, fmt.Errorf("%d:%s", cast.ToInt(result["code"]), cast.ToString(result["msg"])) + } + return result["data"], nil +} + +func (p *Processor) BidPrice(id int64, price int64) error { + reqUrl := "https://hahapiao.cn/api/Synchro/toPrice" + params := map[string]interface{}{ + "id": cast.ToString(id), + "price": fmt.Sprintf("%.2f", float64(price)/100), + } + header := map[string]interface{}{ + "token": p.token, + } + body, err := httputil.HttpPostForm(reqUrl, header, params) + if err != nil { + log.Error("httpPost error : %s", err.Error()) + return err + } + + _, err = p.checkError(body) + if err != nil { + return err + } + + return nil +} diff --git a/worker/orders.go b/worker/haha/haha_sync_order.go similarity index 79% rename from worker/orders.go rename to worker/haha/haha_sync_order.go index fa5f743..ec6cdc7 100644 --- a/worker/orders.go +++ b/worker/haha/haha_sync_order.go @@ -1,4 +1,4 @@ -package worker +package haha import ( "crypto/tls" @@ -11,57 +11,43 @@ import ( "io" "net/http" "net/url" - "strings" "time" ) -type Orders struct { - Token string - Dadi *Dadi +type SyncOrderConfig struct { + Token string + NewOrder chan *model.Order + UpdateOrder chan *model.Order } -func (w *Orders) Init() error { +type SyncOrder struct { + token string + newOrder chan *model.Order + updateOrder chan *model.Order +} + +func NewSyncOrder(cfg *SyncOrderConfig) *SyncOrder { + return &SyncOrder{ + token: cfg.Token, + newOrder: cfg.NewOrder, + updateOrder: cfg.UpdateOrder, + } +} + +func (s *SyncOrder) Sync() { timezone, _ := time.LoadLocation("Asia/Shanghai") cron := gocron.NewScheduler(timezone) cron.Every(30).Seconds().Do(func() { - w.syncOrder() + s.run() }) cron.StartAsync() - return nil } -func (w *Orders) httpPost(requestUrl string) ([]byte, error) { - client := &http.Client{Timeout: 20 * time.Second} - //忽略https的证书 - client.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - p := url.Values{} - u, _ := url.Parse(requestUrl) - - u.RawQuery = p.Encode() - req, err := http.NewRequest("POST", u.String(), nil) - if err != nil { - return nil, err - } - req.Header.Set("token", w.Token) - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) - } - return io.ReadAll(resp.Body) -} - -func (w *Orders) syncOrder() { +func (s *SyncOrder) run() { orderUrl := "https://hahapiao.cn/api/Synchro/toList" - body, err := w.httpPost(orderUrl) + body, err := s.httpPost(orderUrl) if err != nil { log.Errorf("syncOrder error : %s", err.Error()) return @@ -116,15 +102,46 @@ func (w *Orders) syncOrder() { if isAdd { model.AddOrder(order) - if strings.Contains(order.CinemaName, "大地影院") { - w.Dadi.NewOrder(order) + select { + case s.newOrder <- order: + default: + log.Errorf("new order chan is full!") } + } else { model.UpdateOrder(order) - if strings.Contains(order.CinemaName, "大地影院") { - w.Dadi.UpdateOrder(order) + select { + case s.updateOrder <- order: + default: + log.Errorf("update order chan is full!") } } } - +} + +func (s *SyncOrder) httpPost(requestUrl string) ([]byte, error) { + client := &http.Client{Timeout: 20 * time.Second} + //忽略https的证书 + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + p := url.Values{} + u, _ := url.Parse(requestUrl) + + u.RawQuery = p.Encode() + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, err + } + req.Header.Set("token", s.token) + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) + } + return io.ReadAll(resp.Body) } diff --git a/worker/type.go b/worker/type.go deleted file mode 100644 index a40b5ba..0000000 --- a/worker/type.go +++ /dev/null @@ -1,46 +0,0 @@ -package worker - -type DadiFilmShowHall struct { - ShowDay string - FilmName string - HallName string - StartTime string - EndTime string - SessionId string -} - -type DadiFilmShow struct { - Day string - Halls []*DadiFilmShowHall -} - -type DadiFilmOrder struct { - OrderId string -} - -type DadiFilmSeat struct { -} - -type DadiFilm struct { - Id int64 - Name string - Shows []*DadiFilmShow -} - -type DadiCinema struct { - Id int64 - UnifiedCode int64 - Name string - Address string - Latitude string - Longitude string - CityId int64 -} - -type DadiCity struct { - Name string - ShortName string - CityCode int64 - CityId int64 - Cinemas []*DadiCinema -} diff --git a/worker/worker.go b/worker/worker.go new file mode 100644 index 0000000..1c05aae --- /dev/null +++ b/worker/worker.go @@ -0,0 +1,101 @@ +package worker + +import ( + "film/base/util" + "film/config" + "film/model" + "film/worker/dadi" + "film/worker/haha" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/smbrave/goutil" + "gitlab.com/jiangyong27/gobase/wxapi" + "strings" + "time" +) + +type Worker struct { + qyClient *wxapi.WxQiye +} + +func (w *Worker) initQyWeixin() { + cfg := config.GetConfig() + w.qyClient = wxapi.NewQiye(&wxapi.QiyeConfig{ + Corpid: cfg.Weixin.QiyeAppid, + Secret: cfg.Weixin.Qiyesecret, + Sender: cfg.Weixin.QiyeAgent, + }) +} +func (w *Worker) Run() { + w.initQyWeixin() + cfg := config.GetConfig() + newOrderChan := make(chan *model.Order, 100000) + updateOrderChan := make(chan *model.Order, 100000) + hahaSyncer := haha.NewSyncOrder(&haha.SyncOrderConfig{ + Token: cfg.Film.HahaToken, + NewOrder: newOrderChan, + UpdateOrder: updateOrderChan, + }) + + hahaSyncer.Sync() + + //order, _ := model.GetOrder(590623) + //newOrderChan <- order + + //hahaProcessor := haha.NewProcessor(&haha.ProcessorConfig{Token: cfg.Film.HahaToken}) + dadiProcessor, err := dadi.NewProcessor(&dadi.ProcessorConfig{Token: cfg.Film.DadiToken}) + if err != nil { + panic(err) + } + for { + select { + case order := <-newOrderChan: + if order.IsSeat == 2 || order.IsSeat == 1 { + w.qyClient.SendText([]string{"jiangyong"}, order.CinemaName+":"+order.MovieName) + } + if !strings.Contains(order.CinemaName, "大地影院") { + continue + } + checkInfo, err := dadiProcessor.CheckOrder(order) + if err != nil { + log.Errorf("check orrder[%s] error : %s", order.OrderId, err.Error()) + continue + } + + //hahaProcessor.BidPrice(order.Id, checkInfo.UnitPrice) + go func() { + time.Sleep(60 * time.Second) + if err := dadiProcessor.CancelOrder(order, checkInfo); err != nil { + log.Errorf("cancel order[%s] error[%s]", order.OrderId, err.Error()) + } + }() + + // 发送信息 + message := make([]string, 0) + message = append(message, "【哈哈票订单信息】") + message = append(message, fmt.Sprintf("城市:%s", order.CityName)) + message = append(message, fmt.Sprintf("影院:%s", order.CinemaName)) + message = append(message, fmt.Sprintf("影厅:%s", order.Ting)) + message = append(message, fmt.Sprintf("影片:%s", order.MovieName)) + message = append(message, fmt.Sprintf("座位:%s,%s,%s", order.Seats, + goutil.If(order.IsSeat == 3, "可以调座", "不可调座"), + goutil.If(order.LoverSeat == 1, "情侣座", "普通座"))) + message = append(message, fmt.Sprintf("原价:%.2f", float64(order.MaoyanPrice)/100)) + message = append(message, fmt.Sprintf("编号:%s", order.OrderId)) + message = append(message, fmt.Sprintf("总金额:%.2f(%d)", float64(order.TotalPrice)/100, order.SeatNum)) + message = append(message, fmt.Sprintf("报价范围:%.2f~%.2f", float64(order.MinPrice)/100, float64(order.MaxPrice)/100)) + message = append(message, fmt.Sprintf("订单时间:%s", time.Unix(order.PayTime, 0).Format("2006-01-02 15:04"))) + message = append(message, fmt.Sprintf("放映时间:%s", time.Unix(order.ShowTime, 0).Format("2006-01-02 15:04"))) + message = append(message, "\n") + message = append(message, "【大地订单信息】") + message = append(message, fmt.Sprintf("单价:%s", util.MoneyFen(checkInfo.UnitPrice))) + message = append(message, fmt.Sprintf("总价:%s", util.MoneyFen(checkInfo.TotalPrice))) + if err := w.qyClient.SendText([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil { + log.Errorf("send message error : %s", err.Error()) + } + case updateOrder := <-updateOrderChan: + log.Debugf("update:", goutil.EncodeJSON(updateOrder)) + } + } + +}