Djam36
@Djam36

Как инициализировать конфиг для всего проекта?

Привет возник у меня один вопрос, есть проект с множеством пакетов и go файлов, в некоторых из них есть вызов данных из конфига, для парсинга конфигов используется отдельный файл, как мне инициализировать конфиг что бы можно было его использовать во всех файлах проекта?
Накидал примерчик
-- Парсинг конфига
package controllers

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"

	"gopkg.in/yaml.v2"
)

var config = "./conf.yml"

type Serverconfig struct {
	Port         string `yaml:"Port"`
	ReadTimeout  int    `yaml:"ReadTimeout"`
	WriteTimeout int    `yaml:"WriteTimeout"`
}

func (s *Serverconfig) validate() func() {
	fmt.Println("Parsing Config", config)
	return func() {
		if s.Port == "" {
			log.Fatal("Config Pars ERROR Port Required ", s.Port)
		}
		if s.ReadTimeout == 0 {
			log.Fatal("Config Pars ERROR ReadTimeout Requierd", s.ReadTimeout)
		}
		if s.WriteTimeout == 0 {
			log.Fatal("Config Pars ERROR WriteTimeout Requierd", s.WriteTimeout)
		}
	}
}

func Pars() *Serverconfig {
	config, error := filepath.Abs(config)
	if error != nil {
		log.Panic("ERROR: ", error)
	}
	yamlFile, error := ioutil.ReadFile(config)
	if error != nil {
		log.Panic("ERROR: ", error)
	}

	Serverconfig := Serverconfig{}
	error = yaml.Unmarshal(yamlFile, &Serverconfig)
	f := Serverconfig.validate()
	f()
	fmt.Println("Start server with parametrs\nServer Port" + Serverconfig.Port)
	if error != nil {
		log.Fatal(error)
	}
	return &Serverconfig

}


-- Main.GO
package main

import (
	"fmt"
	"gobots/route"
	"gowiki/controllers"
	"html/template"
	"log"
	"net/http"
	"time"
)

func main() {
	Serverconfig := controllers.Pars()
	handler := http.NewServeMux()
	handler.HandleFunc("/register/", register)
	s := http.Server{
		Addr:         Serverconfig.Port,
		Handler:      handler,
		ReadTimeout:  time.Duration(Serverconfig.ReadTimeout) * time.Second,
		WriteTimeout: time.Duration(Serverconfig.WriteTimeout) * time.Second,
	}
	log.Fatal(s.ListenAndServe())
}
func register(responseW http.ResponseWriter, request *http.Request) {
	if request.Method == "GET" {
		t, error := template.ParseFiles("templates/main.html")
		if error != nil {
			http.Error(responseW, error.Error(), 400)
			return
		}
		if err := t.Execute(responseW, nil); err != nil {
			fmt.Println(err)
			return
		}
	} else {
		route.Register(responseW, request)
		http.Redirect(responseW, request, "/home/", 302)
	}

}

здесь я в main функции его инициализирую и могу пользоваться соответственно только в main функции.., в других местах конфиг становится не доступным, только если не вызывать его как показано тут
ontrollers.Pars().MyVar
но это вообще как-то не правильно и не красиво и так не должно быть, может уже есть где-то на просторах интернета ответ на мой вопрос, пытался это сделать с помощью init() но что-то не вышло
  • Вопрос задан
  • 180 просмотров
