2019-10-22 16:36:54 +00:00
package config
import (
2019-10-25 18:12:38 +00:00
"fmt"
2019-10-22 19:55:43 +00:00
"github.com/pkg/errors"
2019-10-22 16:36:54 +00:00
"io/ioutil"
2019-10-25 18:12:38 +00:00
"github.com/santhosh-tekuri/jsonschema"
2019-10-22 16:36:54 +00:00
"gopkg.in/yaml.v2"
)
type Config struct {
Telegram TelegramConfig ` yaml:":telegram" `
Xmpp XmppConfig ` yaml:":xmpp" `
}
type XmppConfig struct {
Loglevel string ` yaml:":loglevel" `
Jid string ` yaml:":jid" `
Host string ` yaml:":host" `
Port string ` yaml:":port" `
Password string ` yaml:":password" `
Db string ` yaml:":db" `
}
type TelegramConfig struct {
Loglevel string ` yaml:":loglevel" `
Content TelegramContentConfig ` yaml:":content" `
Verbosity uint8 ` yaml:":tdlib_verbosity" `
Tdlib TelegramTdlibConfig ` yaml:":tdlib" `
}
type TelegramContentConfig struct {
Path string ` yaml:":path" `
Link string ` yaml:":link" `
Upload string ` yaml:":upload" `
}
type TelegramTdlibConfig struct {
Path string ` yaml:":lib_path" `
Client TelegramTdlibClientConfig ` yaml:":client" `
}
type TelegramTdlibClientConfig struct {
ApiId string ` yaml:":api_id" `
ApiHash string ` yaml:":api_hash" `
DeviceModel string ` yaml:":device_model" `
ApplicationVersion string ` yaml:":application_version" `
UseChatInfoDatabase bool ` yaml:":use_chat_info_database" `
}
2019-10-25 18:12:38 +00:00
func ReadConfig ( path string , schema_path string ) ( Config , error ) {
2019-10-22 16:36:54 +00:00
var config Config
file , err := ioutil . ReadFile ( path )
if err != nil {
2019-10-22 19:55:43 +00:00
return config , errors . Wrap ( err , "Can't open config file" )
2019-10-22 16:36:54 +00:00
}
err = yaml . Unmarshal ( file , & config )
if err != nil {
2019-10-22 19:55:43 +00:00
return config , errors . Wrap ( err , "Error parsing config" )
2019-10-22 16:36:54 +00:00
}
2019-10-25 18:12:38 +00:00
err = validateConfig ( file , schema_path )
if err != nil {
return config , errors . Wrap ( err , "Validation error" )
}
2019-10-22 19:55:43 +00:00
return config , nil
2019-10-22 16:36:54 +00:00
}
2019-10-25 18:12:38 +00:00
func validateConfig ( file [ ] byte , schema_path string ) error {
schema , err := jsonschema . Compile ( schema_path )
if err != nil {
return errors . Wrap ( err , "Corrupted JSON schema" )
}
var config_generic interface { }
err = yaml . Unmarshal ( file , & config_generic )
if err != nil {
return errors . Wrap ( err , "Error re-parsing config" )
}
config_generic , err = convertToStringKeysRecursive ( config_generic , "" )
if err != nil {
return errors . Wrap ( err , "Config conversion error" )
}
err = schema . ValidateInterface ( config_generic )
if err != nil {
return errors . Wrap ( err , "Config validation error" )
}
return nil
}
// copied and adapted from https://github.com/docker/docker-ce/blob/de14285fad39e215ea9763b8b404a37686811b3f/components/cli/cli/compose/loader/loader.go#L330
func convertToStringKeysRecursive ( value interface { } , keyPrefix string ) ( interface { } , error ) {
if mapping , ok := value . ( map [ interface { } ] interface { } ) ; ok {
dict := make ( map [ string ] interface { } )
for key , entry := range mapping {
str , ok := key . ( string )
if ! ok {
return nil , formatInvalidKeyError ( keyPrefix , key )
}
var newKeyPrefix string
if keyPrefix == "" {
newKeyPrefix = str
} else {
newKeyPrefix = fmt . Sprintf ( "%s.%s" , keyPrefix , str )
}
convertedEntry , err := convertToStringKeysRecursive ( entry , newKeyPrefix )
if err != nil {
return nil , err
}
dict [ str ] = convertedEntry
}
return dict , nil
}
if list , ok := value . ( [ ] interface { } ) ; ok {
var convertedList [ ] interface { }
for index , entry := range list {
newKeyPrefix := fmt . Sprintf ( "%s[%d]" , keyPrefix , index )
convertedEntry , err := convertToStringKeysRecursive ( entry , newKeyPrefix )
if err != nil {
return nil , err
}
convertedList = append ( convertedList , convertedEntry )
}
return convertedList , nil
}
return value , nil
}
func formatInvalidKeyError ( keyPrefix string , key interface { } ) error {
var location string
if keyPrefix == "" {
location = "at top level"
} else {
location = fmt . Sprintf ( "in %s" , keyPrefix )
}
return errors . Errorf ( "Non-string key %s: %#v" , location , key )
}