You've already forked tarr
							
							
		
			
				
	
	
		
			202 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package config
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/xml"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"git.cryptic.systems/volker.raschek/tarr/pkg/domain"
 | |
| 	"github.com/fsnotify/fsnotify"
 | |
| 	"gopkg.in/yaml.v3"
 | |
| )
 | |
| 
 | |
| type XMLConfig struct {
 | |
| 	XMLName              xml.Name `xml:"Config"`
 | |
| 	APIToken             string   `xml:"ApiKey,omitempty"`
 | |
| 	AuthenticationMethod string   `xml:"AuthenticationMethod,omitempty"`
 | |
| 	BindAddress          string   `xml:"BindAddress,omitempty"`
 | |
| 	Branch               string   `xml:"Branch,omitempty"`
 | |
| 	EnableSSL            string   `xml:"EnableSsl,omitempty"`
 | |
| 	InstanceName         string   `xml:"InstanceName,omitempty"`
 | |
| 	LaunchBrowser        string   `xml:"LaunchBrowser,omitempty"`
 | |
| 	LogLevel             string   `xml:"LogLevel,omitempty"`
 | |
| 	Port                 string   `xml:"Port,omitempty"`
 | |
| 	SSLCertPassword      string   `xml:"SSLCertPassword,omitempty"`
 | |
| 	SSLCertPath          string   `xml:"SSLCertPath,omitempty"`
 | |
| 	SSLPort              string   `xml:"SslPort,omitempty"`
 | |
| 	UpdateMechanism      string   `xml:"UpdateMechanism,omitempty"`
 | |
| 	URLBase              string   `xml:"UrlBase,omitempty"`
 | |
| }
 | |
| 
 | |
| type YAMLConfigAuth struct {
 | |
| 	APIToken string `yaml:"apikey,omitempty"`
 | |
| 	Password string `yaml:"password,omitempty"`
 | |
| 	Type     string `yaml:"type,omitempty"`
 | |
| 	Username string `yaml:"username,omitempty"`
 | |
| }
 | |
| 
 | |
| type YAMLConfig struct {
 | |
| 	Auth YAMLConfigAuth `yaml:"auth,omitempty"`
 | |
| }
 | |
| 
 | |
| // Read reads the config struct from a file. The decoding format will be determined by the file extension like
 | |
| // `xml` or `yaml`.
 | |
| func ReadConfig(name string) (*domain.Config, error) {
 | |
| 	f, err := os.Open(name)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 
 | |
| 	switch {
 | |
| 	case strings.HasSuffix(name, "xml"):
 | |
| 		return readXMLConfig(f)
 | |
| 	case strings.HasSuffix(name, "yml") || strings.HasSuffix(name, "yaml"):
 | |
| 		return readYAMLConfig(f)
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("Unsupported file extension")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func readXMLConfig(r io.Reader) (*domain.Config, error) {
 | |
| 	xmlConfig := new(XMLConfig)
 | |
| 
 | |
| 	xmlDecoder := xml.NewDecoder(r)
 | |
| 	err := xmlDecoder.Decode(xmlConfig)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &domain.Config{
 | |
| 		API: &domain.API{
 | |
| 			Token: xmlConfig.APIToken,
 | |
| 		},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func readYAMLConfig(r io.Reader) (*domain.Config, error) {
 | |
| 	yamlConfig := new(YAMLConfig)
 | |
| 
 | |
| 	yamlDecoder := yaml.NewDecoder(r)
 | |
| 	err := yamlDecoder.Decode(yamlConfig)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &domain.Config{
 | |
| 		API: &domain.API{
 | |
| 			Password: yamlConfig.Auth.Password,
 | |
| 			Token:    yamlConfig.Auth.APIToken,
 | |
| 			Username: yamlConfig.Auth.Username,
 | |
| 		},
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func WatchConfig(ctx context.Context, name string) (<-chan *domain.Config, <-chan error) {
 | |
| 	configChannel := make(chan *domain.Config, 0)
 | |
| 	errorChannel := make(chan error, 0)
 | |
| 
 | |
| 	go func() {
 | |
| 		wait := time.Second * 3
 | |
| 		timer := time.NewTimer(wait)
 | |
| 		<-timer.C
 | |
| 
 | |
| 		watcher, err := fsnotify.NewWatcher()
 | |
| 		if err != nil {
 | |
| 			errorChannel <- err
 | |
| 			return
 | |
| 		}
 | |
| 		watcher.Add(name)
 | |
| 
 | |
| 		for {
 | |
| 			select {
 | |
| 			case <-ctx.Done():
 | |
| 				close(configChannel)
 | |
| 				close(errorChannel)
 | |
| 				break
 | |
| 			case event, open := <-watcher.Events:
 | |
| 				if !open {
 | |
| 					errorChannel <- fmt.Errorf("FSWatcher closed channel: %w", err)
 | |
| 					break
 | |
| 				}
 | |
| 
 | |
| 				switch event.Op {
 | |
| 				case fsnotify.Write:
 | |
| 					timer.Reset(wait)
 | |
| 				}
 | |
| 			case <-timer.C:
 | |
| 				config, err := ReadConfig(name)
 | |
| 				if err != nil {
 | |
| 					errorChannel <- err
 | |
| 					continue
 | |
| 				}
 | |
| 				configChannel <- config
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	return configChannel, errorChannel
 | |
| }
 | |
| 
 | |
| // WriteConfig writes the config struct into the file. The encoding format will be determined by the file extension like
 | |
| // `xml` or `yaml`.
 | |
| func WriteConfig(name string, config *domain.Config) error {
 | |
| 	f, err := os.Create(name)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer f.Close()
 | |
| 
 | |
| 	switch {
 | |
| 	case strings.HasSuffix(name, "xml"):
 | |
| 		return writeXMLConfig(f, config)
 | |
| 	case strings.HasSuffix(name, "yml") || strings.HasSuffix(name, "yaml"):
 | |
| 		return writeYAMLConfig(f, config)
 | |
| 	default:
 | |
| 		return fmt.Errorf("Unsupported file extension")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func writeXMLConfig(w io.Writer, config *domain.Config) error {
 | |
| 	xmlEncoder := xml.NewEncoder(w)
 | |
| 	defer xmlEncoder.Close()
 | |
| 
 | |
| 	xmlConfig := &XMLConfig{
 | |
| 		APIToken: config.API.Token,
 | |
| 	}
 | |
| 
 | |
| 	xmlEncoder.Indent("", "  ")
 | |
| 	err := xmlEncoder.Encode(xmlConfig)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func writeYAMLConfig(w io.Writer, config *domain.Config) error {
 | |
| 	yamlEncoder := yaml.NewEncoder(w)
 | |
| 	defer yamlEncoder.Close()
 | |
| 
 | |
| 	yamlConfig := &YAMLConfig{
 | |
| 		Auth: YAMLConfigAuth{
 | |
| 			APIToken: config.API.Token,
 | |
| 			Password: config.API.Password,
 | |
| 			Username: config.API.Username,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	yamlEncoder.SetIndent(2)
 | |
| 
 | |
| 	err := yamlEncoder.Encode(yamlConfig)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |