<commit_before>package QesyGo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type RandWeiht struct {
	Name   string
	Weight int
}

var randSeek int64 = 0

type RandWeihtArr []RandWeiht

func Substr(str string, start int, end int) string {
	var endNum int
	s := []byte(str)
	if end > 0 {
		endNum = start + end
	} else {
		endNum = len(str) + end
	}
	return string(s[start:endNum])
}

func Rand(Min int, Max int) int {
	tempNum := Max - Min
	if randSeek > 9999999999 {
		randSeek = 0
	} else {
		randSeek++
	}
	rand.Seed(time.Now().UnixNano() + randSeek)
	return Min + rand.Intn(tempNum)
}

func Rate(num int) bool {
	rand := Rand(1, 100)
	if rand <= num {
		return true
	} else {
		return false
	}
}

/*
* RandWeihtArr := &lib.RandWeihtArr{{"user1",8}, {"user2",1},{"user3",1}}
* who := RandWeihtArr.RandWeight()
 */
func (arr *RandWeihtArr) RandWeight() string {
	var all int
	for _, v := range *arr {
		all += v.Weight
	}
	plusNum := 0
	tempArr := make(map[string][2]int)
	for _, v := range *arr {
		plusNum += v.Weight
		tempArr[v.Name] = [2]int{plusNum - v.Weight, plusNum}
	}
	randNum := Rand(0, all) + 1
	var ret string
	for k, v := range tempArr {
		if randNum > v[0] && randNum <= v[1] {
			ret = k
			break
		}
	}
	return ret
}

func ReadFile(str string) ([]byte, error) {
	return ioutil.ReadFile(str)
}

func JsonEncode(arr interface{}) ([]byte, error) {
	return json.Marshal(arr)
}

func JsonDecode(str []byte, jsonArr interface{}) error {
	strNew := string(str)
	if strNew == "null" || strNew == "" {
		return nil
	}
	err := json.Unmarshal(str, jsonArr)
	return err

}

func Printf(format string, a ...interface{}) {
	fmt.Printf(format, a)
}

func Fprintf(w http.ResponseWriter, str string) {
	fmt.Fprintf(w, str)
}

func Die(v interface{}) {
	log.Fatal(v)
}

func Implode(arr []string, sep string) string {
	return strings.Join(arr, sep)
}

func Explode(str string, sep string) []string {
	if str == "" {
		return []string{}
	}
	return strings.Split(str, sep)
}

func Err(str string) error {
	return errors.New(str)
}

func Println(str ...interface{}) {
	fmt.Println(str)
}

func Time(str string) int64 {
	now := time.Now()
	t := now.UnixNano()
	switch str {
	case "Millisecond":
		t = now.UnixNano() / 1000
	case "Microsecond":
		t = now.UnixNano() / 1000000
	case "Second":
		t = now.UnixNano() / 1000000000
	}
	return t
}

func TimeStr(str string) string {
	t := Time(str)
	return strconv.FormatInt(t, 10)
}

func TimeInt(str string) int {
	t := Time(str)
	ret, _ := Int64ToInt(t)
	return ret
}

//-- format : "2006-01-02 03:04:05 PM" --
/*
月份 1,01,Jan,January
日　 2,02,_2
时　 3,03,15,PM,pm,AM,am
分　 4,04
秒　 5,05
年　 06,2006
周几 Mon,Monday
时区时差表示 -07,-0700,Z0700,Z07:00,-07:00,MST
时区字母缩写 MST
*/
func Date(timestamp int64, format string) string {
	tm := time.Unix(timestamp, 0)
	return tm.Format(format)
}

//-- "01/02/2006", "02/08/2015" --
func StrToTime(format string, input string) int64 {
	tm2, _ := time.Parse(format, input)
	return tm2.Unix()
}

func Int64ToInt(num int64) (int, error) {
	str := strconv.FormatInt(num, 10)
	return strconv.Atoi(str)
}

func StrToInt(str string) int {
	ret, _ := strconv.Atoi(str)
	return ret
}

func Unset(arr []string, str string) []string {
	newArr := []string{}
	for _, v := range arr {
		if v != str && v != "" {
			newArr = append(newArr, v)
		}
	}
	return newArr
}

