mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
NEW REGISTRAR: OpenSRS (#275)
* Initial commit for OpenSRS registrar support #272 * sort existing name servers before comparing. * vendor philhug/opensrs-go * Update docs for OpenSRS #272 * Cache OpenSRS client to prevent http connection leak * run go fmt
This commit is contained in:
committed by
Tom Limoncelli
parent
20f0c984e4
commit
dfd015e5cd
21
vendor/github.com/philhug/opensrs-go/LICENSE
generated
vendored
Normal file
21
vendor/github.com/philhug/opensrs-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Philipp Hug
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
44
vendor/github.com/philhug/opensrs-go/opensrs/authentication.go
generated
vendored
Normal file
44
vendor/github.com/philhug/opensrs-go/opensrs/authentication.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package opensrs
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const (
|
||||
httpHeaderUserName = "X-UserName"
|
||||
httpHeaderSignature = "X-Signature"
|
||||
)
|
||||
|
||||
// Provides credentials that can be used for authenticating with OpenSRS.
|
||||
//
|
||||
type Credentials interface {
|
||||
// Returns the HTTP headers that should be set
|
||||
// to authenticate the HTTP Request.
|
||||
Headers(xml []byte) map[string]string
|
||||
}
|
||||
|
||||
// API key MD5 authentication
|
||||
type apiKeyMD5Credentials struct {
|
||||
userName string
|
||||
apiKey string
|
||||
}
|
||||
|
||||
// NewApiKeyMD5Credentials construct Credentials using the OpenSRS MD5 Api Key method.
|
||||
func NewApiKeyMD5Credentials(userName string, apiKey string) Credentials {
|
||||
return &apiKeyMD5Credentials{userName: userName, apiKey: apiKey}
|
||||
}
|
||||
|
||||
func (c *apiKeyMD5Credentials) Headers(xml []byte) map[string]string {
|
||||
h := md5.New()
|
||||
h.Write(xml)
|
||||
h.Write([]byte(c.apiKey))
|
||||
m := hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
h = md5.New()
|
||||
h.Write([]byte(m))
|
||||
h.Write([]byte(c.apiKey))
|
||||
m = hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
return map[string]string{httpHeaderUserName: c.userName, httpHeaderSignature: m}
|
||||
}
|
56
vendor/github.com/philhug/opensrs-go/opensrs/domains.go
generated
vendored
Normal file
56
vendor/github.com/philhug/opensrs-go/opensrs/domains.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package opensrs
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// DomainsService handles communication with the domain related
|
||||
// methods of the OpenSRS API.
|
||||
//
|
||||
type DomainsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// GetDomain fetches a domain.
|
||||
//
|
||||
func (s *DomainsService) GetDomain(domainIdentifier string, domainType string, limit int) (*OpsResponse, error) {
|
||||
opsResponse := OpsResponse{}
|
||||
opsRequestAttributes := OpsRequestAttributes{Domain: domainIdentifier, Limit: strconv.Itoa(limit), Type: domainType}
|
||||
|
||||
resp, err := s.client.post("GET", "DOMAIN", opsRequestAttributes, &opsResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = resp
|
||||
return &opsResponse, nil
|
||||
}
|
||||
|
||||
// UpdateDomainNameservers changes domain servers on a domain.
|
||||
//
|
||||
func (s *DomainsService) UpdateDomainNameservers(domainIdentifier string, newDs []string) (*OpsResponse, error) {
|
||||
opsResponse := OpsResponse{}
|
||||
|
||||
opsRequestAttributes := OpsRequestAttributes{Domain: domainIdentifier, AssignNs: newDs, OpType: "assign"}
|
||||
|
||||
resp, err := s.client.post("ADVANCED_UPDATE_NAMESERVERS", "DOMAIN", opsRequestAttributes, &opsResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = resp
|
||||
return &opsResponse, nil
|
||||
}
|
||||
|
||||
// GetDNSZone fetches zone info for a domain.
|
||||
//
|
||||
func (s *DomainsService) GetDNSZone(domainIdentifier string) (*OpsResponse, error) {
|
||||
opsResponse := OpsResponse{}
|
||||
opsRequestAttributes := OpsRequestAttributes{Domain: domainIdentifier}
|
||||
|
||||
resp, err := s.client.post("GET_DNS_ZONE", "DOMAIN", opsRequestAttributes, &opsResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = resp
|
||||
return &opsResponse, nil
|
||||
}
|
||||
|
231
vendor/github.com/philhug/opensrs-go/opensrs/opensrs.go
generated
vendored
Normal file
231
vendor/github.com/philhug/opensrs-go/opensrs/opensrs.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Package opensrs provides a client for the OpenSRS API.
|
||||
// In order to use this package you will need a OpenSRS account.
|
||||
package opensrs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version identifies the current library version.
|
||||
// This is a pro-forma convention given that Go dependencies
|
||||
// tends to be fetched directly from the repo.
|
||||
// It is also used in the user-agent identify the client.
|
||||
Version = "0.0.1"
|
||||
|
||||
// defaultBaseURL to the OpenSRS production API.
|
||||
//defaultBaseURL = "https://rr-n1-tor.opensrs.net:55443"
|
||||
defaultBaseURL = "https://horizon.opensrs.net:55443"
|
||||
|
||||
// userAgent represents the default user agent used
|
||||
// when no other user agent is set.
|
||||
defaultUserAgent = "opensrs-go/" + Version
|
||||
)
|
||||
|
||||
// Client represents a client to the OpenSRS API.
|
||||
type Client struct {
|
||||
// HttpClient is the underlying HTTP client
|
||||
// used to communicate with the API.
|
||||
HttpClient *http.Client
|
||||
|
||||
// Credentials used for accessing the OpenSRS API
|
||||
Credentials Credentials
|
||||
|
||||
// BaseURL for API requests.
|
||||
// Defaults to the public OpenSRS API, but can be set to a different endpoint (e.g. the sandbox).
|
||||
BaseURL string
|
||||
|
||||
// UserAgent used when communicating with the OpenSRS API.
|
||||
UserAgent string
|
||||
|
||||
// Services used for talking to different parts of the OpenSRS API.
|
||||
Domains *DomainsService
|
||||
|
||||
// Set to true to output debugging logs during API calls
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// NewClient returns a new OpenSRS API client using the given credentials.
|
||||
func NewClient(credentials Credentials) *Client {
|
||||
proxyUrl, _ := url.Parse("http://127.0.0.1:8080")
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify : true},
|
||||
Proxy: http.ProxyURL(proxyUrl),
|
||||
}
|
||||
c := &Client{Credentials: credentials, HttpClient: &http.Client{Transport: tr}, BaseURL: defaultBaseURL}
|
||||
c.Domains = &DomainsService{client: c}
|
||||
return c
|
||||
}
|
||||
|
||||
// NewRequest creates an API request.
|
||||
// The path is expected to be a relative path and will be resolved
|
||||
// according to the BaseURL of the Client. Paths should always be specified without a preceding slash.
|
||||
func (c *Client) NewRequest(method, path string, payload interface{}) (*http.Request, error) {
|
||||
url := c.BaseURL + path
|
||||
|
||||
body := new(bytes.Buffer)
|
||||
if payload != nil {
|
||||
xml, err := ToXml(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body = bytes.NewBuffer(xml)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "text/xml")
|
||||
req.Header.Add("Accept", "text/xml")
|
||||
req.Header.Add("User-Agent", formatUserAgent(c.UserAgent))
|
||||
for key, value := range c.Credentials.Headers(body.Bytes()) {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// formatUserAgent builds the final user agent to use for HTTP requests.
|
||||
//
|
||||
// If no custom user agent is provided, the default user agent is used.
|
||||
//
|
||||
// opensrs-go/1.0
|
||||
//
|
||||
// If a custom user agent is provided, the final user agent is the combination of the custom user agent
|
||||
// prepended by the default user agent.
|
||||
//
|
||||
// opensrs-go/1.0 customAgentFlag
|
||||
//
|
||||
func formatUserAgent(customUserAgent string) string {
|
||||
if customUserAgent == "" {
|
||||
return defaultUserAgent
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s", defaultUserAgent, customUserAgent)
|
||||
}
|
||||
|
||||
func (c *Client) post(action string, object string, attributes OpsRequestAttributes, obj *OpsResponse) (*http.Response, error) {
|
||||
payload := OpsRequest{Action: action, Object: object, Protocol: "XCP", Attributes: attributes}
|
||||
req, err := c.NewRequest("POST", "", payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.Do(req, obj)
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response.
|
||||
//
|
||||
// The API response is JSON decoded and stored in the value pointed by obj,
|
||||
// or returned as an error if an API error has occurred.
|
||||
// If obj implements the io.Writer interface, the raw response body will be written to obj,
|
||||
// without attempting to decode it.
|
||||
func (c *Client) Do(req *http.Request, obj *OpsResponse) (*http.Response, error) {
|
||||
if c.Debug {
|
||||
log.Printf("Executing request (%v): %#v", req.URL, req)
|
||||
}
|
||||
|
||||
resp, err := c.HttpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if c.Debug {
|
||||
log.Printf("Response received: %#v", resp)
|
||||
}
|
||||
|
||||
err = CheckResponse(resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// If obj implements the io.Writer,
|
||||
// the response body is decoded into v.
|
||||
if obj != nil {
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = FromXml(b, obj)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
err = CheckOpsResponse(resp, obj)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// An ErrorResponse represents an API response that generated an error.
|
||||
type ErrorResponse struct {
|
||||
HttpResponse *http.Response
|
||||
OpsResponse *OpsResponse
|
||||
|
||||
// human-readable message
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (r *ErrorResponse) Error() string {
|
||||
s := fmt.Sprintf("%v %v: ",
|
||||
r.HttpResponse.Request.Method, r.HttpResponse.Request.URL)
|
||||
if r.OpsResponse != nil {
|
||||
s = s + fmt.Sprintf("%v %v",
|
||||
r.OpsResponse.ResponseCode,
|
||||
r.OpsResponse.ResponseText)
|
||||
} else {
|
||||
s = s + fmt.Sprintf("%v %v",
|
||||
r.HttpResponse.StatusCode, r.Message)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if present.
|
||||
// A response is considered an error if the status code is different than 2xx. Specific requests
|
||||
// may have additional requirements, but this is sufficient in most of the cases.
|
||||
func CheckResponse(resp *http.Response) error {
|
||||
if code := resp.StatusCode; 200 <= code && code <= 299 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errorResponse := &ErrorResponse{}
|
||||
errorResponse.HttpResponse = resp
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = FromXml(b, errorResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errorResponse
|
||||
}
|
||||
|
||||
func CheckOpsResponse(resp *http.Response, or *OpsResponse) error {
|
||||
if or.IsSuccess == "1" {
|
||||
return nil
|
||||
}
|
||||
|
||||
errorResponse := &ErrorResponse{}
|
||||
errorResponse.HttpResponse = resp
|
||||
errorResponse.OpsResponse = or
|
||||
|
||||
return errorResponse
|
||||
}
|
92
vendor/github.com/philhug/opensrs-go/opensrs/structs.go
generated
vendored
Normal file
92
vendor/github.com/philhug/opensrs-go/opensrs/structs.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
package opensrs
|
||||
|
||||
type NameserverList []struct {
|
||||
Name string `json:"name"`
|
||||
IpAddress string `json:"ipaddress,omitempty"`
|
||||
Ipv6 string `json:"ipv6,omitempty"`
|
||||
SortOrder string `json:"sortorder,omitempty"`
|
||||
}
|
||||
|
||||
type ARecord struct {
|
||||
IpAddress string `json:"ipaddress,omitempty"`
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
}
|
||||
|
||||
type AAAARecord struct {
|
||||
Ipv6Address string `json:"ipv6_address,omitempty"`
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
}
|
||||
|
||||
type CNAMERecord struct {
|
||||
HostName string `json:"hostname,omitempty"`
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
}
|
||||
|
||||
type MXRecord struct {
|
||||
Priority string `json:"priority,omitempty"`
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
HostName string `json:"hostname,omitempty"`
|
||||
}
|
||||
|
||||
type SRVRecord struct {
|
||||
Priority string `json:"priority,omitempty"`
|
||||
Weight string `json:"weight,omitempty"`
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
HostName string `json:"hostname,omitempty"`
|
||||
Port string `json:"port,omitempty"`
|
||||
}
|
||||
|
||||
type TXTRecord struct {
|
||||
SubDomain string `json:"subdomain,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
type DnsRecords struct {
|
||||
A []ARecord `json:"A,omitempty"`
|
||||
AAAA []AAAARecord `json:"AAAA,omitempty"`
|
||||
CNAME []CNAMERecord `json:"CNAME,omitempty"`
|
||||
MX []MXRecord `json:"MX,omitempty"`
|
||||
SRV []SRVRecord `json:"SRV,omitempty"`
|
||||
TXT []TXTRecord `json:"TXT,omitempty"`
|
||||
}
|
||||
|
||||
func (n NameserverList) ToString() []string {
|
||||
domains := make([]string, len(n))
|
||||
for i, ns := range n {
|
||||
domains[i] = ns.Name
|
||||
}
|
||||
return domains
|
||||
}
|
||||
|
||||
type OpsRequestAttributes struct {
|
||||
Domain string `json:"domain"`
|
||||
Limit string `json:"limit,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
AffectDomains string `json:"affect_domains,omitempty"`
|
||||
NameserverList NameserverList `json:"nameserver_list,omitempty"`
|
||||
OpType string `json:"op_type,omitempty"`
|
||||
AssignNs []string `json:"assign_ns,omitempty"`
|
||||
}
|
||||
|
||||
type OpsResponse struct {
|
||||
Action string `json:"action"`
|
||||
Object string `json:"object"`
|
||||
Protocol string `json:"protocol"`
|
||||
IsSuccess string `json:"is_success"`
|
||||
ResponseCode string `json:"response_code"`
|
||||
ResponseText string `json:"response_text"`
|
||||
Attributes struct {
|
||||
NameserverList NameserverList `json:"nameserver_list,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
LockState string `json:"lock_state,omitempty"`
|
||||
Records DnsRecords `json:"records,omitempty"`
|
||||
} `json:"attributes"`
|
||||
}
|
||||
|
||||
type OpsRequest struct {
|
||||
Action string `json:"action"`
|
||||
Object string `json:"object"`
|
||||
Protocol string `json:"protocol"`
|
||||
Attributes OpsRequestAttributes `json:"attributes"`
|
||||
}
|
176
vendor/github.com/philhug/opensrs-go/opensrs/xml.go
generated
vendored
Normal file
176
vendor/github.com/philhug/opensrs-go/opensrs/xml.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
package opensrs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"log"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Header struct {
|
||||
XMLName xml.Name `xml:"header"`
|
||||
Version string `xml:"version"`
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
XMLName xml.Name `xml:"item"`
|
||||
Key string `xml:"key,attr"`
|
||||
DtArray *DtArray `xml:"dt_array,omitempty"`
|
||||
DtAssoc *DtAssoc `xml:"dt_assoc,omitempty"`
|
||||
Value string `xml:",chardata"`
|
||||
}
|
||||
|
||||
func (i *Item) decode() interface{} {
|
||||
if i.DtAssoc != nil {
|
||||
return i.DtAssoc.decode()
|
||||
}
|
||||
if i.DtArray != nil {
|
||||
return i.DtArray.decode()
|
||||
}
|
||||
return i.Value
|
||||
}
|
||||
|
||||
type DtArray struct {
|
||||
XMLName xml.Name `xml:"dt_array"`
|
||||
ItemList []Item `xml:"item,omitempty"`
|
||||
}
|
||||
|
||||
func (d *DtArray) decode() []interface{} {
|
||||
m := make([]interface{}, 0)
|
||||
for _, element := range d.ItemList {
|
||||
m = append(m, element.decode())
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type DtAssoc struct {
|
||||
XMLName xml.Name `xml:"dt_assoc"`
|
||||
ItemList []Item `xml:"item,omitempty"`
|
||||
}
|
||||
|
||||
func (d *DtAssoc) decode() Map {
|
||||
m := make(Map)
|
||||
for _, element := range d.ItemList {
|
||||
m[element.Key] = element.decode()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type DataBlock struct {
|
||||
XMLName xml.Name `xml:"data_block"`
|
||||
DtAssoc *DtAssoc `xml:"dt_assoc,omitempty"`
|
||||
//DtArray DtArray `xml:"dt_array,omitempty"`
|
||||
}
|
||||
|
||||
type Map map[string]interface{}
|
||||
|
||||
func (d *DataBlock) decode() Map {
|
||||
m := make(Map)
|
||||
if d.DtAssoc != nil {
|
||||
return d.DtAssoc.decode()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func encodeItem(key string, value reflect.Value) Item {
|
||||
item := Item{}
|
||||
item.Key = key
|
||||
v := internalEncode(value)
|
||||
s, ok := v.(string)
|
||||
if ok {
|
||||
item.Value = s
|
||||
}
|
||||
dtass, ok := v.(DtAssoc)
|
||||
if ok {
|
||||
item.DtAssoc = &dtass
|
||||
}
|
||||
dtarr, ok := v.(DtArray)
|
||||
if ok {
|
||||
item.DtArray = &dtarr
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func internalEncode(v reflect.Value) (p interface{}) {
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case reflect.Interface:
|
||||
return internalEncode(v.Elem())
|
||||
case reflect.String:
|
||||
return v.Interface().(string)
|
||||
case reflect.Struct:
|
||||
dt := DtAssoc{}
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
key := strings.ToLower(t.Field(i).Name)
|
||||
value := v.Field(i)
|
||||
item := encodeItem(key, value)
|
||||
dt.ItemList = append(dt.ItemList, item)
|
||||
}
|
||||
return dt
|
||||
case reflect.Map: // DtAssoc
|
||||
dt := DtAssoc{}
|
||||
|
||||
for _, k := range v.MapKeys() {
|
||||
v := v.MapIndex(k)
|
||||
key := k.String()
|
||||
item := encodeItem(key, v)
|
||||
dt.ItemList = append(dt.ItemList, item)
|
||||
}
|
||||
return dt
|
||||
case reflect.Slice: //DtArray
|
||||
dt := DtArray{}
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
key := strconv.Itoa(i)
|
||||
value := v.Index(i)
|
||||
item := encodeItem(key, value)
|
||||
dt.ItemList = append(dt.ItemList, item)
|
||||
}
|
||||
return dt
|
||||
default:
|
||||
log.Println("FAIL, unknown type", t.Kind())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"body"`
|
||||
DataBlock DataBlock `xml:"data_block"`
|
||||
}
|
||||
|
||||
type OPSEnvelope struct {
|
||||
XMLName xml.Name `xml:"OPS_envelope"`
|
||||
Header Header `xml:"header"`
|
||||
Body Body `xml:"body"`
|
||||
}
|
||||
|
||||
func FromXml(b []byte, v interface{}) error {
|
||||
var q OPSEnvelope
|
||||
err := xml.Unmarshal(b, &q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := q.Body.DataBlock.decode()
|
||||
jsonString, _ := json.Marshal(m)
|
||||
log.Println(string(jsonString))
|
||||
return json.Unmarshal(jsonString, &v)
|
||||
|
||||
}
|
||||
|
||||
func ToXml(v interface{}) (b []byte, err error) {
|
||||
jsonString, _ := json.Marshal(v)
|
||||
var m interface{}
|
||||
json.Unmarshal(jsonString, &m)
|
||||
|
||||
q := OPSEnvelope{Header: Header{Version: "0.9"}, Body: Body{}}
|
||||
dtass, ok := internalEncode(reflect.ValueOf(m)).(DtAssoc)
|
||||
if ok {
|
||||
q.Body.DataBlock.DtAssoc = &dtass
|
||||
} else {
|
||||
return nil, errors.New("Encoding failed")
|
||||
}
|
||||
return xml.MarshalIndent(q, "", " ")
|
||||
}
|
Reference in New Issue
Block a user