From dd64f4f0ee9d2bb6e7983869eeb6d9b52d4e171e Mon Sep 17 00:00:00 2001 From: jiangyong Date: Sat, 27 Apr 2024 23:12:44 +0800 Subject: [PATCH] newcar --- cmd/film.go | 27 +++--- conf/server.conf.dev | 11 ++- dao/nowcar.go | 68 +++++++++++++++ model/model.go => global/db.go | 35 ++++---- go.mod | 3 + model/nowcar.go | 9 ++ model/orders.go | 7 +- worker/haha/haha_sync_order.go | 34 ++------ worker/nowcar/nowcar.go | 130 +++++++++++++++++++++++++++++ worker/worker.go | 147 ++++----------------------------- 10 files changed, 278 insertions(+), 193 deletions(-) create mode 100644 dao/nowcar.go rename model/model.go => global/db.go (66%) create mode 100644 model/nowcar.go create mode 100644 worker/nowcar/nowcar.go diff --git a/cmd/film.go b/cmd/film.go index d3101b7..acc0cbb 100644 --- a/cmd/film.go +++ b/cmd/film.go @@ -2,9 +2,9 @@ package main import ( "film/config" - "film/model" + "film/global" "film/worker" - "fmt" + "film/worker/nowcar" rotatelogs "github.com/lestrrat-go/file-rotatelogs" "github.com/rifflock/lfshook" log "github.com/sirupsen/logrus" @@ -44,19 +44,24 @@ func initLog() { log.SetLevel(log.Level(cfg.Server.LogLevel)) } +func main2() { + config.LoadServerConfig() + config.LoadDadiConfig() + config.LoadHahaConfig() + initLog() + + global.InitDB() + + work := &worker.Worker{} + work.Run() +} + func main() { config.LoadServerConfig() config.LoadDadiConfig() config.LoadHahaConfig() initLog() - cfg := config.GetConfig() - dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", cfg.Mysql.User, - cfg.Mysql.Pass, cfg.Mysql.Host, cfg.Mysql.Port, cfg.Mysql.Db) - _, err := model.Init(dsn) - if err != nil { - panic(err) - } - work := &worker.Worker{} - work.Run() + global.InitDB() + nowcar.Sync() } diff --git a/conf/server.conf.dev b/conf/server.conf.dev index c06f7c2..2641673 100644 --- a/conf/server.conf.dev +++ b/conf/server.conf.dev @@ -1,22 +1,21 @@ [server] address = "0.0.0.0:9263" #0:PAINC 1:FATAL 2:ERROR 3:WARNING 4:INFO 5:DEBUG 6:TRACE -log_level = 4 +log_level = 5 [mysql] -host = "100.118.29.74" -port = 3307 +host = "14.22.116.197" +port = 9305 user = "film" pass = "7VCfJx7H8MymUm" db = "film" + [weixin] qiye_appid = "ww288920bd3e8c92b2" qiye_secret = "3aqE6LAEKLiGtYBtX7TZm0uY_YD52w3R20AQirSICXY" qiye_agent = "1000013" receiver = ["jiangyong", "zhangping"] -[film] -haha_token = "d6847dfbd7b79bc18709e0311fd7813b" -dadi_token = "321566:7b84a0b1-832a-4492-a96a-23002d6c8715" \ No newline at end of file + diff --git a/dao/nowcar.go b/dao/nowcar.go new file mode 100644 index 0000000..b57fe9c --- /dev/null +++ b/dao/nowcar.go @@ -0,0 +1,68 @@ +package dao + +import ( + "film/global" + "film/model" + "gorm.io/gorm" +) + +type NowCarDao struct { +} + +func NewNowCarDao() *NowCarDao { + return &NowCarDao{} +} + +func (d *NowCarDao) TableName() string { + return "nowcar" +} + +func (d *NowCarDao) Create(o *model.Nowcar) (int64, error) { + res := global.GetDB().Table(d.TableName()).Create(o) + return o.Id, res.Error +} +func (d *NowCarDao) Update(o *model.Nowcar) error { + tx := global.GetDB().Table(d.TableName()) + res := tx.Save(o) + return res.Error +} + +func (d *NowCarDao) GetStart(shopName, workstation string, startTime int64) (*model.Nowcar, error) { + var u model.Nowcar + tx := global.GetDB().Table(d.TableName()) + + tx = tx.Where("shop_name = ?", shopName) + tx = tx.Where("workstation = ?", workstation) + tx = tx.Where("start_time = ?", startTime) + + tx = tx.Order("start_time DESC") + res := tx.First(&u) + if res.Error == gorm.ErrRecordNotFound { + return nil, nil + } + + if res.Error != nil { + return nil, res.Error + } + return &u, nil +} +func (d *NowCarDao) GetBusy(shopName, workstation string) (*model.Nowcar, error) { + var u model.Nowcar + tx := global.GetDB().Table(d.TableName()) + + tx = tx.Where("shop_name = ?", shopName) + tx = tx.Where("workstation = ?", workstation) + tx = tx.Where("start_time != 0") + tx = tx.Where("end_time = 0") + + tx = tx.Order("start_time DESC") + res := tx.First(&u) + if res.Error == gorm.ErrRecordNotFound { + return nil, nil + } + + if res.Error != nil { + return nil, res.Error + } + return &u, nil +} diff --git a/model/model.go b/global/db.go similarity index 66% rename from model/model.go rename to global/db.go index abca160..3b55cb9 100644 --- a/model/model.go +++ b/global/db.go @@ -1,7 +1,9 @@ -package model +package global import ( "context" + "film/config" + "fmt" log "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" @@ -13,16 +15,13 @@ var ( db *gorm.DB = nil ) -func SetDb(b *gorm.DB) { - db = b -} - -func GetOrm() *gorm.DB { +func GetDB() *gorm.DB { return db } type DBLogger struct { - level logger.LogLevel + level logger.LogLevel + threshold int64 } func (d *DBLogger) LogMode(level logger.LogLevel) logger.Interface { @@ -48,27 +47,31 @@ func (d *DBLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql st if err != nil && err != gorm.ErrRecordNotFound { log.Errorf("[SQL]sql=%s affect=%d cost=%dms error=%v", sql, affects, time.Since(begin).Milliseconds(), err) } else { - if time.Since(begin).Milliseconds() > 1000 { - log.Errorf("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds()) + if time.Since(begin).Milliseconds() > d.threshold { + log.Warnf("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds()) } else { - log.Tracef("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds()) + log.Debugf("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds()) } } } -func Init(dsn string) (*gorm.DB, error) { +func InitDB() error { + + cfg := config.GetConfig() + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", cfg.Mysql.User, + cfg.Mysql.Pass, cfg.Mysql.Host, cfg.Mysql.Port, cfg.Mysql.Db) + var err error db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { log.Errorf("open dsn[%s] error[%s]", dsn, err) - return nil, err + return err } - - db.Logger = &DBLogger{} - return db, err + db.Logger = &DBLogger{threshold: 1000} + return nil } -func Ping() error { +func DBPing() error { d, err := db.DB() if err != nil { return err diff --git a/go.mod b/go.mod index 6c05cf3..4215ddf 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/smbrave/goutil v0.0.0-20230208141215-e3360c3bfd1b github.com/spf13/cast v1.5.0 github.com/spf13/viper v1.15.0 + github.com/tidwall/gjson v1.17.1 gitlab.com/jiangyong27/gobase v1.0.23 gorm.io/driver/mysql v1.4.7 gorm.io/gorm v1.24.6 @@ -38,6 +39,8 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect diff --git a/model/nowcar.go b/model/nowcar.go new file mode 100644 index 0000000..17f5ff2 --- /dev/null +++ b/model/nowcar.go @@ -0,0 +1,9 @@ +package model + +type Nowcar struct { + Id int64 + ShopName string + Workstation string + StartTime int64 + EndTime int64 +} diff --git a/model/orders.go b/model/orders.go index d5be30b..f435d7d 100644 --- a/model/orders.go +++ b/model/orders.go @@ -1,6 +1,7 @@ package model import ( + "film/global" "fmt" "github.com/smbrave/goutil" "gorm.io/gorm" @@ -48,13 +49,13 @@ func (o *Order) String() string { func AddOrder(o *Order) (int64, error) { o.CreateTime = time.Now().Unix() o.CreateDate = time.Now().Format("2006-01-02") - res := db.Table(tableNameOrder).Create(o) + res := global.GetDB().Table(tableNameOrder).Create(o) return o.Id, res.Error } func GetOrder(id int64) (*Order, error) { var u Order - tx := db.Table(tableNameOrder) + tx := global.GetDB().Table(tableNameOrder) tx = tx.Where("id = ?", id) res := tx.First(&u) if res.Error == gorm.ErrRecordNotFound { @@ -69,7 +70,7 @@ func GetOrder(id int64) (*Order, error) { func UpdateOrder(o *Order) error { o.UpdateTime = time.Now().Unix() - tx := db.Table(tableNameOrder) + tx := global.GetDB().Table(tableNameOrder) res := tx.Save(o) return res.Error } diff --git a/worker/haha/haha_sync_order.go b/worker/haha/haha_sync_order.go index caa2aa6..5f47ba3 100644 --- a/worker/haha/haha_sync_order.go +++ b/worker/haha/haha_sync_order.go @@ -7,9 +7,7 @@ import ( "film/model" "film/worker/common" "fmt" - "github.com/go-co-op/gocron" log "github.com/sirupsen/logrus" - "github.com/smbrave/goutil" "github.com/spf13/cast" "io" "net/http" @@ -18,40 +16,26 @@ import ( ) type SyncOrderConfig struct { - Token string - NewOrder chan *model.Order - UpdateOrder chan *model.Order - SyncInterval int + Token string + NewOrder chan *model.Order + UpdateOrder chan *model.Order } type SyncOrder struct { - token string - syncInterval int - newOrder chan *model.Order - updateOrder chan *model.Order + 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, - syncInterval: goutil.If(cfg.SyncInterval == 0, 30, cfg.SyncInterval), + token: cfg.Token, + newOrder: cfg.NewOrder, + updateOrder: cfg.UpdateOrder, } } func (s *SyncOrder) Sync() { - timezone, _ := time.LoadLocation("Asia/Shanghai") - cron := gocron.NewScheduler(timezone) - - cron.Every(s.syncInterval).Seconds().Do(func() { - s.run() - }) - - cron.StartAsync() -} - -func (s *SyncOrder) run() { orderUrl := "https://hahapiao.cn/api/Synchro/pcToList" body, err := s.httpPost(orderUrl) if err != nil { diff --git a/worker/nowcar/nowcar.go b/worker/nowcar/nowcar.go new file mode 100644 index 0000000..fa0ec2c --- /dev/null +++ b/worker/nowcar/nowcar.go @@ -0,0 +1,130 @@ +package nowcar + +import ( + "bytes" + "film/dao" + "film/model" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/tidwall/gjson" + "io" + "net/http" + "net/url" + "time" +) + +func Sync() { + + devIds, err := getDevId() + if err != nil { + return + } + for _, devId := range devIds { + if devId == "" { + continue + } + getInfo(devId) + } +} + +func getInfo(devId string) ([]string, error) { + reqUrl := "https://wx.wdfcar.com/NowZiZhuXiCheApp/userSiteOrder/getInfo" + + params := make(url.Values) + params.Set("user_lng", "106.55072784423828") + params.Set("user_lat", "29.56471061706543") + params.Set("dev_id", devId) + params.Set("lt-id", "1811") + params.Set("lt-token", "c5e139a7e118b346149750489c57560b") + resp, err := http.Post(reqUrl, "application/x-www-form-urlencoded", + bytes.NewBuffer([]byte(params.Encode()))) + if err != nil { + log.Error("http poset error :%s", err.Error()) + return nil, err + } + defer resp.Body.Close() + rspbody, _ := io.ReadAll(resp.Body) + code := gjson.GetBytes(rspbody, "code").Int() + if code != 0 { + log.Errorf("devId:%s rspbody error :%s", devId, string(rspbody)) + return nil, fmt.Errorf("code is :%d", code) + } + + data := gjson.GetBytes(rspbody, "data") + shopName := data.Get("addr_name").String() + doors := data.Get("doors").Array() + + m := new(model.Nowcar) + m.ShopName = shopName + + for _, door := range doors { + workstation := door.Get("number").String() + + status := door.Get("status").String() + if status != "空闲" { + startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", status, time.Local) + m1, err := dao.NewNowCarDao().GetStart(shopName, workstation, startTime.Unix()) + if err != nil { + log.Errorf("db error :%s", err.Error()) + continue + } + if m1 != nil { + continue + } + m.Id = 0 + m.Workstation = workstation + m.StartTime = startTime.Unix() + dao.NewNowCarDao().Create(m) + } else { + m2, err := dao.NewNowCarDao().GetBusy(shopName, workstation) + if err != nil { + log.Errorf("db error :%s", err.Error()) + continue + } + if m2 == nil || m2.EndTime != 0 { + continue + } + + m2.EndTime = time.Now().Unix() + err = dao.NewNowCarDao().Update(m2) + if err != nil { + log.Errorf("db error :%s", err.Error()) + } + } + + } + + return nil, nil +} +func getDevId() ([]string, error) { + reqUrl := "https://wx.wdfcar.com/NowZiZhuXiCheApp/userSiteOrder/nearSite" + + params := make(url.Values) + params.Set("user_lng", "106.55072784423828") + params.Set("user_lat", "29.56471061706543") + + resp, err := http.Post(reqUrl, "application/x-www-form-urlencoded", + bytes.NewBuffer([]byte(params.Encode()))) + if err != nil { + log.Error("http poset error :%s", err.Error()) + return nil, err + } + defer resp.Body.Close() + rspbody, _ := io.ReadAll(resp.Body) + code := gjson.GetBytes(rspbody, "code").Int() + if code != 0 { + log.Errorf("rspbody error :%s", string(rspbody)) + return nil, fmt.Errorf("code is :%d", code) + } + + devids := make([]string, 0) + results := gjson.GetBytes(rspbody, "data").Array() + + for _, res := range results { + devId := res.Get("dev_id").String() + shopName := res.Get("addr_name").String() + log.Infof("shop=%s devid=%s", shopName, devId) + devids = append(devids, devId) + } + return devids, nil +} diff --git a/worker/worker.go b/worker/worker.go index 63a1200..e53ad7a 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -1,15 +1,12 @@ package worker import ( - "film/base/util" "film/config" "film/model" - "film/worker/common" - "film/worker/dadi" "film/worker/haha" - "fmt" + "film/worker/nowcar" + "github.com/go-co-op/gocron" log "github.com/sirupsen/logrus" - "github.com/smbrave/goutil" "gitlab.com/jiangyong27/gobase/wxapi" "strings" "time" @@ -18,9 +15,7 @@ import ( type Worker struct { qyClient *wxapi.WxQiye qyImpClient *wxapi.WxQiye - dadiProcessor common.Processor hahaProcessor *haha.Processor - notifyMap map[string]int64 } func (w *Worker) initQyWeixin() { @@ -37,151 +32,39 @@ func (w *Worker) initQyWeixin() { }) } -func (w *Worker) getOrderMesasge(order *model.Order) []string { - 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.MovieName)) - message = append(message, fmt.Sprintf("影厅:%s", order.Ting)) - message = append(message, fmt.Sprintf("时间:%s", time.Unix(order.ShowTime, 0).Format("2006-01-02 15:04"))) - 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.OrderNo)) - 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.OrderCreateTime, 0).Format("2006-01-02 15:04"))) - message = append(message, fmt.Sprintf("入库时间:%s", time.Unix(order.CreateTime, 0).Format("2006-01-02 15:04"))) - return message -} - -func (w *Worker) sendOrderMessage(order *model.Order, message string) { - messages := w.getOrderMesasge(order) - messages = append(messages, "\n", message) - w.qyClient.SendText(config.GetConfig().Weixin.Receiver, strings.Join(messages, "\n")) -} - -func (w *Worker) processorDadi(order *model.Order) { - checkInfo, err := w.dadiProcessor.CheckOrder(order) - if err != nil { - log.Errorf("check orrder[%s] error : %s", order.String(), err.Error()) - return - } - - cfg := config.GetDadiConfig() - bidStatus := false - realCost := int64(float64(checkInfo.TotalRealPrice) * cfg.Discount) - realUnitCost := realCost / int64(order.SeatNum) - bidPrice := realUnitCost + config.GetDadiConfig().BidProfit - if bidPrice < order.MaxPrice { - if err := w.hahaProcessor.BidPrice(order.Id, bidPrice); err != nil { - log.Errorf("BidPrice order[%s] error[%s]", order.String(), err.Error()) - if err := w.dadiProcessor.CancelOrder(order, checkInfo); err != nil { - log.Errorf("cancel order[%s] error[%s]", order.OrderNo, err.Error()) - } - message := w.getOrderMesasge(order) - message = append(message, "\n", fmt.Sprintf("竞价失败:%s", err.Error())) - w.qyClient.SendText(config.GetConfig().Weixin.Receiver, strings.Join(message, "\n")) - return - } - bidStatus = true - } - - // 发送信息 - message := w.getOrderMesasge(order) - - message = append(message, "\n") - message = append(message, "【大地订单信息】") - message = append(message, fmt.Sprintf("订单原价:%s", util.MoneyFen(checkInfo.TotalOriginPrice))) - message = append(message, fmt.Sprintf("优惠金额:%s", util.MoneyFen(checkInfo.CouponPrice))) - message = append(message, fmt.Sprintf("应付金额:%s", util.MoneyFen(checkInfo.TotalRealPrice))) - message = append(message, fmt.Sprintf("实际成本:%s", util.MoneyFen(realCost))) - message = append(message, fmt.Sprintf("实际单价:%s", util.MoneyFen(realUnitCost))) - - message = append(message, "\n") - message = append(message, "【竞价信息】") - message = append(message, fmt.Sprintf("状态:%s", goutil.If(bidStatus, "竞价中", "不可竞价"))) - message = append(message, fmt.Sprintf("出价:%s", util.MoneyFen(bidPrice))) - - w.qyClient.SendText(config.GetConfig().Weixin.Receiver, strings.Join(message, "\n")) - -} - -func (w *Worker) processBidWin() { - bidOrders, err := w.hahaProcessor.QueryBidWin() - if err != nil { - return - } - for _, o := range bidOrders { - order, err := model.GetOrder(o.OrderId) - if err != nil { - log.Errorf("get order error : %s", err.Error()) - continue - } - nowTime := time.Now().Unix() - if v, ok := w.notifyMap[order.OrderNo]; ok && nowTime-v < 300 { - continue - } - message := w.getOrderMesasge(order) - message = append(message, "\n") - message = append(message, "【竞价成功】") - message = append(message, fmt.Sprintf("出价:%s", util.MoneyFen(o.BidPrice))) - message = append(message, fmt.Sprintf("时间:%s", goutil.TimeToDateTime(o.BidTime))) - if err := w.qyImpClient.SendText(config.GetConfig().Weixin.Receiver, strings.Join(message, "\n")); err == nil { - w.notifyMap[order.OrderNo] = nowTime - } - } -} - func (w *Worker) Run() { + timezone, _ := time.LoadLocation("Asia/Shanghai") + cron := gocron.NewScheduler(timezone) + w.initQyWeixin() newOrderChan := make(chan *model.Order, 100000) updateOrderChan := make(chan *model.Order, 100000) hahaSyncer := haha.NewSyncOrder(&haha.SyncOrderConfig{ - Token: config.GetHahaConfig().Token, - NewOrder: newOrderChan, - UpdateOrder: updateOrderChan, - SyncInterval: config.GetHahaConfig().SyncInterval, + Token: config.GetHahaConfig().Token, + NewOrder: newOrderChan, + UpdateOrder: updateOrderChan, }) - hahaSyncer.Sync() - w.notifyMap = make(map[string]int64) + cron.Every(config.GetHahaConfig().SyncInterval).Seconds().Do(func() { + hahaSyncer.Sync() + }) - w.hahaProcessor = haha.NewProcessor(&haha.ProcessorConfig{Token: config.GetHahaConfig().Token}) - if config.GetDadiConfig().Enable { - dadiProcessor, err := dadi.NewProcessor(&dadi.ProcessorConfig{Token: config.GetDadiConfig().Token}) - if err != nil { - panic(err) - } - w.dadiProcessor = dadiProcessor - } + cron.Every(1).Minute().Do(func() { + nowcar.Sync() + }) - //order, _ := model.GetOrder(594315) - //_, err := w.dadiProcessor.CreateOrder(order) - //if err != nil { - //log.Errorf("create order[%s] error [%s]", order.String(), err.Error()) - //} - //newOrderChan <- order + cron.StartAsync() - bidUploadTimer := time.NewTicker(10 * time.Second) for { select { case order := <-newOrderChan: if !strings.Contains(order.CinemaName, "大地影院") { continue } - if config.GetDadiConfig().Enable { - w.processorDadi(order) - } case updateOrder := <-updateOrderChan: log.Tracef("%s update", updateOrder.String()) - case <-bidUploadTimer.C: - w.processBidWin() } }