//-- kind 0:纯数字，1：小写，2：大写，3：数字+大小写字幕 --
func Krand(size int, kind int) []byte {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	is_all := kind > 2 || kind < 0
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < size; i++ {
		if is_all { // random ikind
			ikind = Rand(1, 3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + Rand(1, scope))
	}
	return result
}
<commit_msg>add Wordwrap<commit_after>package QesyGo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type RandWeiht struct {
	Name   string
	Weight int
}

var randSeek int64 = 0

type RandWeihtArr []RandWeiht

func Substr(str string, start int, end int) string {
	var endNum int
	s := []byte(str)
	if end > 0 {
		endNum = start + end
	} else {
		endNum = len(str) + end
	}
	return string(s[start:endNum])
}

func Rand(Min int, Max int) int {
	tempNum := Max - Min
	if randSeek > 9999999999 {
		randSeek = 0
	} else {
		randSeek++
	}
	rand.Seed(time.Now().UnixNano() + randSeek)
	return Min + rand.Intn(tempNum)
}

func Rate(num int) bool {
	rand := Rand(1, 100)
	if rand <= num {
		return true
	} else {
		return false
	}
}

/*
* RandWeihtArr := &lib.RandWeihtArr{{"user1",8}, {"user2",1},{"user3",1}}
* who := RandWeihtArr.RandWeight()
 */
func (arr *RandWeihtArr) RandWeight() string {
	var all int
	for _, v := range *arr {
		all += v.Weight
	}
	plusNum := 0
	tempArr := make(map[string][2]int)
	for _, v := range *arr {
		plusNum += v.Weight
		tempArr[v.Name] = [2]int{plusNum - v.Weight, plusNum}
	}
	randNum := Rand(0, all) + 1
	var ret string
	for k, v := range tempArr {
		if randNum > v[0] && randNum <= v[1] {
			ret = k
			break
		}
	}
	return ret
}

func ReadFile(str string) ([]byte, error) {
	return ioutil.ReadFile(str)
}

func JsonEncode(arr interface{}) ([]byte, error) {
	return json.Marshal(arr)
}

func JsonDecode(str []byte, jsonArr interface{}) error {
	strNew := string(str)
	if strNew == "null" || strNew == "" {
		return nil
	}
	err := json.Unmarshal(str, jsonArr)
	return err

}

func Printf(format string, a ...interface{}) {
	fmt.Printf(format, a)
}

func Fprintf(w http.ResponseWriter, str string) {
	fmt.Fprintf(w, str)
}

func Die(v interface{}) {
	log.Fatal(v)
}

func Implode(arr []string, sep string) string {
	return strings.Join(arr, sep)
}

func Explode(str string, sep string) []string {
	if str == "" {
		return []string{}
	}
	return strings.Split(str, sep)
}

func Err(str string) error {
	return errors.New(str)
}

func Println(str ...interface{}) {
	fmt.Println(str)
}

func Time(str string) int64 {
	now := time.Now()
	t := now.UnixNano()
	switch str {
	case "Millisecond":
		t = now.UnixNano() / 1000
	case "Microsecond":
		t = now.UnixNano() / 1000000
	case "Second":
		t = now.UnixNano() / 1000000000
	}
	return t
}

func TimeStr(str string) string {
	t := Time(str)
	return strconv.FormatInt(t, 10)
}

func TimeInt(str string) int {
	t := Time(str)
	ret, _ := Int64ToInt(t)
	return ret
}

//-- format : "2006-01-02 03:04:05 PM" --
/*
月份 1,01,Jan,January
日　 2,02,_2
时　 3,03,15,PM,pm,AM,am
分　 4,04
秒　 5,05
年　 06,2006
周几 Mon,Monday
时区时差表示 -07,-0700,Z0700,Z07:00,-07:00,MST
时区字母缩写 MST
*/
func Date(timestamp int64, format string) string {
	tm := time.Unix(timestamp, 0)
	return tm.Format(format)
}

//-- "01/02/2006", "02/08/2015" --
func StrToTime(format string, input string) int64 {
	tm2, _ := time.Parse(format, input)
	return tm2.Unix()
}

func Int64ToInt(num int64) (int, error) {
	str := strconv.FormatInt(num, 10)
	return strconv.Atoi(str)
}

func StrToInt(str string) int {
	ret, _ := strconv.Atoi(str)
	return ret
}

func Unset(arr []string, str string) []string {
	newArr := []string{}
	for _, v := range arr {
		if v != str && v != "" {
			newArr = append(newArr, v)
		}
	}
	return newArr
}

//-- kind 0:纯数字，1：小写，2：大写，3：数字+大小写字幕 --
func Krand(size int, kind int) []byte {
	ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
	is_all := kind > 2 || kind < 0
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < size; i++ {
		if is_all { // random ikind
			ikind = Rand(1, 3)
		}
		scope, base := kinds[ikind][0], kinds[ikind][1]
		result[i] = uint8(base + Rand(1, scope))
	}
	return result
}

func Wordwrap(Str string, width int, breakStr string) string {
	breakStrByte := []byte(breakStr)
	strByte := []byte(Str)
	var tempByte []byte
	for k, v := range strByte {
		if (k+1)%width == 0 {
			tempByte = append(tempByte, v)
			tempByte = append(tempByte, breakStrByte...)
		} else {
			tempByte = append(tempByte, v)
		}
	}
	return string(tempByte)
}
<|endoftext|>


<commit_before>// Copyright 2011 Numerotron Inc.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.
//
// Developed at www.stathat.com by Patrick Crosby
// Contact us on twitter with any questions:  twitter.com/stat_hat

// The jconfig package provides a simple, basic configuration file parser using JSON.
package jconfig

import (
	"bytes"
	"encoding/json"
	"log"
	"os"
)

type Config struct {
	data     map[string]interface{}
	filename string
}

func newConfig() *Config {
	result := new(Config)
	result.data = make(map[string]interface{})
	return result
}

// Loads config information from a JSON file
func LoadConfig(filename string) *Config {
	result := newConfig()
	result.filename = filename
	err := result.parse()
	if err != nil {
		log.Fatalf("error loading config file %s: %s", filename, err)
	}
	return result
}

// Loads config information from a JSON string
func LoadConfigString(s string) *Config {
	result := newConfig()
	err := json.Unmarshal([]byte(s), &result.data)
	if err != nil {
		log.Fatalf("error parsing config string %s: %s", s, err)
	}
	return result
}

func (c *Config) StringMerge(s string) {
	next := LoadConfigString(s)
	c.merge(next.data)
}

func (c *Config) LoadMerge(filename string) {
	next := LoadConfig(filename)
	c.merge(next.data)
}

func (c *Config) merge(ndata map[string]interface{}) {
	for k, v := range ndata {
		c.data[k] = v
	}
}

func (c *Config) parse() error {
	f, err := os.Open(c.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	b := new(bytes.Buffer)
	_, err = b.ReadFrom(f)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b.Bytes(), &c.data)
	if err != nil {
		return err
	}

	return nil
}

// Returns a string for the config variable key
func (c *Config) GetString(key string) string {
	result, present := c.data[key]
	if !present {
		return ""
	}
	return result.(string)
}

// Returns an int for the config variable key
func (c *Config) GetInt(key string) int {
	x, ok := c.data[key]
	if !ok {
		return -1
	}
	return int(x.(float64))
}

// Returns a float for the config variable key
func (c *Config) GetFloat(key string) float64 {
	x, ok := c.data[key]
	if !ok {
		return -1
	}
	return x.(float64)
}

// Returns a bool for the config variable key
func (c *Config) GetBool(key string) bool {
	x, ok := c.data[key]
	if !ok {
		return false
	}
	return x.(bool)
}

// Returns an array for the config variable key
func (c *Config) GetArray(key string) []interface{} {
	result, present := c.data[key]
	if !present {
		return []interface{}(nil)
	}
	return result.([]interface{})
}
<commit_msg>import path<commit_after>// Copyright 2011 Numerotron Inc.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.
//
// Developed at www.stathat.com by Patrick Crosby
// Contact us on twitter with any questions:  twitter.com/stat_hat

// The jconfig package provides a simple, basic configuration file parser using JSON.
package jconfig // import "stathat.com/c/jconfig"

import (
	"bytes"
	"encoding/json"
	"log"
	"os"
)

type Config struct {
	data     map[string]interface{}
	filename string
}

func newConfig() *Config {
	result := new(Config)
	result.data = make(map[string]interface{})
	return result
}

// Loads config information from a JSON file
func LoadConfig(filename string) *Config {
	result := newConfig()
	result.filename = filename
	err := result.parse()
	if err != nil {
		log.Fatalf("error loading config file %s: %s", filename, err)
	}
	return result
}

// Loads config information from a JSON string
func LoadConfigString(s string) *Config {
	result := newConfig()
	err := json.Unmarshal([]byte(s), &result.data)
	if err != nil {
		log.Fatalf("error parsing config string %s: %s", s, err)
	}
	return result
}

func (c *Config) StringMerge(s string) {
	next := LoadConfigString(s)
	c.merge(next.data)
}

func (c *Config) LoadMerge(filename string) {
	next := LoadConfig(filename)
	c.merge(next.data)
}

func (c *Config) merge(ndata map[string]interface{}) {
	for k, v := range ndata {
		c.data[k] = v
	}
}

func (c *Config) parse() error {
	f, err := os.Open(c.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	b := new(bytes.Buffer)
	_, err = b.ReadFrom(f)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b.Bytes(), &c.data)
	if err != nil {
		return err
	}

	return nil
}

// Returns a string for the config variable key
func (c *Config) GetString(key string) string {
	result, present := c.data[key]
	if !present {
		return ""
	}
	return result.(string)
}

// Returns an int for the config variable key
func (c *Config) GetInt(key string) int {
	x, ok := c.data[key]
	if !ok {
		return -1
	}
	return int(x.(float64))
}

// Returns a float for the config variable key
func (c *Config) GetFloat(key string) float64 {
	x, ok := c.data[key]
	if !ok {
		return -1
	}
	return x.(float64)
}

// Returns a bool for the config variable key
func (c *Config) GetBool(key string) bool {
	x, ok := c.data[key]
	if !ok {
		return false
	}
	return x.(bool)
}

// Returns an array for the config variable key
func (c *Config) GetArray(key string) []interface{} {
	result, present := c.data[key]
	if !present {
		return []interface{}(nil)
	}
	return result.([]interface{})
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"fmt"
	"os"
)

type Provider interface {
	SetRawString(raw string)
	SetRawBytes(raw []byte)
	Get(data interface{}) error
	Set(data interface{}) (int, error)
}

var (
	Prefix   string
	filepath string
	provider Provider
)

func New(file, format string) (provider Provider, err error) {

	// set config file full path
	filepath = Prefix + file
	fp, fperr := os.OpenFile(filepath, os.O_RDONLY|os.O_CREATE, os.ModePerm)
	if os.IsNotExist(fperr) {
		fperr = nil
		filepath = Prefix + "/etc/" + file
		fp, fperr = os.Open(filepath)
	}

	if fperr != nil {
		return nil, fperr
	}

	// read config file raw data.
	fstat, _ := fp.Stat()
	raw := make([]byte, fstat.Size())
	fp.Read(raw)

	switch format {
	case "json":
		provider = &JSON{}
		provider.SetRawBytes(raw)

	case "xml":
		provider = &XML{}
		provider.SetRawBytes(raw)

	default:
		return nil, errors.New("Not support this format config file.")
	}
	return
}

// init default provider
func defaultProvider() {
	var derr error
	Prefix = "./"
	provider, derr = New("main.json", "json")
	if derr != nil {
		fmt.Printf("[config package]get default config error,details: %v\n", derr)
		os.Exit(1)
	}
}

func Get(data interface{}) error {
	defaultProvider()
	return provider.Get(data)
}

func Set(data interface{}) (int, error) {
	defaultProvider()
	return provider.Set(data)
}
<commit_msg>add get raw bytes interface.<commit_after>package config

import (
	"errors"
	"fmt"
	"os"
)

type Provider interface {
	SetRawString(raw string)
	SetRawBytes(raw []byte)
	Get(data interface{}) error
	Set(data interface{}) (int, error)
	GetRawBytes() []byte
}

var (
	Prefix   string
	filepath string
	provider Provider
)

func New(file, format string) (provider Provider, err error) {

	// set config file full path
	filepath = Prefix + file
	fp, fperr := os.OpenFile(filepath, os.O_RDONLY|os.O_CREATE, os.ModePerm)
	if os.IsNotExist(fperr) {
		fperr = nil
		filepath = Prefix + "/etc/" + file
		fp, fperr = os.Open(filepath)
	}

	if fperr != nil {
		return nil, fperr
	}

	// read config file raw data.
	fstat, _ := fp.Stat()
	raw := make([]byte, fstat.Size())
	fp.Read(raw)

	switch format {
	case "json":
		provider = &JSON{}
		provider.SetRawBytes(raw)

	case "xml":
		provider = &XML{}
		provider.SetRawBytes(raw)

	default:
		return nil, errors.New("Not support this format config file.")
	}
	return
}

// init default provider
func defaultProvider() {
	var derr error
	Prefix = "./"
	provider, derr = New("main.json", "json")
	if derr != nil {
		fmt.Printf("[config package]get default config error,details: %v\n", derr)
		os.Exit(1)
	}
}

func Get(data interface{}) error {
	defaultProvider()
	return provider.Get(data)
}

func Set(data interface{}) (int, error) {
	defaultProvider()
	return provider.Set(data)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

var (
	homeDir    string
	selfURL127 string // 127.0.0.1:listenAddr
	selfURLLH  string // localhost:listenAddr
)

const (
	blockedFname       = "auto-blocked"
	directFname        = "auto-direct"
	alwaysBlockedFname = "blocked"
	alwaysDirectFname  = "direct"
	chouFname          = "chou"
	rcFname            = "rc"

	version = "0.3.4"
)

type Config struct {
	RcFile        string // config file
	ListenAddr    string
	SocksAddr     string
	Core          int
	SshServer     string
	UpdateBlocked bool
	UpdateDirect  bool
	AutoRetry     bool
	DetectSSLErr  bool
	LogFile       string
	AlwaysProxy   bool
	ShadowSocks   string
	ShadowPasswd  string

	// not configurable in config file
	PrintVer bool
}

var config Config

var dsFile struct {
	dir           string // directory containing config file and blocked site list
	blocked       string // contains blocked domains
	direct        string // contains sites that can be directly accessed
	alwaysDirect  string
	alwaysBlocked string
	chou          string // chou feng, sites which will be temporary blocked
}

func printVersion() {
	fmt.Println("cow version", version)
}

func init() {
	if isWindows() {
		// On windows, put the configuration file in the same directory of cow executable
		homeDir = path.Base(os.Args[0])
		dsFile.dir = homeDir
	} else {
		u, err := user.Current()
		if err != nil {
			fmt.Printf("Can't get user information %v", err)
			os.Exit(1)
		}
		homeDir = u.HomeDir
		dsFile.dir = path.Join(homeDir, ".cow")
	}
	// fmt.Println("home dir:", homeDir)

	dsFile.blocked = path.Join(dsFile.dir, blockedFname)
	dsFile.direct = path.Join(dsFile.dir, directFname)
	dsFile.alwaysBlocked = path.Join(dsFile.dir, alwaysBlockedFname)
	dsFile.alwaysDirect = path.Join(dsFile.dir, alwaysDirectFname)
	dsFile.chou = path.Join(dsFile.dir, chouFname)
}

func parseCmdLineConfig() *Config {
	var rcFileDefault string
	if isWindows() {
		rcFileDefault = path.Join(homeDir, "rc")
	} else {
		rcFileDefault = "~/.cow/rc"
	}
	var c Config
	flag.StringVar(&c.RcFile, "rc", rcFileDefault, "configuration file")
	flag.StringVar(&c.ListenAddr, "listen", "127.0.0.1:7777", "proxy server listen address")
	flag.StringVar(&c.SocksAddr, "socks", "", "socks proxy address")
	flag.IntVar(&c.Core, "core", 2, "number of cores to use")
	flag.StringVar(&c.SshServer, "sshServer", "", "remote server which will ssh to and provide sock server")
	flag.BoolVar(&c.UpdateBlocked, "updateBlocked", true, "update blocked site list")
	flag.BoolVar(&c.UpdateDirect, "updateDirect", true, "update direct site list")
	flag.BoolVar(&c.AutoRetry, "autoRetry", false, "automatically retry timeout requests using socks proxy")
	flag.BoolVar(&c.DetectSSLErr, "detectSSLErr", true, "detect SSL error based on how soon client closes connection")
	flag.StringVar(&c.LogFile, "logFile", "", "write output to file, empty means stdout")
	flag.BoolVar(&c.AlwaysProxy, "alwaysProxy", false, "always use parent proxy")
	flag.BoolVar(&c.PrintVer, "version", false, "print version")

	flag.StringVar(&c.ShadowSocks, "shadowSocks", "", "shadowsocks server address")
	flag.StringVar(&c.ShadowPasswd, "shadowPasswd", "", "shadowsocks password")
	flag.Parse()
	return &c
}

// Tries to open a file, if file not exist, return both nil, err
func openFile(path string) (f *os.File, err error) {
	if f, err = os.Open(path); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		errl.Println("Error opening file:", path, err)
		return nil, err
	}
	return
}

func parseBool(v string, msg string) bool {
	switch v {
	case "true":
		return true
	case "false":
		return false
	default:
		fmt.Printf("%s should be true or false\n", msg)
		os.Exit(1)
	}
	return false
}

type configParser struct{}

func (p configParser) ParseListen(val string) {
	config.ListenAddr = val
}

func isServerAddrValid(val string) bool {
	if val == "" {
		return true
	}
	_, port := splitHostPort(val)
	if port == "" {
		return false
	}
	return true
}

func (p configParser) ParseSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("socks server must have port specified")
		os.Exit(1)
	}
	config.SocksAddr = val
}

func (p configParser) ParseCore(val string) {
	if val == "" {
		return
	}
	var err error
	config.Core, err = strconv.Atoi(val)
	if err != nil {
		fmt.Printf("Config error: core number %s %v", val, err)
		os.Exit(1)
	}
}

func (p configParser) ParseSshServer(val string) {
	config.SshServer = val
}

func (p configParser) ParseUpdateBlocked(val string) {
	config.UpdateBlocked = parseBool(val, "updateBlocked")
}

func (p configParser) ParseUpdateDirect(val string) {
	config.UpdateDirect = parseBool(val, "updateDirect")
}

func (p configParser) ParseAutoRetry(val string) {
	config.AutoRetry = parseBool(val, "autoRetry")
}

func (p configParser) ParseDetectSSLErr(val string) {
	config.DetectSSLErr = parseBool(val, "detectSSLErr")
}

func (p configParser) ParseLogFile(val string) {
	config.LogFile = val
}

func (p configParser) ParseAlwaysProxy(val string) {
	config.AlwaysProxy = parseBool(val, "alwaysProxy")
}

func (p configParser) ParseShadowSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("shadowsocks server must have port specified")
		os.Exit(1)
	}
	config.ShadowSocks = val
}

func (p configParser) ParseShadowPasswd(val string) {
	config.ShadowPasswd = val
}

func parseConfig(path string) {
	// fmt.Println("rcFile:", path)
	f, err := os.Open(expandTild(path))
	if err != nil {
		fmt.Println("error opening config file:", err)
		return
	}
	defer f.Close()

	fr := bufio.NewReader(f)

	parser := reflect.ValueOf(configParser{})
	zeroMethod := reflect.Value{}

	var line string
	var n int
	for {
		n++
		line, err = ReadLine(fr)
		if err == io.EOF {
			return
		} else if err != nil {
			errl.Printf("Error reading rc file: %v\n", err)
			os.Exit(1)
		}

		if line == "" {
			continue
		}

		line = strings.TrimSpace(line)
		// Ignore comment
		if line[0] == '#' {
			continue
		}

		v := strings.Split(line, "=")
		if len(v) != 2 {
			fmt.Println("Config error: syntax error on line", n)
			os.Exit(1)
		}
		key, val := strings.TrimSpace(v[0]), strings.TrimSpace(v[1])

		methodName := "Parse" + strings.ToUpper(key[0:1]) + key[1:]
		method := parser.MethodByName(methodName)
		if method == zeroMethod {
			fmt.Printf("Config error: no such option \"%s\"\n", key)
			os.Exit(1)
		}
		args := []reflect.Value{reflect.ValueOf(val)}
		method.Call(args)
	}
}

func updateConfig(new *Config) {
	newVal := reflect.ValueOf(new).Elem()
	oldVal := reflect.ValueOf(&config).Elem()

	// typeOfT := newVal.Type()
	for i := 0; i < newVal.NumField(); i++ {
		newField := newVal.Field(i)
		oldField := oldVal.Field(i)
		// log.Printf("%d: %s %s = %v\n", i,
		// typeOfT.Field(i).Name, newField.Type(), newField.Interface())
		switch newField.Kind() {
		case reflect.String:
			s := newField.String()
			if s != "" {
				oldField.SetString(s)
			}
		case reflect.Int:
			i := newField.Int()
			if i != 0 {
				oldField.SetInt(i)
			}
		case reflect.Bool:
			b := newField.Bool()
			oldField.SetBool(b)
		}
	}
}

func setSelfURL() {
	_, port := splitHostPort(config.ListenAddr)
	selfURL127 = "127.0.0.1:" + port
	selfURLLH = "localhost:" + port
}
<commit_msg>Remove bool command line options.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

var (
	homeDir    string
	selfURL127 string // 127.0.0.1:listenAddr
	selfURLLH  string // localhost:listenAddr
)

const (
	blockedFname       = "auto-blocked"
	directFname        = "auto-direct"
	alwaysBlockedFname = "blocked"
	alwaysDirectFname  = "direct"
	chouFname          = "chou"
	rcFname            = "rc"

	version = "0.3.4"
)

type Config struct {
	RcFile        string // config file
	ListenAddr    string
	SocksAddr     string
	Core          int
	SshServer     string
	UpdateBlocked bool
	UpdateDirect  bool
	AutoRetry     bool
	DetectSSLErr  bool
	LogFile       string
	AlwaysProxy   bool
	ShadowSocks   string
	ShadowPasswd  string

	// not configurable in config file
	PrintVer bool
}

var config Config

var dsFile struct {
	dir           string // directory containing config file and blocked site list
	blocked       string // contains blocked domains
	direct        string // contains sites that can be directly accessed
	alwaysDirect  string
	alwaysBlocked string
	chou          string // chou feng, sites which will be temporary blocked
}

func printVersion() {
	fmt.Println("cow version", version)
}

func init() {
	if isWindows() {
		// On windows, put the configuration file in the same directory of cow executable
		homeDir = path.Base(os.Args[0])
		dsFile.dir = homeDir
	} else {
		u, err := user.Current()
		if err != nil {
			fmt.Printf("Can't get user information %v", err)
			os.Exit(1)
		}
		homeDir = u.HomeDir
		dsFile.dir = path.Join(homeDir, ".cow")
	}
	// fmt.Println("home dir:", homeDir)

	dsFile.blocked = path.Join(dsFile.dir, blockedFname)
	dsFile.direct = path.Join(dsFile.dir, directFname)
	dsFile.alwaysBlocked = path.Join(dsFile.dir, alwaysBlockedFname)
	dsFile.alwaysDirect = path.Join(dsFile.dir, alwaysDirectFname)
	dsFile.chou = path.Join(dsFile.dir, chouFname)
}

func parseCmdLineConfig() *Config {
	var rcFileDefault string
	if isWindows() {
		rcFileDefault = path.Join(homeDir, "rc")
	} else {
		rcFileDefault = "~/.cow/rc"
	}
	var c Config
	flag.StringVar(&c.RcFile, "rc", rcFileDefault, "configuration file")
	flag.StringVar(&c.ListenAddr, "listen", "127.0.0.1:7777", "proxy server listen address")
	flag.StringVar(&c.SocksAddr, "socks", "", "socks proxy address")
	flag.IntVar(&c.Core, "core", 2, "number of cores to use")
	flag.StringVar(&c.SshServer, "sshServer", "", "remote server which will ssh to and provide sock server")
	flag.StringVar(&c.LogFile, "logFile", "", "write output to file, empty means stdout")
	flag.StringVar(&c.ShadowSocks, "shadowSocks", "", "shadowsocks server address")
	flag.StringVar(&c.ShadowPasswd, "shadowPasswd", "", "shadowsocks password")
	flag.BoolVar(&c.PrintVer, "version", false, "print version")

	// Bool options can't be specified on command line because the flag
	// pacakge dosen't provide an easy way to detect if an option is actually
	// given on command line, so we don't know if the option in config file
	// should be override.

	// flag.BoolVar(&c.AutoRetry, "autoRetry", false, "automatically retry timeout requests using socks proxy")
	// flag.BoolVar(&c.UpdateBlocked, "updateBlocked", true, "update blocked site list")
	// flag.BoolVar(&c.UpdateDirect, "updateDirect", true, "update direct site list")
	// flag.BoolVar(&c.DetectSSLErr, "detectSSLErr", true, "detect SSL error based on how soon client closes connection")
	// flag.BoolVar(&c.AlwaysProxy, "alwaysProxy", false, "always use parent proxy")

	flag.Parse()
	return &c
}

// Tries to open a file, if file not exist, return both nil, err
func openFile(path string) (f *os.File, err error) {
	if f, err = os.Open(path); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		errl.Println("Error opening file:", path, err)
		return nil, err
	}
	return
}

func parseBool(v string, msg string) bool {
	switch v {
	case "true":
		return true
	case "false":
		return false
	default:
		fmt.Printf("%s should be true or false\n", msg)
		os.Exit(1)
	}
	return false
}

type configParser struct{}

func (p configParser) ParseListen(val string) {
	config.ListenAddr = val
}

func isServerAddrValid(val string) bool {
	if val == "" {
		return true
	}
	_, port := splitHostPort(val)
	if port == "" {
		return false
	}
	return true
}

func (p configParser) ParseSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("socks server must have port specified")
		os.Exit(1)
	}
	config.SocksAddr = val
}

func (p configParser) ParseCore(val string) {
	if val == "" {
		return
	}
	var err error
	config.Core, err = strconv.Atoi(val)
	if err != nil {
		fmt.Printf("Config error: core number %s %v", val, err)
		os.Exit(1)
	}
}

func (p configParser) ParseSshServer(val string) {
	config.SshServer = val
}

func (p configParser) ParseUpdateBlocked(val string) {
	config.UpdateBlocked = parseBool(val, "updateBlocked")
}

func (p configParser) ParseUpdateDirect(val string) {
	config.UpdateDirect = parseBool(val, "updateDirect")
}

func (p configParser) ParseAutoRetry(val string) {
	config.AutoRetry = parseBool(val, "autoRetry")
}

func (p configParser) ParseDetectSSLErr(val string) {
	config.DetectSSLErr = parseBool(val, "detectSSLErr")
}

func (p configParser) ParseLogFile(val string) {
	config.LogFile = val
}

func (p configParser) ParseAlwaysProxy(val string) {
	config.AlwaysProxy = parseBool(val, "alwaysProxy")
}

func (p configParser) ParseShadowSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("shadowsocks server must have port specified")
		os.Exit(1)
	}
	config.ShadowSocks = val
}

func (p configParser) ParseShadowPasswd(val string) {
	config.ShadowPasswd = val
}

func parseConfig(path string) {
	// fmt.Println("rcFile:", path)
	f, err := os.Open(expandTild(path))
	if err != nil {
		fmt.Println("error opening config file:", err)
		return
	}
	defer f.Close()

	fr := bufio.NewReader(f)

	parser := reflect.ValueOf(configParser{})
	zeroMethod := reflect.Value{}

	var line string
	var n int
	for {
		n++
		line, err = ReadLine(fr)
		if err == io.EOF {
			return
		} else if err != nil {
			errl.Printf("Error reading rc file: %v\n", err)
			os.Exit(1)
		}

		if line == "" {
			continue
		}

		line = strings.TrimSpace(line)
		// Ignore comment
		if line[0] == '#' {
			continue
		}

		v := strings.Split(line, "=")
		if len(v) != 2 {
			fmt.Println("Config error: syntax error on line", n)
			os.Exit(1)
		}
		key, val := strings.TrimSpace(v[0]), strings.TrimSpace(v[1])

		methodName := "Parse" + strings.ToUpper(key[0:1]) + key[1:]
		method := parser.MethodByName(methodName)
		if method == zeroMethod {
			fmt.Printf("Config error: no such option \"%s\"\n", key)
			os.Exit(1)
		}
		args := []reflect.Value{reflect.ValueOf(val)}
		method.Call(args)
	}
}

func updateConfig(new *Config) {
	newVal := reflect.ValueOf(new).Elem()
	oldVal := reflect.ValueOf(&config).Elem()

	// typeOfT := newVal.Type()
	for i := 0; i < newVal.NumField(); i++ {
		newField := newVal.Field(i)
		oldField := oldVal.Field(i)
		// log.Printf("%d: %s %s = %v\n", i,
		// typeOfT.Field(i).Name, newField.Type(), newField.Interface())
		switch newField.Kind() {
		case reflect.String:
			s := newField.String()
			if s != "" {
				oldField.SetString(s)
			}
		case reflect.Int:
			i := newField.Int()
			if i != 0 {
				oldField.SetInt(i)
			}
		}
	}
}

func setSelfURL() {
	_, port := splitHostPort(config.ListenAddr)
	selfURL127 = "127.0.0.1:" + port
	selfURLLH = "localhost:" + port
}
<|endoftext|>


<commit_before>package main

import (
	"gopkg.in/BlueDragonX/go-settings.v0"
)

func ConfigTemplates(configs []*settings.Settings) []Template {
	templates := make([]Template, len(configs))
	for n, config := range configs {
		src := config.StringDflt("src", "")
		dest := config.StringDflt("dest", "")
		if src == "" {
			logger.Fatalf("config '%s.src' is missing", config.Key)
		}
		if dest == "" {
			logger.Fatalf("config '%s.dest' is missing", config.Key)
		}
		templates[n] = Template{Src: src, Dest: dest}
	}
	return templates
}

func resolvePaths(prefix string, keys []string) []string {
	for n, key := range keys {
		keys[n] = joinPaths(prefix, key)
	}
	return keys
}

func ConfigSentinel(config *settings.Settings) *Sentinel {
	client, err := NewClient(config.ObjectDflt("etcd", &settings.Settings{}))
	if err != nil {
		logger.Fatalf("failed to create client: %s", err)
	}

	sentinel := Sentinel{Client: client}

	watchers, err := config.ObjectMap("watchers")
	if err != nil {
		logger.Fatal("config 'watchers' is invalid")
	}
	if len(watchers) == 0 {
		logger.Fatal("config 'watchers' is missing")
	}

	for name, watcher := range watchers {
		prefix := watcher.StringDflt("prefix", "")
		watch := resolvePaths(prefix, watcher.StringArrayDflt("watch", []string{}))
		context := resolvePaths(prefix, watcher.StringArrayDflt("context", []string{}))

		templatesConfig, err := watcher.ObjectArray("templates")
		if err != nil {
			logger.Fatalf("config '%s.templates' is invalid", watcher.Key)
		}
		templates := ConfigTemplates(templatesConfig)

		var command []string
		if cmdStr, err := watcher.String("command"); err == nil {
			command = []string{"bash", "-c", cmdStr}
		} else if cmdArray, err := watcher.StringArray("command"); err == nil {
			command = cmdArray
		}

		if len(templates) == 0 && len(command) == 0 {
			logger.Fatalf("watcher %s templates and command both missing")
		}

		executor := &Executor{
			Name: name,
			Prefix: prefix,
			Context: context,
			Templates: templates,
			Command: command,
		}

		sentinel.Add(watch, executor)
	}

	return &sentinel
}
<commit_msg>gofmt<commit_after>package main

import (
	"gopkg.in/BlueDragonX/go-settings.v0"
)

func ConfigTemplates(configs []*settings.Settings) []Template {
	templates := make([]Template, len(configs))
	for n, config := range configs {
		src := config.StringDflt("src", "")
		dest := config.StringDflt("dest", "")
		if src == "" {
			logger.Fatalf("config '%s.src' is missing", config.Key)
		}
		if dest == "" {
			logger.Fatalf("config '%s.dest' is missing", config.Key)
		}
		templates[n] = Template{Src: src, Dest: dest}
	}
	return templates
}

func resolvePaths(prefix string, keys []string) []string {
	for n, key := range keys {
		keys[n] = joinPaths(prefix, key)
	}
	return keys
}

func ConfigSentinel(config *settings.Settings) *Sentinel {
	client, err := NewClient(config.ObjectDflt("etcd", &settings.Settings{}))
	if err != nil {
		logger.Fatalf("failed to create client: %s", err)
	}

	sentinel := Sentinel{Client: client}

	watchers, err := config.ObjectMap("watchers")
	if err != nil {
		logger.Fatal("config 'watchers' is invalid")
	}
	if len(watchers) == 0 {
		logger.Fatal("config 'watchers' is missing")
	}

	for name, watcher := range watchers {
		prefix := watcher.StringDflt("prefix", "")
		watch := resolvePaths(prefix, watcher.StringArrayDflt("watch", []string{}))
		context := resolvePaths(prefix, watcher.StringArrayDflt("context", []string{}))

		templatesConfig, err := watcher.ObjectArray("templates")
		if err != nil {
			logger.Fatalf("config '%s.templates' is invalid", watcher.Key)
		}
		templates := ConfigTemplates(templatesConfig)

		var command []string
		if cmdStr, err := watcher.String("command"); err == nil {
			command = []string{"bash", "-c", cmdStr}
		} else if cmdArray, err := watcher.StringArray("command"); err == nil {
			command = cmdArray
		}

		if len(templates) == 0 && len(command) == 0 {
			logger.Fatalf("watcher %s templates and command both missing")
		}

		executor := &Executor{
			Name:      name,
			Prefix:    prefix,
			Context:   context,
			Templates: templates,
			Command:   command,
		}

		sentinel.Add(watch, executor)
	}

	return &sentinel
}
<|endoftext|>


<commit_before>/* Callisto - Yet another Solar System simulator
 *
 * Copyright (c) 2016, Valerian Saliou <valerian@valeriansaliou.name>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
  "math"
  "github.com/go-gl/mathgl/mgl32"
)

// Math
const (
  ConfigMathDegreeToRadian float64 = math.Pi / 180
)

// Time
const (
  ConfigTimeSecondToMilliseconds int = 1000
  ConfigTimeMinuteToMilliseconds int = 60 * ConfigTimeSecondToMilliseconds
  ConfigTimeHourToMilliseconds int = 60 * ConfigTimeMinuteToMilliseconds
  ConfigTimeDayToMilliseconds int = 24 * ConfigTimeHourToMilliseconds
  ConfigTimeYearToMilliseconds int = 365 * ConfigTimeDayToMilliseconds

  ConfigTimeStartFromMilliseconds int = ConfigTimeYearToMilliseconds

  ConfigTimeNormalizeFactor float32 = 64.0
)

// Window
const (
  ConfigWindowTitle string = "Callisto - Solar System Simulator"
  ConfigWindowFullScreen bool = true
)

// Speed
const (
  ConfigSpeedFramerateDefault float64 = 60
  ConfigSpeedFramerateFactor float64 = 1.5
)

// Projection
var (
  ConfigProjectionFieldNear float32 = 0.1
  ConfigProjectionFieldFar float32 = 9999999999999999999.0
)

// Camera
var (
  ConfigCameraDefaultEye = mgl32.Vec3{300, -350, -800}
  ConfigCameraDefaultTarget = mgl32.Vec3{0.255, 0.650, 0.000}

  ConfigCameraMoveCelerityCruise = 1.0
  ConfigCameraMoveCelerityTurbo = 10.0

  ConfigCameraInertiaProduceForward = 0.0075
  ConfigCameraInertiaProduceBackward = -0.0075
  ConfigCameraInertiaConsumeForward = -0.005
  ConfigCameraInertiaConsumeBackward = 0.005

  ConfigCameraTargetAmortizeFactor float32 = 0.002
)

// Object
const (
  ConfigObjectTexturePhiMax int = 90
  ConfigObjectTextureThetaMax int = 360
  ConfigObjectTextureStepLatitude int = 3
  ConfigObjectTextureStepLongitude int = 6

  ConfigObjectFullAngle float64 = 4.0 * math.Pi

  ConfigObjectFactorSize float64 = 0.05
  ConfigObjectFactorSpeedScene float64 = 1.0
  ConfigObjectFactorSpeedMaximum float64 = 200000.0
  ConfigObjectFactorSpeedChangeFactor float64 = 100.0
)
<commit_msg>Rollback<commit_after>/* Callisto - Yet another Solar System simulator
 *
 * Copyright (c) 2016, Valerian Saliou <valerian@valeriansaliou.name>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
  "math"
  "github.com/go-gl/mathgl/mgl32"
)

// Math
const (
  ConfigMathDegreeToRadian float64 = math.Pi / 180
)

// Time
const (
  ConfigTimeSecondToMilliseconds int = 1000
  ConfigTimeMinuteToMilliseconds int = 60 * ConfigTimeSecondToMilliseconds
  ConfigTimeHourToMilliseconds int = 60 * ConfigTimeMinuteToMilliseconds
  ConfigTimeDayToMilliseconds int = 24 * ConfigTimeHourToMilliseconds
  ConfigTimeYearToMilliseconds int = 365 * ConfigTimeDayToMilliseconds

  ConfigTimeStartFromMilliseconds int = ConfigTimeYearToMilliseconds

  ConfigTimeNormalizeFactor float32 = 64.0
)

// Window
const (
  ConfigWindowTitle string = "Callisto - Solar System Simulator"
  ConfigWindowFullScreen bool = false
)

// Speed
const (
  ConfigSpeedFramerateDefault float64 = 60
  ConfigSpeedFramerateFactor float64 = 1.5
)

// Projection
var (
  ConfigProjectionFieldNear float32 = 0.1
  ConfigProjectionFieldFar float32 = 9999999999999999999.0
)

// Camera
var (
  ConfigCameraDefaultEye = mgl32.Vec3{300, -350, -800}
  ConfigCameraDefaultTarget = mgl32.Vec3{0.255, 0.650, 0.000}

  ConfigCameraMoveCelerityCruise = 1.0
  ConfigCameraMoveCelerityTurbo = 10.0

  ConfigCameraInertiaProduceForward = 0.0075
  ConfigCameraInertiaProduceBackward = -0.0075
  ConfigCameraInertiaConsumeForward = -0.005
  ConfigCameraInertiaConsumeBackward = 0.005

  ConfigCameraTargetAmortizeFactor float32 = 0.002
)

// Object
const (
  ConfigObjectTexturePhiMax int = 90
  ConfigObjectTextureThetaMax int = 360
  ConfigObjectTextureStepLatitude int = 3
  ConfigObjectTextureStepLongitude int = 6

  ConfigObjectFullAngle float64 = 4.0 * math.Pi

  ConfigObjectFactorSize float64 = 0.05
  ConfigObjectFactorSpeedScene float64 = 1.0
  ConfigObjectFactorSpeedMaximum float64 = 200000.0
  ConfigObjectFactorSpeedChangeFactor float64 = 100.0
)
<|endoftext|>


<commit_before>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

type xmlProperty struct {
	Name  string `xml:"name,attr"`
	Value string `xml:",chardata"`
}

type xmlFilter struct {
	Enabled  string        `xml:"enabled,attr"`
	Tag      string        `xml:"tag"`
	Level    string        `xml:"level"`
	Type     string        `xml:"type"`
	Property []xmlProperty `xml:"property"`
}

type xmlLoggerConfig struct {
	Filter []xmlFilter `xml:"filter"`
}

// Load XML configuration; see examples/example.xml for documentation
func (log Logger) LoadConfiguration(filename string) {
	log.Close()

	// Open the configuration file
	fd, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
		os.Exit(1)
	}

	contents, err := ioutil.ReadAll(fd)
	if err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
		os.Exit(1)
	}

	xc := new(xmlLoggerConfig)
	if err := xml.Unmarshal(contents, xc); err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
		os.Exit(1)
	}

	for _, xmlfilt := range xc.Filter {
		var filt LogWriter
		var lvl level
		bad, good, enabled := false, true, false

		// Check required children
		if len(xmlfilt.Enabled) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
			bad = true
		} else {
			enabled = xmlfilt.Enabled != "false"
		}
		if len(xmlfilt.Tag) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
			bad = true
		}
		if len(xmlfilt.Type) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
			bad = true
		}
		if len(xmlfilt.Level) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
			bad = true
		}

		switch xmlfilt.Level {
		case "FINEST":
			lvl = FINEST
		case "FINE":
			lvl = FINE
		case "DEBUG":
			lvl = DEBUG
		case "TRACE":
			lvl = TRACE
		case "INFO":
			lvl = INFO
		case "WARNING":
			lvl = WARNING
		case "ERROR":
			lvl = ERROR
		case "CRITICAL":
			lvl = CRITICAL
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
			bad = true
		}

		// Just so all of the required attributes are errored at the same time if missing
		if bad {
			os.Exit(1)
		}

		switch xmlfilt.Type {
		case "console":
			filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
		case "file":
			filt, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
		case "xml":
			filt, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
		case "socket":
			filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
			os.Exit(1)
		}

		// Just so all of the required params are errored at the same time if wrong
		if !good {
			os.Exit(1)
		}

		// If we're disabled (syntax and correctness checks only), don't add to logger
		if !enabled {
			continue
		}

		log[xmlfilt.Tag] = &Filter{lvl, filename, filt}
	}
}

func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (ConsoleLogWriter, bool) {
	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
		}
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	return NewConsoleLogWriter(), true
}

// Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
func strToNumSuffix(str string, mult int) int {
	num := 1
	if len(str) > 1 {
		switch str[len(str)-1] {
		case 'G', 'g':
			num *= mult
			fallthrough
		case 'M', 'm':
			num *= mult
			fallthrough
		case 'K', 'k':
			num *= mult
			str = str[0 : len(str)-1]
		}
	}
	parsed, _ := strconv.Atoi(str)
	return parsed * num
}
func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
	file := ""
	format := "[%D %T] [%L] (%S) %M"
	maxlines := 0
	maxsize := 0
	daily := false
	rotate := false

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "filename":
			file = strings.Trim(prop.Value, " \r\n")
		case "format":
			format = strings.Trim(prop.Value, " \r\n")
		case "maxlines":
			maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
		case "maxsize":
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
		case "daily":
			daily = strings.Trim(prop.Value, " \r\n") != "false"
		case "rotate":
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(file) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	flw := NewFileLogWriter(file, rotate)
	flw.SetFormat(format)
	flw.SetRotateLines(maxlines)
	flw.SetRotateSize(maxsize)
	flw.SetRotateDaily(daily)
	return flw, true
}

func xmlToXMLLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
	file := ""
	maxrecords := 0
	maxsize := 0
	daily := false
	rotate := false

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "filename":
			file = strings.Trim(prop.Value, " \r\n")
		case "maxrecords":
			maxrecords = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
		case "maxsize":
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
		case "daily":
			daily = strings.Trim(prop.Value, " \r\n") != "false"
		case "rotate":
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for xml filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(file) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for xml filter missing in %s\n", "filename", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	xlw := NewXMLLogWriter(file, rotate)
	xlw.SetRotateLines(maxrecords)
	xlw.SetRotateSize(maxsize)
	xlw.SetRotateDaily(daily)
	return xlw, true
}

func xmlToSocketLogWriter(filename string, props []xmlProperty, enabled bool) (SocketLogWriter, bool) {
	endpoint := ""
	protocol := "udp"

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "endpoint":
			endpoint = strings.Trim(prop.Value, " \r\n")
		case "protocol":
			protocol = strings.Trim(prop.Value, " \r\n")
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(endpoint) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "endpoint", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	return NewSocketLogWriter(protocol, endpoint), true
}
<commit_msg>	modified:   config.go<commit_after>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

type xmlProperty struct {
	Name  string `xml:"name,attr"`
	Value string `xml:",chardata"`
}

type xmlFilter struct {
	Enabled  string        `xml:"enabled,attr"`
	Tag      string        `xml:"tag"`
	Level    string        `xml:"level"`
	Type     string        `xml:"type"`
	Property []xmlProperty `xml:"property"`
}

type xmlLoggerConfig struct {
	Filter []xmlFilter `xml:"filter"`
}

// Load XML configuration; see examples/example.xml for documentation
func (log Logger) LoadConfiguration(filename string) {
	log.Close()

	// Open the configuration file
	fd, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
		os.Exit(1)
	}

	contents, err := ioutil.ReadAll(fd)
	if err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
		os.Exit(1)
	}

	xc := new(xmlLoggerConfig)
	if err := xml.Unmarshal(contents, xc); err != nil {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
		os.Exit(1)
	}

	for _, xmlfilt := range xc.Filter {
		var filt LogWriter
		var lvl level
		bad, good, enabled := false, true, false

		// Check required children
		if len(xmlfilt.Enabled) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
			bad = true
		} else {
			enabled = xmlfilt.Enabled != "false"
		}
		if len(xmlfilt.Tag) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
			bad = true
		}
		if len(xmlfilt.Type) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
			bad = true
		}
		if len(xmlfilt.Level) == 0 {
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
			bad = true
		}

		switch xmlfilt.Level {
		case "FINEST":
			lvl = FINEST
		case "FINE":
			lvl = FINE
		case "DEBUG":
			lvl = DEBUG
		case "TRACE":
			lvl = TRACE
		case "INFO":
			lvl = INFO
		case "WARNING":
			lvl = WARNING
		case "ERROR":
			lvl = ERROR
		case "CRITICAL":
			lvl = CRITICAL
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
			bad = true
		}

		// Just so all of the required attributes are errored at the same time if missing
		if bad {
			os.Exit(1)
		}

		switch xmlfilt.Type {
		case "console":
			filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
		case "file":
			filt, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
		case "xml":
			filt, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
		case "socket":
			filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
			os.Exit(1)
		}

		// Just so all of the required params are errored at the same time if wrong
		if !good {
			os.Exit(1)
		}

		// If we're disabled (syntax and correctness checks only), don't add to logger
		if !enabled {
			continue
		}

		log[xmlfilt.Tag] = &Filter{lvl, filename, filt}
	}
}

func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (ConsoleLogWriter, bool) {
	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
		}
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	return NewConsoleLogWriter(), true
}

// Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
func strToNumSuffix(str string, mult int) int {
	num := 1
	if len(str) > 1 {
		switch str[len(str)-1] {
		case 'G', 'g':
			num *= mult
			fallthrough
		case 'M', 'm':
			num *= mult
			fallthrough
		case 'K', 'k':
			num *= mult
			str = str[0 : len(str)-1]
		}
	}
	parsed, _ := strconv.Atoi(str)
	return parsed * num
}
func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
	file := filename
	format := "[%D %T] [%L] (%S) %M"
	maxlines := 0
	maxsize := 0
	daily := false
	rotate := false

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "filename":
			file = strings.Trim(prop.Value, " \r\n")
		case "format":
			format = strings.Trim(prop.Value, " \r\n")
		case "maxlines":
			maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
		case "maxsize":
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
		case "daily":
			daily = strings.Trim(prop.Value, " \r\n") != "false"
		case "rotate":
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(file) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	flw := NewFileLogWriter(file, rotate)
	flw.SetFormat(format)
	flw.SetRotateLines(maxlines)
	flw.SetRotateSize(maxsize)
	flw.SetRotateDaily(daily)
	return flw, true
}

func xmlToXMLLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
	file := ""
	maxrecords := 0
	maxsize := 0
	daily := false
	rotate := false

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "filename":
			file = strings.Trim(prop.Value, " \r\n")
		case "maxrecords":
			maxrecords = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
		case "maxsize":
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
		case "daily":
			daily = strings.Trim(prop.Value, " \r\n") != "false"
		case "rotate":
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for xml filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(file) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for xml filter missing in %s\n", "filename", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	xlw := NewXMLLogWriter(file, rotate)
	xlw.SetRotateLines(maxrecords)
	xlw.SetRotateSize(maxsize)
	xlw.SetRotateDaily(daily)
	return xlw, true
}

func xmlToSocketLogWriter(filename string, props []xmlProperty, enabled bool) (SocketLogWriter, bool) {
	endpoint := ""
	protocol := "udp"

	// Parse properties
	for _, prop := range props {
		switch prop.Name {
		case "endpoint":
			endpoint = strings.Trim(prop.Value, " \r\n")
		case "protocol":
			protocol = strings.Trim(prop.Value, " \r\n")
		default:
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
		}
	}

	// Check properties
	if len(endpoint) == 0 {
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "endpoint", filename)
		return nil, false
	}

	// If it's disabled, we're just checking syntax
	if !enabled {
		return nil, true
	}

	return NewSocketLogWriter(protocol, endpoint), true
}
<|endoftext|>


<commit_before>//  The MIT License (MIT) - http://opensource.org/licenses/MIT
//
//  Copyright (c) 2014 slowfei
//
//  Create on 2014-08-16
//  Update on 2014-09-25
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//
package gosfdoc

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"io/ioutil"
	"path/filepath"
)

const (
	DEFAULT_CONFIG_FILE_NAME = "gosfdoc.json"
)

var (
	_gosfdocConfigJson = `{
    "ScanPath"         : %#v,
    "CodeLang"         : [%v],
    "Outdir"           : "doc",
    "OutAppendPath"    : "",
    "CopyCode"         : false,
    "HtmlTitle"        : "Document",
    "DocTitle"         : "Document:",
    "MenuTitle"        : "package",
    "Languages"        : {"default" : "Default"},
    "FilterPaths"      : []
}`
)

/**
 *  main config info
 *  output `gosfdoc.json` use
 */
type MainConfig struct {
	path          string            // private handle path, save console command path.
	ScanPath      string            // scan document info file path, relative or absolute path, is "/" scan current console path.
	CodeLang      []string          // code languages
	Outdir        string            // output document directory
	OutAppendPath string            // append output source code and markdown relative path(scan path join). defalut ""
	CopyCode      bool              // whether output source code to document directory
	HtmlTitle     string            // document html show title
	DocTitle      string            // html top tabbar show title
	MenuTitle     string            // html left menu show title
	Languages     map[string]string // document support the language. key is lang dirctory name, value is show text
	FilterPaths   []string          // filter path, relative or absolute path
}

/**
 *	set absolute path
 */
func (mc *MainConfig) setAbspath() {

	mc.path = SFFileManager.GetCmdDir()

	if 0 == len(mc.ScanPath) || "/" == mc.ScanPath {
		mc.ScanPath = mc.path
	} else if !filepath.IsAbs(mc.ScanPath) {
		mc.ScanPath = filepath.Join(mc.path, mc.ScanPath)
	}

	if !filepath.IsAbs(mc.Outdir) {
		mc.Outdir = filepath.Join(mc.ScanPath, mc.Outdir)
	}

	for i := 0; i < len(mc.FilterPaths); i++ {
		p := mc.FilterPaths[i]
		if !filepath.IsAbs(p) {
			mc.FilterPaths[i] = filepath.Join(mc.ScanPath, p)
		}
	}
}

/**
 *  check config param value
 *  error value will update default.
 *
 *  @return error
 *  @return bool    fatal error is false, pass is true. (pass does not mean that there are no errors)
 */
func (mc *MainConfig) Check() (error, bool) {
	errBuf := bytes.NewBufferString("")
	pass := true

	mc.path = SFFileManager.GetCmdDir()

	if 0 == len(mc.ScanPath) {
		errBuf.WriteString("ScanPath: please set document scan path.\n")
		pass = false
	}

	if 0 == len(mc.CodeLang) {
		errBuf.WriteString("CodeLang: specify code language type nil.\n")
		pass = false
	} else {
		count := len(mc.CodeLang)
		for i := 0; i < count; i++ {
			lang := mc.CodeLang[i]
			if _, ok := _mapParser[lang]; !ok {
				errBuf.WriteString("CodeLang: not " + lang + " Parser.\n")
			}
		}
	}

	if 0 == len(mc.Outdir) {
		errBuf.WriteString("Outdir: output directory is nil, will use 'doc' default directory.\n")
		mc.Outdir = "doc"
	}

	if 0 == len(mc.HtmlTitle) {
		mc.HtmlTitle = "Document"
		errBuf.WriteString("HtmlTitle: to set the html title.\n")
	}

	if 0 == len(mc.DocTitle) {
		mc.DocTitle = "Document:"
		errBuf.WriteString("DocTitle: to set the doc title.\n")
	}

	if 0 == len(mc.MenuTitle) {
		mc.MenuTitle = "package"
		errBuf.WriteString("MenuTitle: to set the menu title.\n")
	}

	if 0 == len(mc.Languages) {
		mc.Languages = map[string]string{"Default": "default"}
		errBuf.WriteString("Languages: to set the default html text language.\n")
	} else {
		if _, ok := mc.Languages["default"]; !ok {
			mc.Languages["default"] = "Default"
			errBuf.WriteString("Languages: to set the default html text language.\n")
		}
	}

	var err error = nil
	if 0 != errBuf.Len() {
		err = errors.New(errBuf.String())
	}

	return err, pass
}

/**
 *  document directory html javascript use config
 *
 *  output `config.json`
 */
type DocConfig struct {
	ContentJson string                   // content json file
	IntroMd     string                   // intro markdown file
	AboutMd     string                   // about markdown file
	Languages   map[string]string        // key is directory name, value is show text
	Markdowns   map[string][]PackageInfo // markdown info list
}

/**
 *  conifg load
 *
 *  @param jsonData
 *  @return load error info
 */
func configLoadByJson(jsonData []byte, c *MainConfig) error {
	e2 := json.Unmarshal(jsonData, c)
	if nil != e2 {
		return e2
	}
	return nil
}

/**
 *  conifg load
 *
 *  @param configPath
 *  @return error info
 */
func configLoadByFilepath(configPath string, c *MainConfig) error {

	var path string
	if filepath.IsAbs(configPath) {
		path = configPath
	} else {
		path = filepath.Join(SFFileManager.GetExecDir(), configPath)
	}

	isExists, isDir, _ := SFFileManager.Exists(path)
	if !isExists || isDir {
		return errors.New("failed to load configuration file:" + configPath)
	}

	jsonData, e1 := ioutil.ReadFile(path)
	if nil != e1 {
		return e1
	}

	return configLoadByJson(jsonData, c)
}
<commit_msg>修改输出目录的参数架构Outdir更改为Outpath<commit_after>//  The MIT License (MIT) - http://opensource.org/licenses/MIT
//
//  Copyright (c) 2014 slowfei
//
//  Create on 2014-08-16
//  Update on 2014-09-30
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//
package gosfdoc

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"io/ioutil"
	"path/filepath"
)

const (
	DEFAULT_CONFIG_FILE_NAME = "gosfdoc.json"
	DEFAULT_OUTPATH          = "doc"
)

var (
	_gosfdocConfigJson = `{
    "ScanPath"         : %#v,
    "CodeLang"         : [%v],
    "Outpath"          : "doc",
    "OutAppendPath"    : "",
    "CopyCode"         : false,
    "CodeLinkRoot"     : true,
    "HtmlTitle"        : "Document",
    "DocTitle"         : "Document:",
    "MenuTitle"        : "package",
    "Languages"        : {"default" : "Default"},
    "FilterPaths"      : []
}`
)

/**
 *  main config info
 *  output `gosfdoc.json` use
 */
type MainConfig struct {
	path          string            // private handle path, save console command path.
	ScanPath      string            // scan document info file path, relative or absolute path, is "/" scan current console path.
	CodeLang      []string          // code languages
	Outpath       string            // output document path, relative or absolute path.
	OutAppendPath string            // append output source code and markdown relative path(scan path join). defalut ""
	CopyCode      bool              // copy source code to document directory. default false
	CodeLinkRoot  bool              // source code link to root directory, 'CopyCode' is true was invalid default true
	HtmlTitle     string            // document html show title
	DocTitle      string            // html top tabbar show title
	MenuTitle     string            // html left menu show title
	Languages     map[string]string // document support the language. key is directory name, value is show text.
	FilterPaths   []string          // filter path, relative or absolute path
}

/**
 *	set absolute path
 */
func (mc *MainConfig) setAbspath() {

	mc.path = SFFileManager.GetCmdDir()

	if 0 == len(mc.ScanPath) || "/" == mc.ScanPath {
		mc.ScanPath = mc.path
	} else if !filepath.IsAbs(mc.ScanPath) {
		mc.ScanPath = filepath.Join(mc.path, mc.ScanPath)
	}

	if 0 == len(mc.Outpath) {
		mc.Outpath = filepath.Join(mc.ScanPath, DEFAULT_OUTPATH)
	} else if !filepath.IsAbs(mc.Outpath) {
		mc.Outpath = filepath.Join(mc.ScanPath, mc.Outpath)
	}

	for i := 0; i < len(mc.FilterPaths); i++ {
		p := mc.FilterPaths[i]
		if !filepath.IsAbs(p) {
			mc.FilterPaths[i] = filepath.Join(mc.ScanPath, p)
		}
	}
}

/**
 *  check config param value
 *  error value will update default.
 *
 *  @return error
 *  @return bool    fatal error is false, pass is true. (pass does not mean that there are no errors)
 */
func (mc *MainConfig) Check() (error, bool) {
	errBuf := bytes.NewBufferString("")
	pass := true

	mc.path = SFFileManager.GetCmdDir()

	if 0 == len(mc.ScanPath) {
		errBuf.WriteString("ScanPath: please set document scan path.\n")
		pass = false
	}

	if 0 == len(mc.CodeLang) {
		errBuf.WriteString("CodeLang: specify code language type nil.\n")
		pass = false
	} else {
		count := len(mc.CodeLang)
		for i := 0; i < count; i++ {
			lang := mc.CodeLang[i]
			if _, ok := _mapParser[lang]; !ok {
				errBuf.WriteString("CodeLang: not " + lang + " Parser.\n")
			}
		}
	}

	if 0 == len(mc.Outpath) {
		errBuf.WriteString("Outdir: output directory is nil, will use 'doc' default directory.\n")
		mc.Outpath = DEFAULT_OUTPATH
	}

	if 0 == len(mc.HtmlTitle) {
		mc.HtmlTitle = "Document"
		errBuf.WriteString("HtmlTitle: to set the html title.\n")
	}

	if 0 == len(mc.DocTitle) {
		mc.DocTitle = "Document:"
		errBuf.WriteString("DocTitle: to set the doc title.\n")
	}

	if 0 == len(mc.MenuTitle) {
		mc.MenuTitle = "package"
		errBuf.WriteString("MenuTitle: to set the menu title.\n")
	}

	if 0 == len(mc.Languages) {
		mc.Languages = map[string]string{"Default": "default"}
		errBuf.WriteString("Languages: to set the default html text language.\n")
	} else {
		if _, ok := mc.Languages["default"]; !ok {
			mc.Languages["default"] = "Default"
			errBuf.WriteString("Languages: to set the default html text language.\n")
		}
	}

	var err error = nil
	if 0 != errBuf.Len() {
		err = errors.New(errBuf.String())
	}

	return err, pass
}

/**
 *  document directory html javascript use config
 *
 *  output `config.json`
 */
type DocConfig struct {
	ContentJson string                   // content json file
	IntroMd     string                   // intro markdown file
	AboutMd     string                   // about markdown file
	Languages   map[string]string        // key is directory name, value is show text
	Markdowns   map[string][]PackageInfo // markdown info list
}

/**
 *  conifg load
 *
 *  @param jsonData
 *  @return load error info
 */
func configLoadByJson(jsonData []byte, c *MainConfig) error {
	e2 := json.Unmarshal(jsonData, c)
	if nil != e2 {
		return e2
	}
	return nil
}

/**
 *  conifg load
 *
 *  @param configPath
 *  @return error info
 */
func configLoadByFilepath(configPath string, c *MainConfig) error {

	var path string
	if filepath.IsAbs(configPath) {
		path = configPath
	} else {
		path = filepath.Join(SFFileManager.GetExecDir(), configPath)
	}

	isExists, isDir, _ := SFFileManager.Exists(path)
	if !isExists || isDir {
		return errors.New("failed to load configuration file:" + configPath)
	}

	jsonData, e1 := ioutil.ReadFile(path)
	if nil != e1 {
		return e1
	}

	return configLoadByJson(jsonData, c)
}
<|endoftext|>


<commit_before>package hal

import (
	"fmt"
	"net/http"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/danryan/env"
)

// Config struct
type config struct {
	Name        string `env:"key=HAL_NAME default=hal"`
	Alias       string `env:"key=HAL_ALIAS"`
	AdapterName string `env:"key=HAL_ADAPTER default=shell"`
	StoreName   string `env:"key=HAL_STORE default=memory"`
	Port        int    `env:"key=PORT default=9000"`
	LogLevel    string `env:"key=HAL_LOG_LEVEL default=info"`
}

func newConfig() *config {
	c := &config{}
	env.MustProcess(c)
	return c
}

func newLogger() *logrus.Logger {
	level, err := logrus.ParseLevel(Config.LogLevel)
	if err != nil {
		panic(err)
	}
	return &logrus.Logger{
		Level: level,
	}
}

// newRouter initializes a new http.ServeMux and sets up several default routes
func newRouter() *http.ServeMux {
	router := http.NewServeMux()
	router.HandleFunc("/hal/ping", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "PONG")
	})

	router.HandleFunc("/hal/time", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Server time is: %s\n", time.Now().UTC())
	})

	return router
}
<commit_msg>Correctly instantiate new logger<commit_after>package hal

import (
	"fmt"
	"net/http"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/danryan/env"
)

// Config struct
type config struct {
	Name        string `env:"key=HAL_NAME default=hal"`
	Alias       string `env:"key=HAL_ALIAS"`
	AdapterName string `env:"key=HAL_ADAPTER default=shell"`
	StoreName   string `env:"key=HAL_STORE default=memory"`
	Port        int    `env:"key=PORT default=9000"`
	LogLevel    string `env:"key=HAL_LOG_LEVEL default=info"`
}

func newConfig() *config {
	c := &config{}
	env.MustProcess(c)
	return c
}

func newLogger() *logrus.Logger {
	level, err := logrus.ParseLevel(Config.LogLevel)
	if err != nil {
		panic(err)
	}
	logger := logrus.New()
	logger.Level = level

	return logger
}

// newRouter initializes a new http.ServeMux and sets up several default routes
func newRouter() *http.ServeMux {
	router := http.NewServeMux()
	router.HandleFunc("/hal/ping", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "PONG")
	})

	router.HandleFunc("/hal/time", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Server time is: %s\n", time.Now().UTC())
	})

	return router
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.com/phrase/phraseapp-api-client/Godeps/_workspace/src/gopkg.in/yaml.v2"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const configName = ".phraseapp.yml"
const defaultDir = ".config/phraseapp"

func ConfigDefaultCredentials() (*phraseapp.AuthCredentials, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCredentials(content)
}

func ConfigDefaultParams() (phraseapp.DefaultParams, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseDefaults(content)
}

func ConfigCallArgs() (map[string]string, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCallArgs(content)
}

// Paths and content
func ConfigContent() (string, error) {
	path, err := phraseConfigPath()
	if err != nil {
		return "{}", nil
	}

	bytes, err := readFile(path)
	if err != nil {
		return "{}", nil
	}
	return string(bytes), nil
}

func phraseConfigPath() (string, error) {
	callerPath, err := os.Getwd()
	if err != nil {
		return "", err
	}

	possiblePath := path.Join(callerPath, configName)
	if _, err := os.Stat(possiblePath); err == nil {
		return possiblePath, nil
	}

	return defaultConfigDir()
}

func readFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	return ioutil.ReadAll(file)
}

func defaultConfigDir() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", nil
	}
	return path.Join(usr.HomeDir, defaultDir, configName), nil
}

// Parsing
type credentialConf struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		Host        string `yaml:"host"`
		Username    string
		TFA         bool
	}
}

func parseCredentials(yml string) (*phraseapp.AuthCredentials, error) {
	var conf *credentialConf

	if err := yaml.Unmarshal([]byte(yml), &conf); err != nil {
		return nil, err
	}

	phrase := conf.Phraseapp
	credentials := &phraseapp.AuthCredentials{Token: phrase.AccessToken, Username: phrase.Username, TFA: phrase.TFA, Host: phrase.Host}

	return credentials, nil
}

type defaultsConf struct {
	Phraseapp struct {
		Defaults phraseapp.DefaultParams
	}
}

func parseDefaults(yml string) (phraseapp.DefaultParams, error) {
	var conf *defaultsConf

	err := yaml.Unmarshal([]byte(yml), &conf)
	if err != nil {
		return nil, err
	}

	return conf.Phraseapp.Defaults, nil
}

type CallArgs struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		ProjectId   string `yaml:"project_id"`
		Page        int
		PerPage     int
	}
}

func parseCallArgs(yml string) (map[string]string, error) {
	var callArgs *CallArgs

	err := yaml.Unmarshal([]byte(yml), &callArgs)
	if err != nil {
		return nil, err
	}

	m := make(map[string]string)

	if callArgs != nil {
		m["ProjectId"] = callArgs.Phraseapp.ProjectId
		m["AccessToken"] = callArgs.Phraseapp.AccessToken
	}

	return m, nil
}
<commit_msg>adds output about parsing error in  yml<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.com/phrase/phraseapp-api-client/Godeps/_workspace/src/gopkg.in/yaml.v2"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const configName = ".phraseapp.yml"
const defaultDir = ".config/phraseapp"

func ConfigDefaultCredentials() (*phraseapp.AuthCredentials, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCredentials(content)
}

func ConfigDefaultParams() (phraseapp.DefaultParams, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseDefaults(content)
}

func ConfigCallArgs() (map[string]string, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCallArgs(content)
}

// Paths and content
func ConfigContent() (string, error) {
	path, err := phraseConfigPath()
	if err != nil {
		return "{}", nil
	}

	bytes, err := readFile(path)
	if err != nil {
		return "{}", nil
	}
	return string(bytes), nil
}

func phraseConfigPath() (string, error) {
	callerPath, err := os.Getwd()
	if err != nil {
		return "", err
	}

	possiblePath := path.Join(callerPath, configName)
	if _, err := os.Stat(possiblePath); err == nil {
		return possiblePath, nil
	}

	return defaultConfigDir()
}

func readFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	return ioutil.ReadAll(file)
}

func defaultConfigDir() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", nil
	}
	return path.Join(usr.HomeDir, defaultDir, configName), nil
}

// Parsing
type credentialConf struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		Host        string `yaml:"host"`
		Username    string
		TFA         bool
	}
}

func parseCredentials(yml string) (*phraseapp.AuthCredentials, error) {
	var conf *credentialConf

	if err := yaml.Unmarshal([]byte(yml), &conf); err != nil {
		fmt.Println("Could not parse .phraseapp.yml")
		return nil, err
	}

	phrase := conf.Phraseapp
	credentials := &phraseapp.AuthCredentials{Token: phrase.AccessToken, Username: phrase.Username, TFA: phrase.TFA, Host: phrase.Host}

	return credentials, nil
}

type defaultsConf struct {
	Phraseapp struct {
		Defaults phraseapp.DefaultParams
	}
}

func parseDefaults(yml string) (phraseapp.DefaultParams, error) {
	var conf *defaultsConf

	err := yaml.Unmarshal([]byte(yml), &conf)
	if err != nil {
		fmt.Println("Could not parse .phraseapp.yml")
		return nil, err
	}

	return conf.Phraseapp.Defaults, nil
}

type CallArgs struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		ProjectId   string `yaml:"project_id"`
		Page        int
		PerPage     int
	}
}

func parseCallArgs(yml string) (map[string]string, error) {
	var callArgs *CallArgs

	err := yaml.Unmarshal([]byte(yml), &callArgs)
	if err != nil {
		return nil, err
	}

	m := make(map[string]string)

	if callArgs != nil {
		m["ProjectId"] = callArgs.Phraseapp.ProjectId
		m["AccessToken"] = callArgs.Phraseapp.AccessToken
	}

	return m, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"strings"
	"time"

	"encoding/gob"
	"encoding/json"
	"encoding/xml"
)

type Config struct {
	serverAddr     string
	logFilename    string
	sampleFilename string
	format         string

	ServerAddr *net.TCPAddr
	TimeLimit  time.Duration
	MeterID    uint

	CenterFreq int

	SymbolLength int

	BlockSize  uint
	SampleRate uint

	PreambleLength uint
	PacketLength   uint

	Log     *log.Logger
	LogFile *os.File

	GobUnsafe bool
	Encoder   Encoder

	SampleFile *os.File

	Quiet  bool
	Single bool
}

func (c *Config) Parse() (err error) {
	flag.StringVar(&c.serverAddr, "server", "127.0.0.1:1234", "address or hostname of rtl_tcp instance")
	flag.StringVar(&c.logFilename, "logfile", "/dev/stdout", "log statement dump file")
	flag.StringVar(&c.sampleFilename, "samplefile", os.DevNull, "received message signal dump file, offset and message length are displayed to log when enabled")

	flag.IntVar(&c.CenterFreq, "centerfreq", 920299072, "center frequency to receive on")
	flag.IntVar(&c.SymbolLength, "symbollength", 73, `symbol length in samples, bandwidth and performance are determined by this value
	narrow/fast:   ( 8, 262.144 kHz)
	medium/medium: (32,   1.048 MHz), (48, 1.572 MHz)
	wide/slow:     (56,   1.835 MHz), (64, 2.097 MHz), (73, 2.392 MHz)
	valid lengths: [7, 8, 9, 28, 32, 48, 50, 56, 64, 72, 73]`)

	flag.DurationVar(&c.TimeLimit, "duration", 0, "time to run for, 0 for infinite")
	flag.UintVar(&c.MeterID, "filterid", 0, "display only messages matching given id")
	flag.StringVar(&c.format, "format", "plain", "format to write log messages in: plain, json, xml or gob")
	flag.BoolVar(&c.GobUnsafe, "gobunsafe", false, "allow gob output to stdout")
	flag.BoolVar(&c.Quiet, "quiet", false, "suppress state information printed at startup")
	flag.BoolVar(&c.Single, "single", false, "provides one shot execution, listens until exactly one message is recieved")

	flag.Parse()

	validSymbolLengths := map[int]bool{7: true, 8: true, 9: true, 28: true, 32: true, 48: true, 50: true, 56: true, 64: true, 72: true}

	if !validSymbolLengths[c.SymbolLength] {
		return fmt.Errorf("invalid symbol length: %d", c.SymbolLength)
	}

	c.SampleRate = DataRate * uint(c.SymbolLength)

	c.PreambleLength = PreambleSymbols * uint(c.SymbolLength)
	c.PacketLength = PacketSymbols * uint(c.SymbolLength)

	// Power of two sized DFT requires BlockSize to also be power of two.
	// BlockSize must be greater than the preamble length, so calculate next
	// largest power of two from preamble length.
	c.BlockSize = NextPowerOf2(c.PreambleLength)

	// Parse and resolve rtl_tcp server address.
	c.ServerAddr, err = net.ResolveTCPAddr("tcp", c.serverAddr)
	if err != nil {
		return
	}

	// Open or create the log file.
	if c.logFilename == "/dev/stdout" {
		c.LogFile = os.Stdout
	} else {
		c.LogFile, err = os.Create(c.logFilename)
	}

	// Create a new logger with the log file as output.
	c.Log = log.New(c.LogFile, "", log.Ldate|log.Lmicroseconds)
	if err != nil {
		return
	}

	// Create the sample file.
	c.SampleFile, err = os.Create(c.sampleFilename)
	if err != nil {
		return
	}

	// Create encoder for specified logging format.
	switch strings.ToLower(c.format) {
	case "plain":
		break
	case "json":
		c.Encoder = json.NewEncoder(c.LogFile)
	case "xml":
		c.Encoder = xml.NewEncoder(c.LogFile)
	case "gob":
		c.Encoder = gob.NewEncoder(c.LogFile)

		// Don't let the user output gob to stdout unless they really want to.
		if !c.GobUnsafe && c.logFilename == "/dev/stdout" {
			fmt.Println("Gob encoded messages are not stdout safe, specify logfile or use gobunsafe flag.")
			os.Exit(1)
		}
	default:
		// We didn't get a valid encoder, exit and say so.
		log.Fatal("Invalid log format:", c.format)
	}

	return
}

func (c Config) Close() {
	c.LogFile.Close()
	c.SampleFile.Close()
}

// JSON, XML and GOB all implement this interface so we can simplify log
// output formatting.
type Encoder interface {
	Encode(interface{}) error
}

func NextPowerOf2(v uint) uint {
	return 1 << uint(math.Ceil(math.Log2(float64(v))))
}
<commit_msg>Add maximum symbol length to valid lengths to match usage.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"strings"
	"time"

	"encoding/gob"
	"encoding/json"
	"encoding/xml"
)

type Config struct {
	serverAddr     string
	logFilename    string
	sampleFilename string
	format         string

	ServerAddr *net.TCPAddr
	TimeLimit  time.Duration
	MeterID    uint

	CenterFreq int

	SymbolLength int

	BlockSize  uint
	SampleRate uint

	PreambleLength uint
	PacketLength   uint

	Log     *log.Logger
	LogFile *os.File

	GobUnsafe bool
	Encoder   Encoder

	SampleFile *os.File

	Quiet  bool
	Single bool
}

func (c *Config) Parse() (err error) {
	flag.StringVar(&c.serverAddr, "server", "127.0.0.1:1234", "address or hostname of rtl_tcp instance")
	flag.StringVar(&c.logFilename, "logfile", "/dev/stdout", "log statement dump file")
	flag.StringVar(&c.sampleFilename, "samplefile", os.DevNull, "received message signal dump file, offset and message length are displayed to log when enabled")

	flag.IntVar(&c.CenterFreq, "centerfreq", 920299072, "center frequency to receive on")
	flag.IntVar(&c.SymbolLength, "symbollength", 73, `symbol length in samples, bandwidth and performance are determined by this value
	narrow/fast:   ( 8, 262.144 kHz)
	medium/medium: (32,   1.048 MHz), (48, 1.572 MHz)
	wide/slow:     (56,   1.835 MHz), (64, 2.097 MHz), (73, 2.392 MHz)
	valid lengths: [7, 8, 9, 28, 32, 48, 50, 56, 64, 72, 73]`)

	flag.DurationVar(&c.TimeLimit, "duration", 0, "time to run for, 0 for infinite")
	flag.UintVar(&c.MeterID, "filterid", 0, "display only messages matching given id")
	flag.StringVar(&c.format, "format", "plain", "format to write log messages in: plain, json, xml or gob")
	flag.BoolVar(&c.GobUnsafe, "gobunsafe", false, "allow gob output to stdout")
	flag.BoolVar(&c.Quiet, "quiet", false, "suppress state information printed at startup")
	flag.BoolVar(&c.Single, "single", false, "provides one shot execution, listens until exactly one message is recieved")

	flag.Parse()

	validSymbolLengths := map[int]bool{7: true, 8: true, 9: true, 28: true, 32: true, 48: true, 50: true, 56: true, 64: true, 72: true, 73: true}

	if !validSymbolLengths[c.SymbolLength] {
		return fmt.Errorf("invalid symbol length: %d", c.SymbolLength)
	}

	c.SampleRate = DataRate * uint(c.SymbolLength)

	c.PreambleLength = PreambleSymbols * uint(c.SymbolLength)
	c.PacketLength = PacketSymbols * uint(c.SymbolLength)

	// Power of two sized DFT requires BlockSize to also be power of two.
	// BlockSize must be greater than the preamble length, so calculate next
	// largest power of two from preamble length.
	c.BlockSize = NextPowerOf2(c.PreambleLength)

	// Parse and resolve rtl_tcp server address.
	c.ServerAddr, err = net.ResolveTCPAddr("tcp", c.serverAddr)
	if err != nil {
		return
	}

	// Open or create the log file.
	if c.logFilename == "/dev/stdout" {
		c.LogFile = os.Stdout
	} else {
		c.LogFile, err = os.Create(c.logFilename)
	}

	// Create a new logger with the log file as output.
	c.Log = log.New(c.LogFile, "", log.Ldate|log.Lmicroseconds)
	if err != nil {
		return
	}

	// Create the sample file.
	c.SampleFile, err = os.Create(c.sampleFilename)
	if err != nil {
		return
	}

	// Create encoder for specified logging format.
	switch strings.ToLower(c.format) {
	case "plain":
		break
	case "json":
		c.Encoder = json.NewEncoder(c.LogFile)
	case "xml":
		c.Encoder = xml.NewEncoder(c.LogFile)
	case "gob":
		c.Encoder = gob.NewEncoder(c.LogFile)

		// Don't let the user output gob to stdout unless they really want to.
		if !c.GobUnsafe && c.logFilename == "/dev/stdout" {
			fmt.Println("Gob encoded messages are not stdout safe, specify logfile or use gobunsafe flag.")
			os.Exit(1)
		}
	default:
		// We didn't get a valid encoder, exit and say so.
		log.Fatal("Invalid log format:", c.format)
	}

	return
}

