From 85bc78d965f93f1680a059d0628fcae857a6c118 Mon Sep 17 00:00:00 2001 From: appolli Date: Sat, 17 Aug 2024 20:02:49 +0800 Subject: [PATCH] =?UTF-8?q?golang=E8=BF=81=E7=A7=BBChannel=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main_program/common/Constant.go | 8 ++ main_program/config.yml | 12 ++ main_program/config/EnvConfig.go | 25 ++++ main_program/config/config.go | 139 ++++++++++++++++++++++ main_program/entity/Channel.go | 23 ++++ main_program/go.mod | 27 +++++ main_program/go.sum | 43 +++++++ main_program/main.go | 45 +++++++ main_program/moveData/channel_region.xlsx | Bin 0 -> 20574 bytes main_program/moveData/moveDataService.go | 105 ++++++++++++++++ 10 files changed, 427 insertions(+) create mode 100644 main_program/common/Constant.go create mode 100644 main_program/config.yml create mode 100644 main_program/config/EnvConfig.go create mode 100644 main_program/config/config.go create mode 100644 main_program/entity/Channel.go create mode 100644 main_program/go.mod create mode 100644 main_program/go.sum create mode 100644 main_program/main.go create mode 100644 main_program/moveData/channel_region.xlsx create mode 100644 main_program/moveData/moveDataService.go diff --git a/main_program/common/Constant.go b/main_program/common/Constant.go new file mode 100644 index 0000000..e5e901a --- /dev/null +++ b/main_program/common/Constant.go @@ -0,0 +1,8 @@ +package common + +import ( + config "main_program/config" +) + +var ConfigFile string +var MyEnv config.EnvConfig diff --git a/main_program/config.yml b/main_program/config.yml new file mode 100644 index 0000000..c333a89 --- /dev/null +++ b/main_program/config.yml @@ -0,0 +1,12 @@ +log: + logenv: dev + logpath: main_program +command: move_data +movedata: + table: Channel + dbpath: D:/Work/Code/youtube_dev/youtube_prod.db +mysql: + host: 47.108.20.249:3306 + user: root + password: casino888! + database: youtube \ No newline at end of file diff --git a/main_program/config/EnvConfig.go b/main_program/config/EnvConfig.go new file mode 100644 index 0000000..258caca --- /dev/null +++ b/main_program/config/EnvConfig.go @@ -0,0 +1,25 @@ +package config + +type EnvConfig struct { + Log LogEntity + Command string + MoveData MoveDataEntity + Mysql MysqlEntity +} + +type LogEntity struct { + LogEnv string + LogPath string +} + +type MoveDataEntity struct { + Table string + DBPath string +} + +type MysqlEntity struct { + Host string + User string + Password string + Database string +} diff --git a/main_program/config/config.go b/main_program/config/config.go new file mode 100644 index 0000000..5cccd8d --- /dev/null +++ b/main_program/config/config.go @@ -0,0 +1,139 @@ +package config + +import ( + "bytes" + "fmt" + "io" + "os" + "path" + "time" + + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "github.com/logrusorgru/aurora" + "github.com/rifflock/lfshook" + "github.com/sirupsen/logrus" +) + +const ( + maxAgeHour = 168 + rotationHour = 24 +) + +var isInit bool +var Logger *logrus.Logger + +func init() { + isInit = false +} + +func checkInitLog() bool { + return isInit +} + +func InitConfig(logEnv string, logPath string) { + + if checkInitLog() { + return + } + Logger = initLogger(logEnv, logPath) +} + +func initLogger(env string, logPath string) *logrus.Logger { + logFilePath := "" + errFilePath := "" + if dir, err := os.Getwd(); err == nil { + logFilePath = dir + "/logs/" + logPath + "/all.log" + errFilePath = dir + "/logs/" + logPath + "/error.log" + } + + accessWriter, err := rotatelogs.New( + logFilePath+".%Y-%m-%d", + rotatelogs.WithLinkName(logFilePath), + rotatelogs.WithRotationTime(time.Hour*rotationHour), + rotatelogs.WithMaxAge(time.Hour*maxAgeHour), + ) + if err != nil { + panic(err) + } + errorWriter, err := rotatelogs.New( + errFilePath+".%Y-%m-%d", + rotatelogs.WithLinkName(errFilePath), + rotatelogs.WithRotationTime(time.Hour*rotationHour), + rotatelogs.WithMaxAge(time.Hour*maxAgeHour), + ) + if err != nil { + panic(err) + } + allWriter := io.MultiWriter(accessWriter, errorWriter) + //实例化 + logger := logrus.New() + logger.Out = os.Stdout + //设置日志格式 + logger.SetFormatter(&ConsoleFormatter{}) + logger.SetReportCaller(true) + //设置输出 + if env != "dev" { + logger.AddHook(lfshook.NewHook( + lfshook.WriterMap{ + logrus.DebugLevel: accessWriter, + logrus.InfoLevel: accessWriter, + logrus.ErrorLevel: allWriter, + logrus.PanicLevel: allWriter, + }, + &SaveFormatter{}, + )) + } + //设置日志级别 + logger.SetLevel(logrus.DebugLevel) + Logger = logger + isInit = true + return logger +} + +type ConsoleFormatter struct { +} + +func (m *ConsoleFormatter) Format(entry *logrus.Entry) ([]byte, error) { + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + timestamp := entry.Time.Format("2006-01-02 15:04:05") + var newLog string + var levelString aurora.Value + switch entry.Level.String() { + case "info": + levelString = aurora.Green(entry.Level) + case "warning": + levelString = aurora.Yellow(entry.Level) + case "debug": + levelString = aurora.Gray(16-1, entry.Level) + case "error": + levelString = aurora.Red(entry.Level) + case "fatal": + levelString = aurora.Red(entry.Level) + case "panic": + levelString = aurora.Red(entry.Level) + } + newLog = fmt.Sprintf("[%s] [%s:%d] [%s] %s \n", timestamp, path.Base(entry.Caller.File), entry.Caller.Line, levelString, entry.Message) + b.WriteString(newLog) + return b.Bytes(), nil +} + +type SaveFormatter struct { +} + +func (m *SaveFormatter) Format(entry *logrus.Entry) ([]byte, error) { + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + timestamp := entry.Time.Format("2006-01-02 15:04:05") + newLog := fmt.Sprintf("[%s] [%s:%d] [%s] %s \n", timestamp, path.Base(entry.Caller.File), entry.Caller.Line, entry.Level, entry.Message) + b.WriteString(newLog) + return b.Bytes(), nil +} diff --git a/main_program/entity/Channel.go b/main_program/entity/Channel.go new file mode 100644 index 0000000..9f71700 --- /dev/null +++ b/main_program/entity/Channel.go @@ -0,0 +1,23 @@ +package entity + +type ChannelCopy struct { + Id int + ChannelId string + ChannelTitle string + ChannelLanguage string + ChannelReptileTime *string + Is_Copy int +} + +type Channel struct { + Id uint `gorm:"column:id;primaryKey;autoIncrement"` + ChannelId string `gorm:"column:channelId;type:varchar(255);not null"` + ChannelTitle string `gorm:"column:channelTitle;type:varchar(255);not null"` + ChannelLanguage string `gorm:"column:channelLanguage;type:varchar(255);not null"` + ChannelReptileTime *string `gorm:"column:channelReptileTime;type:varchar(255);default:null"` + Region string `gorm:"column:region;type:varchar(255);default:null"` +} + +func (Channel) TableName() string { + return "Channel" +} diff --git a/main_program/go.mod b/main_program/go.mod new file mode 100644 index 0000000..1d8905f --- /dev/null +++ b/main_program/go.mod @@ -0,0 +1,27 @@ +module main_program + +go 1.22.2 + +require ( + github.com/sirupsen/logrus v1.9.3 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/lestrrat-go/strftime v1.0.6 // indirect + github.com/pkg/errors v0.9.1 // indirect + gorm.io/gorm v1.25.7 // indirect +) + +require ( + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/logrusorgru/aurora v2.0.3+incompatible + github.com/mattn/go-sqlite3 v1.14.22 + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 + github.com/tealeg/xlsx v1.0.5 + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + gorm.io/driver/mysql v1.5.7 +) diff --git a/main_program/go.sum b/main_program/go.sum new file mode 100644 index 0000000..6f1e56d --- /dev/null +++ b/main_program/go.sum @@ -0,0 +1,43 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= +github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE= +github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/main_program/main.go b/main_program/main.go new file mode 100644 index 0000000..41f38d7 --- /dev/null +++ b/main_program/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + + common "main_program/common" + "main_program/config" + move_data "main_program/moveData" + + "gopkg.in/yaml.v2" +) + +func init() { + flag.StringVar(&common.ConfigFile, "cf", "config.yml", "配置文件名") +} + +func main() { + flag.Parse() + //读取配置文件 + data, _ := ioutil.ReadFile(common.ConfigFile) + err := yaml.Unmarshal(data, &common.MyEnv) + if err != nil { + fmt.Println("读取配置文件错误...") + return + } + config.InitConfig(common.MyEnv.Log.LogEnv, common.MyEnv.Log.LogPath) + config.Logger.Info("初始化Logger成功...") + // 判断command + command := common.MyEnv.Command + config.Logger.Infof("Command:%s", common.MyEnv.Command) + if command == "move_data" { + // 判断参数 + table := common.MyEnv.MoveData.Table + dbPath := common.MyEnv.MoveData.DBPath + if table == "" || dbPath == "" { + config.Logger.Error("move_data配置文件错误...") + return + } + config.Logger.Infof("开始调用move_data方法") + move_data.MoveDataService.Start(table, dbPath, common.MyEnv.Mysql) + } + +} diff --git a/main_program/moveData/channel_region.xlsx b/main_program/moveData/channel_region.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fae3d69b8df9b259f726dd1f365495aa38e3a018 GIT binary patch literal 20574 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 Mu~X;io6vOs0=@GrhX4Qo literal 0 HcmV?d00001 diff --git a/main_program/moveData/moveDataService.go b/main_program/moveData/moveDataService.go new file mode 100644 index 0000000..40171dc --- /dev/null +++ b/main_program/moveData/moveDataService.go @@ -0,0 +1,105 @@ +package move_data + +import ( + "container/list" + "database/sql" + "fmt" + "main_program/config" + "main_program/entity" + + _ "github.com/mattn/go-sqlite3" + "github.com/tealeg/xlsx" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +type moveDataService struct{} + +var MoveDataService moveDataService + +func (m *moveDataService) Start(table string, sqlitePath string, mysqlConfig config.MysqlEntity) { + config.Logger.Info("开始迁移sqlite3到mysql") + sqliteDB, err := sql.Open("sqlite3", sqlitePath) + if err != nil { + config.Logger.Fatal(err) + } + config.Logger.Info("连接成功sqlite3...") + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", mysqlConfig.User, mysqlConfig.Password, mysqlConfig.Host, mysqlConfig.Database) + mysqlDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + config.Logger.Fatal("数据库连接失败") + } + config.Logger.Info("连接成功mysql...") + if table == "Channel" { + m.moveChannel(sqliteDB, mysqlDB) + } +} + +func (m *moveDataService) moveChannel(sqliteDB *sql.DB, mysqlDB *gorm.DB) { + config.Logger.Info("读取xlsx获取region") + file, err := xlsx.OpenFile("D:/Work/Code/youtube_dev/youtube-golang/main_program/moveData/channel_region.xlsx") + if err != nil { + config.Logger.Fatalf("Error opening file: %s", err) + } + config.Logger.Info("开始迁移Channel表") + // 从sqlite3获取前50个Channel + continueFlag := true + for continueFlag { + rows, err := sqliteDB.Query("SELECT * FROM Channel_copy WHERE is_copy = 0 limit 50") + if err != nil { + config.Logger.Fatal(err) + } + ChannelList := list.New() + for rows.Next() { + channelCopy := new(entity.ChannelCopy) + if err := rows.Scan(&channelCopy.Id, &channelCopy.ChannelId, &channelCopy.ChannelTitle, &channelCopy.ChannelLanguage, &channelCopy.ChannelReptileTime, &channelCopy.Is_Copy); err != nil { + config.Logger.Fatal(err) + } + ChannelList.PushBack(channelCopy) + } + rows.Close() + if ChannelList.Len() <= 0 { + break + } + // 放入mysql里 + for e := ChannelList.Front(); e != nil; e = e.Next() { + channelCopy := e.Value.(*entity.ChannelCopy) + config.Logger.Info(channelCopy) + channel := new(entity.Channel) + channel.ChannelId = channelCopy.ChannelId + channel.ChannelTitle = channelCopy.ChannelTitle + channel.ChannelLanguage = channelCopy.ChannelLanguage + channel.ChannelReptileTime = channelCopy.ChannelReptileTime + channel.Region = m.getRegionByChannelId(channel.ChannelId, file) + result := mysqlDB.Create(&channel) + if result.Error != nil { + config.Logger.Fatal(result.Error) + } + // 修改sqlite里状态 + sqlStr, err := sqliteDB.Prepare("UPDATE Channel_copy SET is_copy = 1 WHERE id = ?") + if err != nil { + config.Logger.Error(err) + } + _, err = sqlStr.Exec(channelCopy.Id) + if err != nil { + config.Logger.Error(err) + } + sqlStr.Close() + } + tmpRows, _ := sqliteDB.Query("SELECT * FROM Channel_copy WHERE is_copy = 0 limit 50") + continueFlag = tmpRows.Next() + tmpRows.Close() + } + +} + +func (m *moveDataService) getRegionByChannelId(channnelId string, file *xlsx.File) string { + for _, sheet := range file.Sheets { + for _, row := range sheet.Rows { + if row.Cells[3].Value == channnelId { + return row.Cells[2].Value + } + } + } + return "" +}