lib/upnp: Refactor out methods to util with tests, refactor IGD

This commit is contained in:
Audrius Butkevicius
2016-03-25 20:22:29 +00:00
committed by Jakob Borg
parent 6a3f3f5577
commit 1d17891286
9 changed files with 497 additions and 300 deletions

View File

@@ -11,15 +11,12 @@ import (
"encoding/json"
"encoding/xml"
"io"
"math/rand"
"net/url"
"os"
"reflect"
"sort"
"strconv"
"strings"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/util"
)
const (
@@ -58,9 +55,9 @@ func New(myID protocol.DeviceID) Configuration {
cfg.Version = CurrentVersion
cfg.OriginalVersion = CurrentVersion
setDefaults(&cfg)
setDefaults(&cfg.Options)
setDefaults(&cfg.GUI)
util.SetDefaults(&cfg)
util.SetDefaults(&cfg.Options)
util.SetDefaults(&cfg.GUI)
cfg.prepare(myID)
@@ -70,9 +67,9 @@ func New(myID protocol.DeviceID) Configuration {
func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
var cfg Configuration
setDefaults(&cfg)
setDefaults(&cfg.Options)
setDefaults(&cfg.GUI)
util.SetDefaults(&cfg)
util.SetDefaults(&cfg.Options)
util.SetDefaults(&cfg.GUI)
err := xml.NewDecoder(r).Decode(&cfg)
cfg.OriginalVersion = cfg.Version
@@ -84,9 +81,9 @@ func ReadXML(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
func ReadJSON(r io.Reader, myID protocol.DeviceID) (Configuration, error) {
var cfg Configuration
setDefaults(&cfg)
setDefaults(&cfg.Options)
setDefaults(&cfg.GUI)
util.SetDefaults(&cfg)
util.SetDefaults(&cfg.Options)
util.SetDefaults(&cfg.GUI)
err := json.NewDecoder(r).Decode(&cfg)
cfg.OriginalVersion = cfg.Version
@@ -143,7 +140,7 @@ func (cfg *Configuration) WriteXML(w io.Writer) error {
}
func (cfg *Configuration) prepare(myID protocol.DeviceID) {
fillNilSlices(&cfg.Options)
util.FillNilSlices(&cfg.Options)
// Initialize any empty slices
if cfg.Folders == nil {
@@ -171,8 +168,8 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
}
}
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
cfg.Options.GlobalAnnServers = uniqueStrings(cfg.Options.GlobalAnnServers)
cfg.Options.ListenAddress = util.UniqueStrings(cfg.Options.ListenAddress)
cfg.Options.GlobalAnnServers = util.UniqueStrings(cfg.Options.GlobalAnnServers)
if cfg.Version > 0 && cfg.Version < OldestHandledVersion {
l.Warnf("Configuration version %d is deprecated. Attempting best effort conversion, but please verify manually.", cfg.Version)
@@ -234,7 +231,7 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
}
if cfg.GUI.APIKey == "" {
cfg.GUI.APIKey = randomString(32)
cfg.GUI.APIKey = util.RandomString(32)
}
}
@@ -242,14 +239,14 @@ func convertV11V12(cfg *Configuration) {
// Change listen address schema
for i, addr := range cfg.Options.ListenAddress {
if len(addr) > 0 && !strings.HasPrefix(addr, "tcp://") {
cfg.Options.ListenAddress[i] = tcpAddr(addr)
cfg.Options.ListenAddress[i] = util.Address("tcp", addr)
}
}
for i, device := range cfg.Devices {
for j, addr := range device.Addresses {
if addr != "dynamic" && addr != "" {
cfg.Devices[i].Addresses[j] = tcpAddr(addr)
cfg.Devices[i].Addresses[j] = util.Address("tcp", addr)
}
}
}
@@ -297,98 +294,6 @@ func convertV10V11(cfg *Configuration) {
cfg.Version = 11
}
func setDefaults(data interface{}) error {
s := reflect.ValueOf(data).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
tag := t.Field(i).Tag
v := tag.Get("default")
if len(v) > 0 {
switch f.Interface().(type) {
case string:
f.SetString(v)
case int:
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return err
}
f.SetInt(i)
case float64:
i, err := strconv.ParseFloat(v, 64)
if err != nil {
return err
}
f.SetFloat(i)
case bool:
f.SetBool(v == "true")
case []string:
// We don't do anything with string slices here. Any default
// we set will be appended to by the XML decoder, so we fill
// those after decoding.
default:
panic(f.Type())
}
}
}
return nil
}
// fillNilSlices sets default value on slices that are still nil.
func fillNilSlices(data interface{}) error {
s := reflect.ValueOf(data).Elem()
t := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
tag := t.Field(i).Tag
v := tag.Get("default")
if len(v) > 0 {
switch f.Interface().(type) {
case []string:
if f.IsNil() {
// Treat the default as a comma separated slice
vs := strings.Split(v, ",")
for i := range vs {
vs[i] = strings.TrimSpace(vs[i])
}
rv := reflect.MakeSlice(reflect.TypeOf([]string{}), len(vs), len(vs))
for i, v := range vs {
rv.Index(i).SetString(v)
}
f.Set(rv)
}
}
}
}
return nil
}
func uniqueStrings(ss []string) []string {
var m = make(map[string]bool, len(ss))
for _, s := range ss {
m[strings.Trim(s, " ")] = true
}
var us = make([]string, 0, len(m))
for k := range m {
us = append(us, k)
}
sort.Strings(us)
return us
}
func ensureDevicePresent(devices []FolderDeviceConfiguration, myID protocol.DeviceID) []FolderDeviceConfiguration {
for _, device := range devices {
if device.DeviceID.Equals(myID) {
@@ -453,24 +358,3 @@ loop:
}
return devices[0:count]
}
// randomCharset contains the characters that can make up a randomString().
const randomCharset = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
// randomString returns a string of random characters (taken from
// randomCharset) of the specified length.
func randomString(l int) string {
bs := make([]byte, l)
for i := range bs {
bs[i] = randomCharset[rand.Intn(len(randomCharset))]
}
return string(bs)
}
func tcpAddr(host string) string {
u := url.URL{
Scheme: "tcp",
Host: host,
}
return u.String()
}