mirror of http://gitlab.batiao8.com/yic/film.git
init
This commit is contained in:
commit
6888a8a813
|
@ -0,0 +1,12 @@
|
||||||
|
*.iml
|
||||||
|
.idea/
|
||||||
|
output/
|
||||||
|
dockerfiles/
|
||||||
|
log
|
||||||
|
.DS_Store
|
||||||
|
web/node_modules
|
||||||
|
ad-api.exe
|
||||||
|
doc
|
||||||
|
cmd/test
|
||||||
|
go.sum
|
||||||
|
pkg
|
|
@ -0,0 +1,20 @@
|
||||||
|
FROM registry.cn-shanghai.aliyuncs.com/devcon/godev:v1.0.14
|
||||||
|
ADD . /app/src
|
||||||
|
WORKDIR /app/src
|
||||||
|
|
||||||
|
RUN mkdir -p /app/bin /app/log
|
||||||
|
|
||||||
|
RUN export GOROOT=/usr/local/go1.18.2 && \
|
||||||
|
export GOPROXY=https://goproxy.cn && \
|
||||||
|
export PATH=$PATH:$GOROOT/bin && \
|
||||||
|
go mod tidy && \
|
||||||
|
go build cmd/film.go && \
|
||||||
|
mv film /app/bin && \
|
||||||
|
cp -r conf /app && \
|
||||||
|
cp start.sh /app && \
|
||||||
|
chmod +x /app/start.sh
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 9263
|
||||||
|
|
||||||
|
CMD ["/app/start.sh"]
|
|
@ -0,0 +1,62 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"film/config"
|
||||||
|
"film/model"
|
||||||
|
"film/worker"
|
||||||
|
"fmt"
|
||||||
|
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||||
|
"github.com/rifflock/lfshook"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/smbrave/goutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initLog() {
|
||||||
|
cfg := config.GetConfig()
|
||||||
|
logfile := "log/server.log"
|
||||||
|
writer, err := rotatelogs.New(
|
||||||
|
logfile+".%Y%m%d",
|
||||||
|
rotatelogs.WithLinkName(logfile),
|
||||||
|
rotatelogs.WithMaxAge(time.Duration(86400*7)*time.Second),
|
||||||
|
rotatelogs.WithRotationTime(time.Duration(86400)*time.Second),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathMap := lfshook.WriterMap{
|
||||||
|
log.TraceLevel: writer,
|
||||||
|
log.DebugLevel: writer,
|
||||||
|
log.InfoLevel: writer,
|
||||||
|
log.WarnLevel: writer,
|
||||||
|
log.ErrorLevel: writer,
|
||||||
|
log.FatalLevel: writer,
|
||||||
|
log.PanicLevel: writer,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.AddHook(lfshook.NewHook(pathMap, new(goutil.LogFile)))
|
||||||
|
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
|
log.SetReportCaller(true)
|
||||||
|
log.SetFormatter(new(goutil.LogFile))
|
||||||
|
log.SetLevel(log.Level(cfg.Server.LogLevel))
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
config.LoadServerConfig()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &worker.Worker{
|
||||||
|
Token: config.GetConfig().Film.Token,
|
||||||
|
}
|
||||||
|
w.Init()
|
||||||
|
select {}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
[server]
|
||||||
|
address = "0.0.0.0:9263"
|
||||||
|
#0:PAINC 1:FATAL 2:ERROR 3:WARNING 4:INFO 5:DEBUG 6:TRACE
|
||||||
|
log_level = 6
|
||||||
|
|
||||||
|
|
||||||
|
[mysql]
|
||||||
|
host = "100.118.29.74"
|
||||||
|
port = 3307
|
||||||
|
user = "film"
|
||||||
|
pass = "7VCfJx7H8MymUm"
|
||||||
|
db = "film"
|
||||||
|
|
||||||
|
|
||||||
|
[film]
|
||||||
|
token = "cc5f1d4c36f7e9544d641a174b298f94"
|
|
@ -0,0 +1,12 @@
|
||||||
|
[server]
|
||||||
|
address = "0.0.0.0:9263"
|
||||||
|
#0:PAINC 1:FATAL 2:ERROR 3:WARNING 4:INFO 5:DEBUG 6:TRACE
|
||||||
|
log_level = 6
|
||||||
|
|
||||||
|
|
||||||
|
[mysql]
|
||||||
|
host = "192.168.13.213"
|
||||||
|
port = 3306
|
||||||
|
user = "film"
|
||||||
|
pass = "7VCfJx7H8MymUm"
|
||||||
|
db = "film"
|
|
@ -0,0 +1,93 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/smbrave/goutil"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
config *Config
|
||||||
|
configEnv string
|
||||||
|
BuildTime string
|
||||||
|
CommitId string
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mysql struct {
|
||||||
|
Host string `toml:"host"`
|
||||||
|
Port int `toml:"port"`
|
||||||
|
User string `toml:"user"`
|
||||||
|
Pass string `toml:"pass"`
|
||||||
|
Db string `toml:"db"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Address string `toml:"address"`
|
||||||
|
LogLevel int `toml:"log_level"`
|
||||||
|
EnableDoc bool `toml:"enable_doc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Redis struct {
|
||||||
|
Addr string `toml:"addr"`
|
||||||
|
Db int `toml:"db"`
|
||||||
|
Password string `toml:"password"`
|
||||||
|
}
|
||||||
|
type Film struct {
|
||||||
|
Token string `toml:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Server *Server `toml:"server"`
|
||||||
|
Mysql *Mysql `toml:"mysql"`
|
||||||
|
Redis *Redis `toml:"redis"`
|
||||||
|
Film *Film `toml:"film"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEnv() string {
|
||||||
|
return configEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsProdEnv() bool {
|
||||||
|
return configEnv == "prod"
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsDevEnv() bool {
|
||||||
|
return configEnv == "dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTestEnv() bool {
|
||||||
|
return configEnv == "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig() *Config {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadServerConfig() {
|
||||||
|
configEnv = os.Getenv("CONFIG_ENV")
|
||||||
|
if configEnv == "" {
|
||||||
|
configEnv = "dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
var envConfig Config
|
||||||
|
|
||||||
|
viper.SetConfigFile("conf/server.conf." + configEnv)
|
||||||
|
viper.SetConfigType("toml")
|
||||||
|
viper.AutomaticEnv()
|
||||||
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||||
|
viper.SetEnvPrefix("conf")
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := viper.Unmarshal(&envConfig, func(decoderConfig *mapstructure.DecoderConfig) {
|
||||||
|
decoderConfig.TagName = "toml"
|
||||||
|
}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config = &envConfig
|
||||||
|
log.Infof("load real config[%s] ", goutil.EncodeJSONIndent(config))
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
module film
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-co-op/gocron v1.19.0
|
||||||
|
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||||
|
github.com/sirupsen/logrus v1.9.0
|
||||||
|
github.com/smbrave/goutil v0.0.0-20230208141215-e3360c3bfd1b
|
||||||
|
github.com/spf13/cast v1.5.0
|
||||||
|
github.com/spf13/viper v1.15.0
|
||||||
|
gorm.io/driver/mysql v1.4.7
|
||||||
|
gorm.io/gorm v1.24.6
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.4.0 // indirect
|
||||||
|
github.com/lestrrat-go/strftime v1.0.6 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
|
github.com/spf13/afero v1.9.3 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
|
golang.org/x/sys v0.3.0 // indirect
|
||||||
|
golang.org/x/text v0.5.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,81 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
db *gorm.DB = nil
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetDb(b *gorm.DB) {
|
||||||
|
db = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOrm() *gorm.DB {
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
type DBLogger struct {
|
||||||
|
level logger.LogLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DBLogger) LogMode(level logger.LogLevel) logger.Interface {
|
||||||
|
d.level = level
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DBLogger) Info(context.Context, string, ...interface{}) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DBLogger) Warn(context.Context, string, ...interface{}) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DBLogger) Error(context.Context, string, ...interface{}) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DBLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
||||||
|
sql, affects := fc()
|
||||||
|
|
||||||
|
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() > 200 {
|
||||||
|
log.Errorf("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds())
|
||||||
|
} else {
|
||||||
|
log.Debugf("[SQL]sql=%s affect=%d cost=%dms", sql, affects, time.Since(begin).Milliseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(dsn string) (*gorm.DB, error) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
db.Logger = &DBLogger{}
|
||||||
|
return db, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ping() error {
|
||||||
|
d, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Ping(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tableNameOrder = "orders"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
Id int64
|
||||||
|
OrderId string
|
||||||
|
StartTime string
|
||||||
|
StartDate string
|
||||||
|
TotalPrice int64
|
||||||
|
PayPrice int64
|
||||||
|
MaoyanPrice int64
|
||||||
|
SeatNum int
|
||||||
|
Seats string
|
||||||
|
ShowTime int64
|
||||||
|
PayTime int64
|
||||||
|
CityName string
|
||||||
|
ProvinceName string
|
||||||
|
Ting string
|
||||||
|
CinemaName string
|
||||||
|
MovieName string
|
||||||
|
Address string
|
||||||
|
CreateTime int64
|
||||||
|
UpdateTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddOrder(o *Order) (int64, error) {
|
||||||
|
o.CreateTime = time.Now().Unix()
|
||||||
|
res := db.Table(tableNameOrder).Create(o)
|
||||||
|
return o.Id, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOrder(id int64) (*Order, error) {
|
||||||
|
var u Order
|
||||||
|
tx := db.Table(tableNameOrder)
|
||||||
|
tx = tx.Where("id = ?", id)
|
||||||
|
res := tx.First(&u)
|
||||||
|
if res.Error == gorm.ErrRecordNotFound {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Error != nil {
|
||||||
|
return nil, res.Error
|
||||||
|
}
|
||||||
|
return &u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateOrder(o *Order) error {
|
||||||
|
o.UpdateTime = time.Now().Unix()
|
||||||
|
tx := db.Table(tableNameOrder)
|
||||||
|
res := tx.Save(o)
|
||||||
|
return res.Error
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -x
|
||||||
|
ROOT=$(cd `dirname $0`; pwd)
|
||||||
|
cd $ROOT
|
||||||
|
|
||||||
|
if [ "$BINARY" = "" ];then
|
||||||
|
BINARY="film"
|
||||||
|
fi
|
||||||
|
|
||||||
|
while [ true ];do
|
||||||
|
$ROOT/bin/$BINARY $@ >> log/run.log 2>&1
|
||||||
|
/usr/local/bin/sendproxy weixin jiangyong "$CONFIG_ENV $BINARY 服务崩溃[`date +"%Y-%m-%d %H:%M:%S"`]"
|
||||||
|
sleep 60
|
||||||
|
done
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package worker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"film/model"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-co-op/gocron"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Worker struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) Init() error {
|
||||||
|
timezone, _ := time.LoadLocation("Asia/Shanghai")
|
||||||
|
cron := gocron.NewScheduler(timezone)
|
||||||
|
|
||||||
|
cron.Every(30).Seconds().Do(func() {
|
||||||
|
w.syncOrder()
|
||||||
|
})
|
||||||
|
|
||||||
|
cron.StartAsync()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) 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 *Worker) syncOrder() {
|
||||||
|
orderUrl := "https://hahapiao.cn/api/Synchro/toList"
|
||||||
|
body, err := w.httpPost(orderUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("syncOrder error : %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
datas := cast.ToSlice(result["data"])
|
||||||
|
|
||||||
|
for _, d := range datas {
|
||||||
|
data := cast.ToStringMap(d)
|
||||||
|
id := cast.ToInt64(data["id"])
|
||||||
|
order, err := model.GetOrder(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("get order id : %d error :%s", id, err.Error())
|
||||||
|
}
|
||||||
|
isAdd := false
|
||||||
|
|
||||||
|
if order == nil {
|
||||||
|
order = new(model.Order)
|
||||||
|
order.Id = id
|
||||||
|
isAdd = true
|
||||||
|
}
|
||||||
|
order.OrderId = cast.ToString(data["order_id"])
|
||||||
|
order.PayPrice = int64(cast.ToFloat64(data["payPrice"]) * 100)
|
||||||
|
order.TotalPrice = int64(cast.ToFloat64(data["total_price"]) * 100)
|
||||||
|
order.MaoyanPrice = int64(cast.ToFloat64(data["maoyan_price"]) * 100)
|
||||||
|
order.StartTime = cast.ToString(data["startTime"])
|
||||||
|
order.StartDate = cast.ToString(data["invalidateDate"])
|
||||||
|
order.SeatNum = cast.ToInt(data["seat_num"])
|
||||||
|
order.Seats = cast.ToString(data["seats"])
|
||||||
|
order.ShowTime = cast.ToInt64(data["show_time"])
|
||||||
|
order.PayTime = cast.ToInt64(data["pay_time"])
|
||||||
|
order.CityName = cast.ToString(data["cityName"])
|
||||||
|
order.ProvinceName = cast.ToString(data["provinceName"])
|
||||||
|
order.MovieName = cast.ToString(data["movieName"])
|
||||||
|
order.Address = cast.ToString(data["address"])
|
||||||
|
order.Ting = cast.ToString(data["ting"])
|
||||||
|
|
||||||
|
if isAdd {
|
||||||
|
model.AddOrder(order)
|
||||||
|
} else {
|
||||||
|
model.UpdateOrder(order)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue