<commit_before>package config

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"strings"
	"time"
)

var (
	defaultConfig = Config{
		ListenAddr: ":8080",
		Clusters:   []Cluster{defaultCluster},
	}

	defaultCluster = Cluster{
		Scheme:   "http",
		ExecutionUsers: []ExecutionUser{defaultExecutionUser},
	}

	defaultExecutionUser = ExecutionUser{
		Name: "default",
	}
)

// Config is an structure to describe access and proxy rules
// The simplest configuration consists of:
// 	 cluster description - see <remote_servers> section in CH config.xml
// 	 and users - who allowed to access proxy
// Users requests are mapped to CH-cluster via `to_cluster` option
// with credentials of cluster user from `to_user` option
type Config struct {
	// TCP address to listen to for http
	// Default is `localhost:8080`
	ListenAddr string `yaml:"listen_addr,omitempty"`

	// TCP address to listen to for https
	ListenTLSAddr string `yaml:"listen_tls_addr,omitempty"`

	// Path to the directory where letsencrypt certs are cache
	CertCacheDir string `yaml:"cert_cache_dir,omitempty"`

	// Whether to print debug logs
	LogDebug bool `yaml:"log_debug,omitempty"`

	Clusters []Cluster `yaml:"clusters"`

	InitialUsers []InitialUser `yaml:"initial_users"`

	// Catches all undefined fields
	XXX map[string]interface{} `yaml:",inline"`
}

// Validates passed configuration by additional marshalling
// to ensure that all rules and checks were applied
func (c *Config) Validate() error {
	content, err := yaml.Marshal(c)
	if err != nil {
		return fmt.Errorf("error while marshalling config: %s", err)
	}

	cfg := &Config{}
	return yaml.Unmarshal([]byte(content), cfg)
}

// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	*c = defaultConfig

	// set c to the defaults and then overwrite it with the input.
	type plain Config
	if err := unmarshal((*plain)(c)); err != nil {
		return err
	}

	if len(c.InitialUsers) == 0 {
		return fmt.Errorf("field `initial_users` must contain at least 1 user")
	}

	if len(c.ListenTLSAddr) > 0 && len(c.CertCacheDir) == 0 {
		return fmt.Errorf("field `cert_cache_dir` must be set for TLS")
	}


	return checkOverflow(c.XXX, "config")
}

// Cluster is an structure to describe CH cluster configuration
// The simplest configuration consists of:
// 	 cluster description - see <remote_servers> section in CH config.xml
// 	 and users - see <users> section in CH users.xml
type Cluster struct {
	// Name of ClickHouse cluster
	Name string `yaml:"name"`

	// Scheme: `http` or `https`; would be applied to all nodes
	// default value is `http`
	Scheme string `yaml:"scheme,omitempty"`

	// Nodes - list of nodes addresses
	Nodes []string `yaml:"nodes"`
<commit_msg>format<commit_after>package config

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"strings"
	"time"
)

var (
	defaultConfig = Config{
		ListenAddr: ":8080",
		Clusters:   []Cluster{defaultCluster},
	}

	defaultCluster = Cluster{
		Scheme:         "http",
		ExecutionUsers: []ExecutionUser{defaultExecutionUser},
	}

	defaultExecutionUser = ExecutionUser{
		Name: "default",
	}
)

// Config is an structure to describe access and proxy rules
// The simplest configuration consists of:
// 	 cluster description - see <remote_servers> section in CH config.xml
// 	 and users - who allowed to access proxy
// Users requests are mapped to CH-cluster via `to_cluster` option
// with credentials of cluster user from `to_user` option
type Config struct {
	// TCP address to listen to for http
	// Default is `localhost:8080`
	ListenAddr string `yaml:"listen_addr,omitempty"`

	// TCP address to listen to for https
	ListenTLSAddr string `yaml:"listen_tls_addr,omitempty"`

	// Path to the directory where letsencrypt certs are cache
	CertCacheDir string `yaml:"cert_cache_dir,omitempty"`

	// Whether to print debug logs
	LogDebug bool `yaml:"log_debug,omitempty"`

	Clusters []Cluster `yaml:"clusters"`

	InitialUsers []InitialUser `yaml:"initial_users"`

	// Catches all undefined fields
	XXX map[string]interface{} `yaml:",inline"`
}

// Validates passed configuration by additional marshalling
// to ensure that all rules and checks were applied
func (c *Config) Validate() error {
	content, err := yaml.Marshal(c)
	if err != nil {
		return fmt.Errorf("error while marshalling config: %s", err)
	}

	cfg := &Config{}
	return yaml.Unmarshal([]byte(content), cfg)
}

// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	*c = defaultConfig

	// set c to the defaults and then overwrite it with the input.
	type plain Config
	if err := unmarshal((*plain)(c)); err != nil {
		return err
	}

	if len(c.InitialUsers) == 0 {
		return fmt.Errorf("field `initial_users` must contain at least 1 user")
	}

	if len(c.ListenTLSAddr) > 0 && len(c.CertCacheDir) == 0 {
		return fmt.Errorf("field `cert_cache_dir` must be set for TLS")
	}

	return checkOverflow(c.XXX, "config")
}

// Cluster is an structure to describe CH cluster configuration
// The simplest configuration consists of:
// 	 cluster description - see <remote_servers> section in CH config.xml
// 	 and users - see <users> section in CH users.xml
type Cluster struct {
	// Name of ClickHouse cluster
	Name string `yaml:"name"`

	// Scheme: `http` or `https`; would be applied to all nodes
	// default value is `http`
	Scheme string `yaml:"scheme,omitempty"`

	// Nodes - list of nodes addresses
	Nodes []string `yaml:"nodes"`

{'fraction_non_alphanumeric': 0.11296162201303403, 'fraction_numerical': 0.004706734250543085, 'mean_word_length': 4.1539179104477615, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7272153', 'n_tokens_mistral': 1750, 'n_tokens_neox': 1638, 'n_words': 596}