package main import ( "errors" "gopkg.in/yaml.v2" "log" "os" "strings" "sync" ) var ( BlogUrl string MediaEndpointUrl string IgnoredWebmentionUrls []string SyndicationTargets []SyndicationTarget SelectedStorage Storage SelectedMediaStorage MediaStorage SelectedCdn Cdn SelectedNotificationServices NotificationServices SelectedImageCompression ImageCompression DefaultLanguage string Languages map[string]Language ) type SyndicationTarget struct { Uid string `json:"uid"` Name string `json:"name"` } type YamlConfig struct { BlogUrl string `yaml:"blogUrl"` BaseUrl string `yaml:"baseUrl"` MediaUrl string `yaml:"mediaUrl"` DefaultLanguage string `yaml:"defaultLang"` Languages map[string]Language `yaml:"languages"` Git GitConfig `yaml:"git"` BunnyCdn BunnyCdnConfig `yaml:"bunnyCdn"` Telegram TelegramConfig `yaml:"telegram"` Tinify TinifyConfig `yaml:"tinify"` IgnoredWebmentionUrls []string `yaml:"ignoreWebmention"` SyndicationTargets []string `yaml:"syndication"` } type BunnyCdnConfig struct { Key string `yaml:"key"` StorageKey string `yaml:"storageKey"` StorageName string `yaml:"storageName"` } type TelegramConfig struct { UserId int `yaml:"userId"` BotToken string `yaml:"botToken"` } type TinifyConfig struct { Key string `yaml:"key"` } type GitConfig struct { Filepath string `yaml:"filepath"` Url string `yaml:"url"` Username string `yaml:"username"` Password string `yaml:"password"` AuthorName string `yaml:"authorName"` AuthorEmail string `yaml:"authorEmail"` } type Language struct { BlogUrl string `yaml:"blogUrl"` ContentDir string `yaml:"contentDir"` DefaultSection string `yaml:"defaultSection"` Sections map[string]Section `yaml:"sections"` } type Section struct { FilenameTemplate string `yaml:"file"` LocationTemplate string `yaml:"location"` } func initConfig() (err error) { configFileName, configSet := os.LookupEnv("CONFIG") if !configSet { configFileName = "config.yml" } configFile, err := os.Open(configFileName) if err != nil { return errors.New("failed to open config file") } cfg := YamlConfig{} err = yaml.NewDecoder(configFile).Decode(&cfg) if err != nil { return errors.New("failed to parse yaml") } // Blog URL (required) if len(cfg.BlogUrl) < 1 { return errors.New("blogUrl not configured") } if !strings.HasSuffix(cfg.BlogUrl, "/") { return errors.New("missing trailing slash in configured blogUrl") } BlogUrl = cfg.BlogUrl // Media endpoint (required) if len(cfg.BaseUrl) < 1 { return errors.New("baseUrl not configured") } if len(cfg.MediaUrl) < 1 { return errors.New("mediaUrl not configured") } if !strings.HasSuffix(cfg.BaseUrl, "/") { return errors.New("missing trailing slash in configured baseUrl") } MediaEndpointUrl = cfg.BaseUrl + "media" // Languages (required) if len(cfg.DefaultLanguage) < 1 { return errors.New("no default language configured") } DefaultLanguage = cfg.DefaultLanguage if len(cfg.Languages) > 0 { for _, lang := range cfg.Languages { if len(lang.ContentDir) < 1 || len(lang.DefaultSection) < 1 || len(lang.Sections) < 1 { return errors.New("language not completely configured") } for _, section := range lang.Sections { if len(section.FilenameTemplate) < 1 || len(section.LocationTemplate) < 1 { return errors.New("section not completely configured") } } } Languages = cfg.Languages } else { return errors.New("no languages configured") } // Ignored Webmention URLs (optional) IgnoredWebmentionUrls = cfg.IgnoredWebmentionUrls // Syndication Targets (optional) targets := make([]SyndicationTarget, 0) for _, url := range cfg.SyndicationTargets { targets = append(targets, SyndicationTarget{ Uid: url, Name: url, }) } SyndicationTargets = targets // Find selected storage SelectedStorage = func() Storage { // Git if len(cfg.Git.Filepath) > 0 && len(cfg.Git.Url) > 0 && len(cfg.Git.Username) > 0 && len(cfg.Git.Password) > 0 && len(cfg.Git.AuthorName) > 0 && len(cfg.Git.AuthorEmail) > 0 { return &Git{ filepath: cfg.Git.Filepath, url: cfg.Git.Url, username: cfg.Git.Username, password: cfg.Git.Password, name: cfg.Git.AuthorName, email: cfg.Git.AuthorEmail, lock: &sync.Mutex{}, } } return nil }() if SelectedStorage == nil { return errors.New("no storage configured") } // Find selected media storage (Optional) SelectedMediaStorage = func() MediaStorage { // BunnyCDN // MEDIA_URL needs trailing slash too if len(cfg.BunnyCdn.StorageKey) > 0 && len(cfg.BunnyCdn.StorageName) > 0 && len(cfg.MediaUrl) > 0 && strings.HasSuffix(cfg.MediaUrl, "/") { return &BunnyCdnStorage{ key: cfg.BunnyCdn.StorageKey, storageZoneName: cfg.BunnyCdn.StorageName, baseLocation: cfg.MediaUrl, } } return nil }() if SelectedMediaStorage == nil { log.Println("no media storage configured") } // Find selected CDN (optional) SelectedCdn = func() Cdn { // BunnyCDN if len(cfg.BunnyCdn.Key) > 0 { return &BunnyCdn{key: cfg.BunnyCdn.Key} } return nil }() if SelectedCdn == nil { log.Println("no CDN configured") } // Find configured notification services (optional) SelectedNotificationServices = func() NotificationServices { var notificationServices []NotificationService = nil // Telegram if cfg.Telegram.UserId > 0 && len(cfg.Telegram.BotToken) > 0 { notificationServices = append(notificationServices, &Telegram{ userId: cfg.Telegram.UserId, botToken: cfg.Telegram.BotToken, }) } return notificationServices }() if SelectedNotificationServices == nil { log.Println("No notification services configured") } // Find configured image compression service (optional) SelectedImageCompression = func() ImageCompression { // Tinify if len(cfg.Tinify.Key) > 0 { return &Tinify{ key: cfg.Tinify.Key, } } return nil }() if SelectedImageCompression == nil { log.Println("no image compression configured") } return nil }