Пригласить эксперта
Ответы на вопрос 1
@mr-spouk
В Go один из вариантов использование обобщенной структуры, в которой связываются остальные компоненты и модули. Для примера с собственного проекта пример обобщенной структуры
type Server struct {
	sync.WaitGroup
	Mux          *chi.Mux
	Log          *log.Logger
	LogFile      *log.Logger
	DB           *gorm.DB
	Render       *render.Render
	Convert      *convert.Convert
	Transliter   *transliter.Transliter
	Mailer       *mailer.Mail
	Flash        *flash.Flash
	Config       *Config
	StaticStock  map[string]string //key = filesDir, []string = workDir
	pool         sync.Pool
	Forms        *forms.Form
	Support      *support.Support
	LogReaders   []LogReader
	LogStock     []string
	LogFH        *os.File
	Paginator    *paginate.Paginate
	Gobdump      *gobdump.Configdump
	ConfigOrigin *Config
	Uploader     *uploader.Uploader
	Datetime    *Datetime
}
//иницализация для примера 
func NewServer(originConfigUse bool) *Server {
	//instance
	s := new(Server)
	//logger
	s.Log = log.New(os.Stdout, SERVER, log.Ldate|log.Ltime|log.Lshortfile)
	//gobdump
	s.Gobdump = gobdump.NewConfigdump()
	//config
	cc := config.NewConf("config/dumpconfig.dmp", os.Stdout)
	ci := new(Config)
	if err := cc.ReadConfig("config/config.yaml", ci); err != nil {
		s.Log.Fatal(err)
	}
	s.Config = ci

	//assign config intance to SERVER
	if originConfigUse == false {
		s.ConfigOrigin = ci
		s.Config = s.ConfigDumpRead(false)
	}
	//logfile
	err := s.openLogs("logs")
	if err != nil {
		panic(err)
	}
	s.LogFile = log.New(s.LogFH, SERVER, log.Ldate|log.Ltime|log.Lshortfile)
	//database

	s.DatabaseConnect(ListTables)
	//render
	s.Render = render.NewRender(s.Config.TemplatePath, s.Config.TemplateDebug, s.Log, s.Config.TemplateDebugFatal)
	//add user functions
	s.Render.AddUserFilter("loop", s.Loop)
	s.Render.AddUserFilter("loopstr", s.LoopStr)
	s.Render.AddUserFilter("addstr", s.AddStr)
	//s.Render.AddUserFilter("substr", s.SubStr)
	//s.Render.AddUserFilter("intstr", s.IntToStr)
	//transliter
	s.Transliter = transliter.NewTransliter()
	//mailer
	s.Mailer = mailer.NewMail()
	//flash
	s.Flash = flash.NewFlash(s.Config.FlashSalt)
	//converter
	s.Convert = convert.NewConverter(s.Log)
	//staticstock
	s.StaticStock = make(map[string]string)
	//chi router
	s.Mux = chi.NewRouter()

	//pool
	s.pool = sync.Pool{}
	s.pool.New = func() interface{} {
		return &Data{
			Server: s,
			Flash:  flash.NewFlash(s.Config.FlashSalt),
			Stock:  databox.NewData(),
		}
	}
	//forms
	s.Forms = forms.NewForm()
	s.Forms.LoadFieldForms(formsdata)
	//support
	s.Support = support.NewSupport()
	//добавление админа по умолчанию на основе данных из конфига
	if err := s.addDefaultAdmin(); err != nil {
		s.Log.Fatal(err)
	}
	//запуск горутин
	s.Add(2)
	go s.gorExpiredLogedUser(time.Minute * 60)
	go s.gorPulicatePostLaterData(time.Minute * 2)

	//paginator
	pagparams := &paginate.Params{
		Limit:      s.Config.PaginateCountOnPage,
		DBS:        s.DB,
		DebugQuery: s.Config.PaginateDebug,
		SortTypes:  s.Config.PaginateSortType,
		CountLinks: s.Config.PaginateCountLinks,
	}
	s.Paginator = paginate.NewPaginate(pagparams)

	//uploader
	s.Uploader = uploader.NewUploader()

	//datetime
	s.Datetime = NewDateTimeList(2019)

	//back result
	return s
}


Привязка конфига идет к ConfigOrigin *Config
Структура конфига + пакет для обработки его

package lib

import "time"

type Config struct {
	//global
	TemplatePath          string        `yaml:"templatepath"`
	TemplateDebug         bool          `yaml:"templatedebug"`
	TemplateDebugFatal    bool          `yaml:"teamplatedebugfatal"`
	AdressHTTP            string        `yaml:"adresshttp"`
	ReadTimeout           time.Duration `yaml:"readtimeout"`
	WriteTimeout          time.Duration `yaml:"writetimeout"`
	CertFile              string        `yaml:"certfile"`
	KeyFile               string        `yaml:"keyfile"`
	RedirectTrailingSlash bool          `yaml:"redirecttrailingslash"`
	RedirectFixedPath     bool          `yaml:"redirectfixedpath"`
	Logfile               string        `yaml:"logfile"`
	//roles
	Roles      []string `yaml:"roles"`
	RolesAdmin []string `yaml:"rolesadmin"`
	//database
	DBTypeDB             string `yaml:"dbtypedb"`
	DBHost               string `yaml:"dbhost"`
	DBPort               int    `yaml:"dbport"`
	DBUser               string `yaml:"dbuser"`
	DBPassword           string `yaml:"dbpassword"`
	DBDatabase           string `yaml:"dbdatabase"`
	DBSSLMode            bool   `yaml:"dbsslmode"`
	DBSetMaxIdleConns    int    `yaml:"dbsetmaxidleconns"`
	DBSetMaxOpenConns    int    `yaml:"dbsetmaxopenconns"`
	DBSetConnMaxLifetime int    `yaml:"dbsetconnmaxlifetime"`
	//project
	PaginateCountOnPage int      `yaml:"paginatecountonpage"`
	PaginateCountLinks  int      `yaml:"paginatecountlinks"`
	PaginateSortType    []string `yaml:"paginatesorttype"`
	PaginateDebug       bool     `yaml:"paginatedebug"`
	UploadPath          string   `yaml:"uploadpath"`
	SitemapPath         string   `yaml:"sitemappath"`
	SitemapHost         string   `yaml:"sitemaphost"`
	HostFullPathHTTP    string   `yaml:"hostfullpathhttp"`
	HostFullPathHTTPS   string   `yaml:"hostfullpathhttps"`
	SeoTitle            string   `yaml:"seotitle"`
	SeoDesc             string   `yaml:"seodesc"`
	SeoKeys             string   `yaml:"seokeys"`
	SeoRobot            string   `yaml:"seorobot"`
	LaterPostTimePeriod int      `yaml:"laterposttimeperiod"`
	//session
	MailTo               string        `yaml:"mailto"`
	MailFrom             string        `yaml:"mailfrom"`
	MailHost             string        `yaml:"mailhost"`
	MailPort             int           `yaml:"mailport"`
	MailUsername         string        `yaml:"mailusername"`
	MailPassword         string        `yaml:"mailpassword"`
	CSRFTimeActive       int           `yaml:"csrftimeactive"`
	CSRFSalt             string        `yaml:"csrfsalt"`
	CookieName           string        `yaml:"cookiename"`
	CookieDomain         string        `yaml:"cookiedomain"`
	CookieExpired        int64         `yaml:"cookieexpired"`
	CookieSalt           string        `yaml:"cookiesalt"`
	RoleDefaultUser      string        `yaml:"roledefaultuser"`
	SessionTime          time.Duration `yaml:"sessiontime"`
	SessionTimeExpired   time.Duration `yaml:"sessiontimeexpired"`
	SessionTimeSave      time.Duration `yaml:"sessiontimesave"`
	SessionPathSave      string        `yaml:"pathsavesession"`
	TimerTime            time.Duration `yaml:"timertime"`
	SleepTimeCatcher     time.Duration `yaml:"sleeptimecatcher"`
	DeferPostSleepTime   time.Duration `yaml:"deferpostsleeptime"`
	DeferPostTime        time.Duration `yaml:"deferposttime"`
	ContactReview        []string      `yaml:"contactreview"`
	FlashSalt            string        `yaml:"flashsatl"`
	DefaultUserCookie    string        `yaml:"defaultusercookie"`
	DefaultAdminEmail    string        `yaml:"defaultadminemail"`
	DefaultAdminPassword string        `yaml:"defaultadminpassword"`
	DefaultAdminRole     string        `yaml:"defaultadminrole"`
	RedisAdress          string        `yaml:"redisadress"`
	RedisDB              int           `yaml:"redisdb"`
	RedisPassword        string        `yaml:"redispassword"`
	DumpConfigFile       string        `yaml:"dumpconfigfile"`
	//oauth2 authorization
	// +vk+
	O2vkid       string `yaml:"o2vkid"`
	O2vkkey      string `yaml:"o2vkkey"`
	O2vkcallback string `yaml:"o2vkcallback"`
	o2vkscope    []string `yaml:"o2vkscope"`
	// +yandex+
	O2yandexid       string `yaml:"o2yandexid"`
	O2yandexkey      string `yaml:"o2yandexkey"`
	O2yandexcallback string `yaml:"o2yandexcallback"`
	o2yandexscope    []string `yaml:"o2yandexscope"`
	// +google+
	O2googleid       string   `yaml:"o2googleid"`
	O2googlekey      string   `yaml:"o2googlekey"`
	O2googlecallback string   `yaml:"o2googlecallback"`
	O2googlescope    []string `yaml"o2googlescope"`
}

package config

import (
	"os"
	"log"
	"io/ioutil"
	"encoding/gob"
	"github.com/go-yaml/yaml"
	"io"
)

const (
	logConfigPrefix           = "[config-log] "
	logConfigFlags            = log.Ldate | log.Ltime | log.Lshortfile
	msgsuccessReadDumpConfig  = "дамп конфига успешно прочитан"
	msgsuccessWriteDumpConfig = "дамп конфига успешно записан"

	dumpfileflag = os.O_CREATE | os.O_RDWR | os.O_TRUNC
	dumpfileperm = 0666
)

//---------------------------------------------------------------------------
//  example other config
//---------------------------------------------------------------------------
type Conf struct {
	Log            *log.Logger
	PathDumpconfig string
}

func (c *Conf) ReadConfig(fileConfig string, exConf interface{}) (error) {
	//открываю файл конфигурации
	f, err := os.Open(fileConfig)
	if err != nil {
		return err
	}
	//читаю файл конфига
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	//конвертирую его в структуру
	err = yaml.Unmarshal(b, exConf)
	if err != nil {
		return err
	}
	return nil
}
func NewConf(pathDumpconfig string, logout io.Writer) *Conf {
	n := &Conf{
		PathDumpconfig: pathDumpconfig,
	}
	if logout == nil {
		n.Log = log.New(os.Stdout, logConfigPrefix, logConfigFlags)
	} else {
		n.Log = log.New(logout, logConfigPrefix, logConfigFlags)
	}
	return n
}

//запись дампа конфигурационного файла
func (c *Conf) WriteDumpConfig(config interface{}) error {
	f, err := os.OpenFile(c.PathDumpconfig, dumpfileflag, dumpfileperm)
	if err != nil {
		return err
	}
	defer f.Close()
	enc := gob.NewEncoder(f)
	err = enc.Encode(config)
	if err != nil {
		return err
	}
	if c.Log != nil {
		c.Log.Printf(msgsuccessWriteDumpConfig)
		return err
	}
	return nil
}



//читаем дамп конфигурационного файла
func (c *Conf) ReadDumpConfig(config interface{}) (error) {
	f, err := os.Open(c.PathDumpconfig)
	if err != nil {
		return err
	}
	defer f.Close()
	dec := gob.NewDecoder(f)
	err = dec.Decode(config)
	if err != nil {
		return err
	}
	c.Log.Printf(msgsuccessReadDumpConfig)
	return nil
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы