This commit is contained in:
jiangyong27 2023-04-09 02:11:58 +08:00
parent 9515fdd61a
commit 603f72e657
13 changed files with 706 additions and 368 deletions

84
base/httputil/httppost.go Normal file
View File

@ -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)
}

View File

@ -1 +1,7 @@
package util package util
import "fmt"
func MoneyFen(money int64) string {
return fmt.Sprintf("%.2f", float64(money)/100)
}

View File

@ -55,24 +55,6 @@ func main() {
panic(err) panic(err)
} }
dadiProcessor := &worker.Dadi{ work := &worker.Worker{}
Token: cfg.Film.DadiToken, work.Run()
}
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 {}
} }

View File

@ -18,4 +18,4 @@ qiye_agent = "1000013"
[film] [film]
haha_token = "cc5f1d4c36f7e9544d641a174b298f94" haha_token = "cc5f1d4c36f7e9544d641a174b298f94"
dadi_token = "321566:b891effb-5493-4f26-ac54-bfa5581ca8c3" dadi_token = "321566:7b84a0b1-832a-4492-a96a-23002d6c8715"

View File

@ -19,4 +19,5 @@ qiye_agent = "1000013"
[film] [film]
haha_token = "cc5f1d4c36f7e9544d641a174b298f94" haha_token = "cc5f1d4c36f7e9544d641a174b298f94"
dadi_token = "321566:b891effb-5493-4f26-ac54-bfa5581ca8c3" dadi_token = "321566:7b84a0b1-832a-4492-a96a-23002d6c8715"

View File

@ -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
}

View File

@ -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
}

332
worker/dadi/processor.go Normal file
View File

@ -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
}

43
worker/dadi/type.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package worker package haha
import ( import (
"crypto/tls" "crypto/tls"
@ -11,57 +11,43 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strings"
"time" "time"
) )
type Orders struct { type SyncOrderConfig struct {
Token string Token string
Dadi *Dadi 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") timezone, _ := time.LoadLocation("Asia/Shanghai")
cron := gocron.NewScheduler(timezone) cron := gocron.NewScheduler(timezone)
cron.Every(30).Seconds().Do(func() { cron.Every(30).Seconds().Do(func() {
w.syncOrder() s.run()
}) })
cron.StartAsync() cron.StartAsync()
return nil
} }
func (w *Orders) httpPost(requestUrl string) ([]byte, error) { func (s *SyncOrder) run() {
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() {
orderUrl := "https://hahapiao.cn/api/Synchro/toList" orderUrl := "https://hahapiao.cn/api/Synchro/toList"
body, err := w.httpPost(orderUrl) body, err := s.httpPost(orderUrl)
if err != nil { if err != nil {
log.Errorf("syncOrder error : %s", err.Error()) log.Errorf("syncOrder error : %s", err.Error())
return return
@ -116,15 +102,46 @@ func (w *Orders) syncOrder() {
if isAdd { if isAdd {
model.AddOrder(order) model.AddOrder(order)
if strings.Contains(order.CinemaName, "大地影院") { select {
w.Dadi.NewOrder(order) case s.newOrder <- order:
} default:
} else { log.Errorf("new order chan is full!")
model.UpdateOrder(order)
if strings.Contains(order.CinemaName, "大地影院") {
w.Dadi.UpdateOrder(order)
}
}
} }
} else {
model.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)
} }

View File

@ -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
}

101
worker/worker.go Normal file
View File

@ -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))
}
}
}