From fe4f39f65da6d32376efb78ea6062f488a32cc9f Mon Sep 17 00:00:00 2001 From: Kailash Nadh Date: Wed, 26 Jun 2019 16:53:23 +0530 Subject: [PATCH] Replace viper with koanf --- go.mod | 7 ++-- go.sum | 39 ++++++++++----------- install.go | 5 ++- main.go | 82 +++++++++++++++++++++++++------------------- messenger/emailer.go | 14 ++++---- 5 files changed, 77 insertions(+), 70 deletions(-) diff --git a/go.mod b/go.mod index 2a2fc27..8dd93ac 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/knadh/listmonk require ( - github.com/BurntSushi/toml v0.3.1 // indirect github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf github.com/disintegration/imaging v1.5.0 github.com/jinzhu/gorm v1.9.1 github.com/jmoiron/sqlx v1.2.0 github.com/jordan-wright/email v0.0.0-20181027021455-480bedc4908b github.com/knadh/goyesql v1.1.1 + github.com/knadh/koanf v0.4.2 github.com/knadh/stuffbin v0.0.0-20190103171338-6379e949be48 github.com/labstack/echo v3.3.10+incompatible github.com/labstack/gommon v0.2.7 // indirect @@ -16,12 +16,11 @@ require ( github.com/mattn/go-isatty v0.0.4 // indirect github.com/satori/go.uuid v1.2.0 github.com/spf13/pflag v1.0.3 - github.com/spf13/viper v1.2.1 - github.com/stretchr/testify v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect - golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd + golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd // indirect golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b // indirect + golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 // indirect google.golang.org/appengine v1.4.0 // indirect gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b ) diff --git a/go.sum b/go.sum index 1860a28..cbcb1ad 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,16 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.5.0 h1:uYqUhwNmLU4K1FN44vhqS4TZJRAA4RhBINgbQlKyGi0= github.com/disintegration/imaging v1.5.0/go.mod h1:9B/deIUIrliYkyMTuXJd6OUFLcrZ2tf+3Qlwnaf/CjU= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -19,42 +22,34 @@ github.com/jordan-wright/email v0.0.0-20181027021455-480bedc4908b h1:veTPVnbkOij github.com/jordan-wright/email v0.0.0-20181027021455-480bedc4908b/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/knadh/goyesql v1.1.1 h1:iQLgsjYI/zC417DhmZYxmJgWmCHhtV4fho5QazWL/1g= github.com/knadh/goyesql v1.1.1/go.mod h1:W0tSzU8l7lYH1Fihj+bdQzkzOwvirrsMNHwkuY22qoY= +github.com/knadh/koanf v0.4.2 h1:A/bb9+eRoHHHQ57O6y66vzRCYui915CK3FdDYzNs56Q= +github.com/knadh/koanf v0.4.2/go.mod h1:Qd5yvXN39ZzjoRJdXMKN2QqHzQKhSx/K8fU5gyn4LPs= github.com/knadh/stuffbin v0.0.0-20190103171338-6379e949be48 h1:lRb28d0+iiVwqF7Li25IJXjNRaVCQPH6n/fHwk9Qo+E= github.com/knadh/stuffbin v0.0.0-20190103171338-6379e949be48/go.mod h1:afUOPBWr6bZ09aS3wbSOqXVGaO6rKcyvXYTcuG9LYpI= -github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4= -github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= github.com/labstack/gommon v0.2.7 h1:2qOPq/twXDrQ6ooBGrn3mrmVOC+biLlatwgIu8lbzRM= github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I= -github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.2.1 h1:bIcUwXqLseLF3BDAZduuNfekWG87ibtFxi59Bq+oI9M= -github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -69,9 +64,11 @@ golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBm golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b h1:P+3+n9hUbqSDkSdtusWHVPQRrpRpLiLFzlZ02xXskM0= gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b/go.mod h1:0LRKfykySnChgQpG3Qpk+bkZFWazQ+MMfc5oldQCwnY= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/install.go b/install.go index 8cd1dda..400ce24 100644 --- a/install.go +++ b/install.go @@ -10,7 +10,6 @@ import ( "github.com/knadh/listmonk/models" "github.com/lib/pq" uuid "github.com/satori/go.uuid" - "github.com/spf13/viper" ) // install runs the first time setup of creating and @@ -19,7 +18,7 @@ func install(app *App, qMap goyesql.Queries) { fmt.Println("") fmt.Println("** First time installation **") fmt.Printf("** IMPORTANT: This will wipe existing listmonk tables and types in the DB '%s' **", - viper.GetString("db.database")) + ko.String("db.database")) fmt.Println("") var ok string @@ -84,7 +83,7 @@ func install(app *App, qMap goyesql.Queries) { } logger.Printf("Setup complete") - logger.Printf(`Run the program view it at %s`, viper.GetString("app.address")) + logger.Printf(`Run the program view it at %s`, ko.String("app.address")) } diff --git a/main.go b/main.go index c3be7e3..58fa6e8 100644 --- a/main.go +++ b/main.go @@ -12,13 +12,16 @@ import ( _ "github.com/jinzhu/gorm/dialects/postgres" "github.com/jmoiron/sqlx" "github.com/knadh/goyesql" + "github.com/knadh/koanf" + "github.com/knadh/koanf/parsers/toml" + "github.com/knadh/koanf/providers/file" + "github.com/knadh/koanf/providers/posflag" "github.com/knadh/listmonk/manager" "github.com/knadh/listmonk/messenger" "github.com/knadh/listmonk/subimporter" "github.com/knadh/stuffbin" "github.com/labstack/echo" flag "github.com/spf13/pflag" - "github.com/spf13/viper" ) type constants struct { @@ -45,39 +48,42 @@ type App struct { Messenger messenger.Messenger } -var logger *log.Logger +var ( + // Global logger. + logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) -func init() { - logger = log.New(os.Stdout, "SYS: ", log.Ldate|log.Ltime|log.Lshortfile) + // Global configuration reader. + ko = koanf.New(".") +) +func initConfig(ko *koanf.Koanf) error { // Register --help handler. - flagSet := flag.NewFlagSet("config", flag.ContinueOnError) - flagSet.Usage = func() { - fmt.Println(flagSet.FlagUsages()) + f := flag.NewFlagSet("config", flag.ContinueOnError) + f.Usage = func() { + fmt.Println(f.FlagUsages()) os.Exit(0) } // Setup the default configuration. - viper.SetConfigName("config") - flagSet.StringSlice("config", []string{"config.toml"}, + f.StringSlice("config", []string{"config.toml"}, "Path to one or more config files (will be merged in order)") - flagSet.Bool("install", false, "Run first time installation") - flagSet.Bool("version", false, "Current version of the build") + f.Bool("install", false, "Run first time installation") + f.Bool("version", false, "Current version of the build") // Process flags. - flagSet.Parse(os.Args[1:]) - viper.BindPFlags(flagSet) + f.Parse(os.Args[1:]) - // Read the config files. - cfgs := viper.GetStringSlice("config") - for _, c := range cfgs { - logger.Printf("reading config: %s", c) - viper.SetConfigFile(c) - - if err := viper.MergeInConfig(); err != nil { - logger.Fatalf("error reading config: %s", err) + // Load config files. + cFiles, _ := f.GetStringSlice("config") + for _, f := range cFiles { + log.Printf("reading config: %s", f) + if err := ko.Load(file.Provider(f), toml.Parser()); err != nil { + return err } } + ko.Load(posflag.Provider(f, ".", ko), nil) + + return nil } // initFileSystem initializes the stuffbin FileSystem to provide @@ -116,14 +122,14 @@ func initFileSystem(binPath string) (stuffbin.FileSystem, error) { func initMessengers(r *manager.Manager) messenger.Messenger { // Load SMTP configurations for the default e-mail Messenger. var srv []messenger.Server - for name := range viper.GetStringMapString("smtp") { - if !viper.GetBool(fmt.Sprintf("smtp.%s.enabled", name)) { + for _, name := range ko.MapKeys("smtp") { + if !ko.Bool(fmt.Sprintf("smtp.%s.enabled", name)) { logger.Printf("skipped SMTP: %s", name) continue } var s messenger.Server - viper.UnmarshalKey("smtp."+name, &s) + ko.Unmarshal("smtp."+name, &s) s.Name = name s.SendTimeout = s.SendTimeout * time.Millisecond srv = append(srv, s) @@ -143,20 +149,26 @@ func initMessengers(r *manager.Manager) messenger.Messenger { } func main() { + // Load config into the global conf. + if err := initConfig(ko); err != nil { + logger.Printf("error reading config: %v", err) + os.Exit(1) + } + // Connect to the DB. - db, err := connectDB(viper.GetString("db.host"), - viper.GetInt("db.port"), - viper.GetString("db.user"), - viper.GetString("db.password"), - viper.GetString("db.database"), - viper.GetString("db.ssl_mode")) + db, err := connectDB(ko.String("db.host"), + ko.Int("db.port"), + ko.String("db.user"), + ko.String("db.password"), + ko.String("db.database"), + ko.String("db.ssl_mode")) if err != nil { logger.Fatalf("error connecting to DB: %v", err) } defer db.Close() var c constants - viper.UnmarshalKey("app", &c) + ko.Unmarshal("app", &c) c.RootURL = strings.TrimRight(c.RootURL, "/") c.UploadURI = filepath.Clean(c.UploadURI) c.UploadPath = filepath.Clean(c.UploadPath) @@ -187,7 +199,7 @@ func main() { } // Run the first time installation. - if viper.GetBool("install") { + if ko.Bool("install") { install(app, qMap) return } @@ -222,8 +234,8 @@ func main() { return sendNotification(notifTplCampaign, subject, data, app) } m := manager.New(manager.Config{ - Concurrency: viper.GetInt("app.concurrency"), - MaxSendErrors: viper.GetInt("app.max_send_errors"), + Concurrency: ko.Int("app.concurrency"), + MaxSendErrors: ko.Int("app.max_send_errors"), FromEmail: app.Constants.FromEmail, // url.com/unsubscribe/{campaign_uuid}/{subscriber_uuid} @@ -273,5 +285,5 @@ func main() { srv.GET("/frontend/*", echo.WrapHandler(fSrv)) srv.Static(c.UploadURI, c.UploadURI) registerHandlers(srv) - srv.Logger.Fatal(srv.Start(viper.GetString("app.address"))) + srv.Logger.Fatal(srv.Start(ko.String("app.address"))) } diff --git a/messenger/emailer.go b/messenger/emailer.go index 8e03093..7ffacb2 100644 --- a/messenger/emailer.go +++ b/messenger/emailer.go @@ -14,13 +14,13 @@ const emName = "email" // Server represents an SMTP server's credentials. type Server struct { Name string - Host string `mapstructure:"host"` - Port int `mapstructure:"port"` - AuthProtocol string `mapstructure:"auth_protocol"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - SendTimeout time.Duration `mapstructure:"send_timeout"` - MaxConns int `mapstructure:"max_conns"` + Host string `koanf:"host"` + Port int `koanf:"port"` + AuthProtocol string `koanf:"auth_protocol"` + Username string `koanf:"username"` + Password string `koanf:"password"` + SendTimeout time.Duration `koanf:"send_timeout"` + MaxConns int `koanf:"max_conns"` mailer *email.Pool }