diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..325ab99 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,9 @@ +kind: pipeline +name: build_release + +steps: + - name: test and build + image: golang + commands: + - go test + - go build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d3ed4c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.yml diff --git a/go.mod b/go.mod index 2875366..748c316 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,8 @@ go 1.12 require ( git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 + github.com/json-iterator/go v1.1.6 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index e342763..555f5f1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,12 @@ git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 h1:V6ifeiJ3ExnjaUylTOz37n6z5uLwm6fjKjnztbTCaQI= git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index bb414a6..85c20d0 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "log" "git.trj.tw/golang/go-ddns-client/module/config" + "git.trj.tw/golang/go-ddns-client/module/ddns" "git.trj.tw/golang/go-ddns-client/module/option" ) @@ -19,4 +20,20 @@ func main() { if err != nil { log.Fatal(err) } + + data, err := ddns.GetDNSSetting() + if err != nil { + log.Fatal(err) + } + + if len(data.V4) > 0 { + if err = ddns.SendRequest(true, data.V4); err != nil { + log.Fatal(err) + } + } + if len(data.V6) > 0 { + if err = ddns.SendRequest(false, data.V6); err != nil { + log.Fatal(err) + } + } } diff --git a/module/config/config.go b/module/config/config.go index a6d8887..6ac6489 100644 --- a/module/config/config.go +++ b/module/config/config.go @@ -71,4 +71,31 @@ func LoadConfig(p ...string) error { func GetConfig() *Config { return conf } // GetV4Data - -func (p DomainData) GetV4Data() {} +func (p DomainData) GetV4Data() DomainData { + domain := DomainData{} + domain.Name = p.Name + if len(p.Records) == 0 { + return domain + } + for _, it := range p.Records { + if it.Type == "A" { + domain.Records = append(domain.Records, it) + } + } + return domain +} + +// GetV6Data - +func (p DomainData) GetV6Data() DomainData { + domain := DomainData{} + domain.Name = p.Name + if len(p.Records) == 0 { + return domain + } + for _, it := range p.Records { + if it.Type == "AAAA" { + domain.Records = append(domain.Records, it) + } + } + return domain +} diff --git a/module/config/config_test.go b/module/config/config_test.go new file mode 100644 index 0000000..d85cc6d --- /dev/null +++ b/module/config/config_test.go @@ -0,0 +1,78 @@ +package config + +import ( + "os" + "path" + "reflect" + "testing" +) + +func TestLoadConfig(t *testing.T) { + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + p := path.Join(wd, "../..", "config.default.yml") + + err = LoadConfig(p) + if err != nil { + t.Fatal(err) + } +} + +func TestGetConfig(t *testing.T) { + conf := GetConfig() + if conf == nil { + t.Fail() + } +} + +func TestDomainData_GetV6Data(t *testing.T) { + type fields struct { + Name string + Records []RecordData + } + tests := []struct { + name string + fields fields + want DomainData + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := DomainData{ + Name: tt.fields.Name, + Records: tt.fields.Records, + } + if got := p.GetV6Data(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("DomainData.GetV6Data() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDomainData_GetV4Data(t *testing.T) { + type fields struct { + Name string + Records []RecordData + } + tests := []struct { + name string + fields fields + want DomainData + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := DomainData{ + Name: tt.fields.Name, + Records: tt.fields.Records, + } + if got := p.GetV4Data(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("DomainData.GetV4Data() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/module/ddns/ddns.go b/module/ddns/ddns.go index a958bb9..6055560 100644 --- a/module/ddns/ddns.go +++ b/module/ddns/ddns.go @@ -2,24 +2,117 @@ package ddns import ( "errors" + "io/ioutil" + "log" + "net/http" + "net/textproto" + "net/url" + + "bytes" "git.trj.tw/golang/go-ddns-client/module/config" + jsoniter "github.com/json-iterator/go" ) +var json = jsoniter.ConfigCompatibleWithStandardLibrary + // Errors var ( ErrNoDomain = errors.New("No Domain Setting") + ErrAPIResp = errors.New("api call not success") ) -// SendDNSSetting - -func SendDNSSetting() error { +// DNSSetting - +type DNSSetting struct { + V4 []config.DomainData + V6 []config.DomainData +} + +// GetDNSSetting - +func GetDNSSetting() (DNSSetting, error) { + setting := DNSSetting{} conf := config.GetConfig() if len(conf.Domains) == 0 { - return ErrNoDomain + return setting, ErrNoDomain } + + v4Data := make([]config.DomainData, 0) + v6Data := make([]config.DomainData, 0) + + for _, it := range conf.Domains { + v4 := it.GetV4Data() + if len(v4.Records) > 0 { + v4Data = append(v4Data, v4) + } + + v6 := it.GetV6Data() + if len(v6.Records) > 0 { + v6Data = append(v6Data, v6) + } + } + + setting.V4 = v4Data + setting.V6 = v6Data + + return setting, nil +} + +// SendRequest - +func SendRequest(v4 bool, data []config.DomainData) error { + conf := config.GetConfig() + var baseURL string + if v4 { + baseURL = conf.URL.V4 + } else { + baseURL = conf.URL.V6 + } + token := conf.VerifyValue + if len(baseURL) == 0 || len(token) == 0 { + return errors.New("server setting error") + } + + body := struct { + Domains []config.DomainData `json:"domains"` + }{} + body.Domains = data + byteData, err := json.Marshal(body) + if err != nil { + return err + } + log.Println("send data :: ", string(byteData)) + + apiURL, err := url.Parse(baseURL) + if err != nil { + return err + } + apiURL, err = apiURL.Parse("/api/ddns") + if err != nil { + return err + } + + reader := bytes.NewReader(byteData) + req, err := http.NewRequest("POST", apiURL.String(), reader) + if err != nil { + return err + } + + req.Header.Set(textproto.CanonicalMIMEHeaderKey("X-Mtfos-Key"), token) + req.Header.Set(textproto.CanonicalMIMEHeaderKey("Content-Type"), "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyByte, err := ioutil.ReadAll(resp.Body) + if err == nil { + log.Println("body ::: ", string(bodyByte)) + } + + if resp.StatusCode != 200 { + return ErrAPIResp + } + return nil } - -func parseConf(domains []config.DomainData) { - -} diff --git a/module/ddns/ddns_test.go b/module/ddns/ddns_test.go new file mode 100644 index 0000000..514a3c8 --- /dev/null +++ b/module/ddns/ddns_test.go @@ -0,0 +1,28 @@ +package ddns + +import ( + "reflect" + "testing" +) + +func TestGetDNSSetting(t *testing.T) { + tests := []struct { + name string + want DNSSetting + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetDNSSetting() + if (err != nil) != tt.wantErr { + t.Errorf("GetDNSSetting() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetDNSSetting() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/module/option/option.go b/module/option/option.go index e35b4dc..3a0699e 100644 --- a/module/option/option.go +++ b/module/option/option.go @@ -17,7 +17,6 @@ func RegOptions() { flag.StringVar(&opts.Config, "config", "", "config file path - default: `pwd/config.yml`") flag.StringVar(&opts.Config, "f", "", "config file path - default: `pwd/config.yml`") flag.BoolVar(&opts.Help, "help", false, "show help") - flag.BoolVar(&opts.Once, "once", false, "run once") flag.Parse() } diff --git a/module/option/option_test.go b/module/option/option_test.go new file mode 100644 index 0000000..b6c34f3 --- /dev/null +++ b/module/option/option_test.go @@ -0,0 +1,35 @@ +package option + +import ( + "reflect" + "testing" +) + +func TestRegOptions(t *testing.T) { + tests := []struct { + name string + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + RegOptions() + }) + } +} + +func TestGetOptions(t *testing.T) { + tests := []struct { + name string + want *Options + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetOptions(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetOptions() = %v, want %v", got, tt.want) + } + }) + } +}