forked from shadowsocks/shadowsocks-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
136 lines (122 loc) · 3.32 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* Created with IntelliJ IDEA.
* User: clowwindy
* Date: 12-11-2
* Time: 上午10:31
* To change this template use File | Settings | File Templates.
*/
package shadowsocks
import (
"encoding/json"
"fmt"
"io/ioutil"
// "log"
"os"
"reflect"
"strings"
"time"
)
type Config struct {
Server interface{} `json:"server"`
ServerPort int `json:"server_port"`
LocalPort int `json:"local_port"`
Password string `json:"password"`
Method string `json:"method"` // encryption method
Auth bool `json:"auth"` // one time auth
// following options are only used by server
PortPassword map[string]string `json:"port_password"`
Timeout int `json:"timeout"`
// following options are only used by client
// The order of servers in the client config is significant, so use array
// instead of map to preserve the order.
ServerPassword [][]string `json:"server_password"`
}
var readTimeout time.Duration
func (config *Config) GetServerArray() []string {
// Specifying multiple servers in the "server" options is deprecated.
// But for backward compatiblity, keep this.
if config.Server == nil {
return nil
}
single, ok := config.Server.(string)
if ok {
return []string{single}
}
arr, ok := config.Server.([]interface{})
if ok {
/*
if len(arr) > 1 {
log.Println("Multiple servers in \"server\" option is deprecated. " +
"Please use \"server_password\" instead.")
}
*/
serverArr := make([]string, len(arr), len(arr))
for i, s := range arr {
serverArr[i], ok = s.(string)
if !ok {
goto typeError
}
}
return serverArr
}
typeError:
panic(fmt.Sprintf("Config.Server type error %v", reflect.TypeOf(config.Server)))
}
func ParseConfig(path string) (config *Config, err error) {
file, err := os.Open(path) // For read access.
if err != nil {
return
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return
}
config = &Config{}
if err = json.Unmarshal(data, config); err != nil {
return nil, err
}
readTimeout = time.Duration(config.Timeout) * time.Second
if strings.HasSuffix(strings.ToLower(config.Method), "-auth") {
config.Method = config.Method[:len(config.Method)-5]
config.Auth = true
}
return
}
func SetDebug(d DebugLog) {
Debug = d
}
// Useful for command line to override options specified in config file
// Debug is not updated.
func UpdateConfig(old, new *Config) {
// Using reflection here is not necessary, but it's a good exercise.
// For more information on reflections in Go, read "The Laws of Reflection"
// http://golang.org/doc/articles/laws_of_reflection.html
newVal := reflect.ValueOf(new).Elem()
oldVal := reflect.ValueOf(old).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.Interface:
if fmt.Sprintf("%v", newField.Interface()) != "" {
oldField.Set(newField)
}
case reflect.String:
s := newField.String()
if s != "" {
oldField.SetString(s)
}
case reflect.Int:
i := newField.Int()
if i != 0 {
oldField.SetInt(i)
}
}
}
old.Timeout = new.Timeout
readTimeout = time.Duration(old.Timeout) * time.Second
}