func (c Config) Close() {
	c.LogFile.Close()
	c.SampleFile.Close()
}

// JSON, XML and GOB all implement this interface so we can simplify log
// output formatting.
type Encoder interface {
	Encode(interface{}) error
}

func NextPowerOf2(v uint) uint {
	return 1 << uint(math.Ceil(math.Log2(float64(v))))
}
<|endoftext|>


<commit_before>package lazycache

import (
	"fmt"
	flag "github.com/spf13/pflag"
	"github.com/spf13/viper"
	"strings"
)

func ViperConfiguration() {

	// Configuration
	viper.SetDefault("port", 8080)
	viper.SetDefault("bind", "0.0.0.0")
	viper.SetDefault("imagestore", "")
	viper.SetDefault("imagestore.bucket", "camhd-image-cache")

	viper.SetDefault("quicktimestore", "")
	viper.SetDefault("directorystore", "")

	viper.SetConfigName("lazycache")
	viper.AddConfigPath("/etc/lazycache")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		switch err.(type) {
		case viper.ConfigFileNotFoundError:
			// ignore
		default:
			panic(fmt.Errorf("Fatal error config file: %s \n", err))
		}
	}

	viper.SetEnvPrefix("lazycache")
	viper.AutomaticEnv()
	// Convert '.' to '_' in configuration variable names
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// var (
	// 	bindFlag          = flag.String("bind", "0.0.0.0", "Network interface to bind to (defaults to 0.0.0.0)")
	// 	ImageStoreFlag   = flag.String("image-store", "", "Type of image store (none, google)")
	// 	ImageBucketFlag = flag.String("image-store-bucket", "", "Bucket used for Google image store")
	// )
	flag.Int("port", 80, "Network port to listen on (default: 8080)")
	flag.String("bind", "0.0.0.0", "Network interface to bind to (defaults to 0.0.0.0)")

	flag.String("image-store", "", "Type of image store (none, local, google)")
	flag.String("image-store-bucket", "camhd-image-cache", "Bucket used for Google image store")
	flag.String("image-local-root", "", "Bucket used for Google image store")
	flag.String("image-url-root", "", "Bucket used for Google image store")

	flag.String("quicktime-store", "", "Type of quicktime store (none, redis)")
	flag.String("directory-store", "", "Type of directory store (none, redis)")
	flag.String("redis-host", "localhost:6379", "Host used for redis store")

	viper.BindPFlag("port", flag.Lookup("port"))
	viper.BindPFlag("bind", flag.Lookup("bind"))
	viper.BindPFlag("imagestore", flag.Lookup("image-store"))

	viper.BindPFlag("imagestore.bucket", flag.Lookup("image-store-bucket"))
	viper.BindPFlag("imagestore.localroot", flag.Lookup("image-local-root"))

	viper.BindPFlag("directorystore", flag.Lookup("directory-store"))
	viper.BindPFlag("quicktimestore", flag.Lookup("quicktime-store"))
	viper.BindPFlag("redishost", flag.Lookup("redis-host"))

	flag.Parse()
}

func ConfigureImageStoreFromViper() {
	storeKey := viper.GetString("imagestore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring image store with type \"%s\"", storeKey))
	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of image store from \"%s\"", storeKey))
		DefaultImageStore = NullImageStore{}
	case "", "none":
		DefaultLogger.Log("msg", "No image store configured.")
		DefaultImageStore = NullImageStore{}
	case "local":
		DefaultImageStore = CreateLocalStore(viper.GetString("imagestore.localRoot"),
			viper.GetString("imagestore.bind"))
	case "google":
		DefaultImageStore = CreateGoogleStore(viper.GetString("imagestore.bucket"))
	}
}

func ConfigureQuicktimeStoreFromViper() {
	storeKey := viper.GetString("quicktimestore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring quicktime store with type \"%s\"", storeKey))

	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of image store from \"%s\"", storeKey))
		QTMetadataStore = CreateMapJSONStore()
	case "", "none":
		DefaultLogger.Log("msg", "Using default QuicktimeStore.")
		QTMetadataStore = CreateMapJSONStore()
	case "redis":
		hostname := viper.GetString("redishost")
		DefaultLogger.Log("msg", fmt.Sprintf("Connecting to redis host \"%s\"", hostname))
		redis, err := CreateRedisJSONStore(hostname, "qt")
		if err != nil {
			DefaultLogger.Log("msg", fmt.Sprintf("Failed to configure Redis Quicktime store to host \"%s\"", hostname))
		}

		DefaultLogger.Log("msg", fmt.Sprintf("Logging movie metadata to Redis at %s", hostname))
		QTMetadataStore = redis
	}
}

func ConfigureDirectoryStoreFromViper() {
	storeKey := viper.GetString("directorystore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring directory store with type \"%s\"", storeKey))

	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of directory store from \"%s\"", storeKey))
		DirKeyStore = CreateMapJSONStore()
	case "", "none":
		DefaultLogger.Log("msg", "Using default directory store.")
		DirKeyStore = CreateMapJSONStore()
	case "redis":
		hostname := viper.GetString("redishost")
		DefaultLogger.Log("msg", fmt.Sprintf("Connecting to redis host \"%s\"", hostname))
		redis, err := CreateRedisJSONStore(hostname, "dir")
		if err != nil {
			DefaultLogger.Log("msg", fmt.Sprintf("Failed to configure Redis directory store to host \"%s\"", hostname))
		}

		DefaultLogger.Log("msg", fmt.Sprintf("Logging directory metadata to Redis at %s", hostname))
		DirKeyStore = redis
	}
}

func ConfigureFromViper() {
	ConfigureImageStoreFromViper()
	ConfigureDirectoryStoreFromViper()
	ConfigureQuicktimeStoreFromViper()
}
<commit_msg>Added more debugging in ConfigureFromViper.<commit_after>package lazycache

import (
	"fmt"
	flag "github.com/spf13/pflag"
	"github.com/spf13/viper"
	"strings"
)

func ViperConfiguration() {

	// Configuration
	viper.SetDefault("port", 8080)
	viper.SetDefault("bind", "0.0.0.0")
	viper.SetDefault("imagestore", "")
	viper.SetDefault("imagestore.bucket", "camhd-image-cache")

	viper.SetDefault("quicktimestore", "")
	viper.SetDefault("directorystore", "")

	viper.SetConfigName("lazycache")
	viper.AddConfigPath("/etc/lazycache")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		switch err.(type) {
		case viper.ConfigFileNotFoundError:
			// ignore
		default:
			panic(fmt.Errorf("Fatal error config file: %s \n", err))
		}
	}

	viper.SetEnvPrefix("lazycache")
	viper.AutomaticEnv()
	// Convert '.' to '_' in configuration variable names
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// var (
	// 	bindFlag          = flag.String("bind", "0.0.0.0", "Network interface to bind to (defaults to 0.0.0.0)")
	// 	ImageStoreFlag   = flag.String("image-store", "", "Type of image store (none, google)")
	// 	ImageBucketFlag = flag.String("image-store-bucket", "", "Bucket used for Google image store")
	// )
	flag.Int("port", 80, "Network port to listen on (default: 8080)")
	flag.String("bind", "0.0.0.0", "Network interface to bind to (defaults to 0.0.0.0)")

	flag.String("image-store", "", "Type of image store (none, local, google)")
	flag.String("image-store-bucket", "camhd-image-cache", "Bucket used for Google image store")
	flag.String("image-local-root", "", "Bucket used for Google image store")
	flag.String("image-url-root", "", "Bucket used for Google image store")

	flag.String("quicktime-store", "", "Type of quicktime store (none, redis)")
	flag.String("directory-store", "", "Type of directory store (none, redis)")
	flag.String("redis-host", "localhost:6379", "Host used for redis store")

	viper.BindPFlag("port", flag.Lookup("port"))
	viper.BindPFlag("bind", flag.Lookup("bind"))
	viper.BindPFlag("imagestore", flag.Lookup("image-store"))

	viper.BindPFlag("imagestore.bucket", flag.Lookup("image-store-bucket"))
	viper.BindPFlag("imagestore.localroot", flag.Lookup("image-local-root"))

	viper.BindPFlag("directorystore", flag.Lookup("directory-store"))
	viper.BindPFlag("quicktimestore", flag.Lookup("quicktime-store"))
	viper.BindPFlag("redishost", flag.Lookup("redis-host"))

	flag.Parse()
}

func ConfigureImageStoreFromViper() {
	storeKey := viper.GetString("imagestore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring image store with type \"%s\"", storeKey))
	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of image store from \"%s\"", storeKey))
		DefaultImageStore = NullImageStore{}
	case "", "none":
		DefaultLogger.Log("msg", "No image store configured.")
		DefaultImageStore = NullImageStore{}
	case "local":
		DefaultImageStore = CreateLocalStore(viper.GetString("imagestore.localRoot"),
			viper.GetString("imagestore.bind"))
	case "google":
		DefaultImageStore = CreateGoogleStore(viper.GetString("imagestore.bucket"))
	}
}

func ConfigureQuicktimeStoreFromViper() {
	storeKey := viper.GetString("quicktimestore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring quicktime store with type \"%s\"", storeKey))

	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of image store from \"%s\"", storeKey))
		QTMetadataStore = CreateMapJSONStore()
	case "", "none":
		DefaultLogger.Log("msg", "Using default QuicktimeStore.")
		QTMetadataStore = CreateMapJSONStore()
	case "redis":
		hostname := viper.GetString("redishost")
		DefaultLogger.Log("msg", fmt.Sprintf("Connecting to redis host \"%s\"", hostname))
		redis, err := CreateRedisJSONStore(hostname, "qt")
		if err != nil {
			DefaultLogger.Log("msg", fmt.Sprintf("Failed to configure Redis Quicktime store to host \"%s\"", hostname))
		}

		DefaultLogger.Log("msg", fmt.Sprintf("Logging movie metadata to Redis at %s", hostname))
		QTMetadataStore = redis
	}
}

func ConfigureDirectoryStoreFromViper() {
	storeKey := viper.GetString("directorystore")
	DefaultLogger.Log("msg", fmt.Sprintf("Configuring directory store with type \"%s\"", storeKey))

	switch strings.ToLower(storeKey) {
	default:
		DefaultLogger.Log("msg", fmt.Sprintf("Unable to determine type of directory store from \"%s\"", storeKey))
		DirKeyStore = CreateMapJSONStore()
	case "", "none":
		DefaultLogger.Log("msg", "Using default directory store.")
		DirKeyStore = CreateMapJSONStore()
	case "redis":
		hostname := viper.GetString("redishost")
		DefaultLogger.Log("msg", fmt.Sprintf("Connecting to redis host \"%s\"", hostname))
		redis, err := CreateRedisJSONStore(hostname, "dir")
		if err != nil {
			DefaultLogger.Log("msg", fmt.Sprintf("Failed to configure Redis directory store to host \"%s\"", hostname))
		}

		DefaultLogger.Log("msg", fmt.Sprintf("Logging directory metadata to Redis at %s", hostname))
		DirKeyStore = redis
	}
}

func ConfigureFromViper() {
	DefaultLogger.Log("msg", "In ConfigureFromViper")
	ConfigureImageStoreFromViper()
	ConfigureDirectoryStoreFromViper()
	ConfigureQuicktimeStoreFromViper()
}
<|endoftext|>