132 строки
3.1 KiB
Go
132 строки
3.1 KiB
Go
package xmlrpc
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"encoding/xml"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func newRequest(url string, method string, params...interface{}) (*http.Request, error) {
|
|
body := buildRequestBody(method, params)
|
|
request, err := http.NewRequest("POST", url, strings.NewReader(body))
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
request.Header.Set("Content-Type", "text/xml")
|
|
request.Header.Set("Content-Lenght", fmt.Sprintf("%d", len(body)))
|
|
|
|
return request, nil
|
|
}
|
|
|
|
func buildRequestBody(method string, params []interface{}) (buffer string) {
|
|
buffer += `<?xml version="1.0" encoding="UTF-8"?><methodCall>`
|
|
buffer += fmt.Sprintf("<methodName>%s</methodName><params>", method)
|
|
|
|
if params != nil && len(params) > 0 {
|
|
for _, value := range params {
|
|
if value != nil {
|
|
buffer += buildParamElement(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
buffer += "</params></methodCall>"
|
|
|
|
return
|
|
}
|
|
|
|
func buildParamElement(value interface{}) (string) {
|
|
return fmt.Sprintf("<param>%s</param>", buildValueElement(value))
|
|
}
|
|
|
|
func buildValueElement(value interface{}) (buffer string) {
|
|
buffer = `<value>`
|
|
|
|
switch v := value.(type) {
|
|
case Struct:
|
|
buffer += buildStructElement(v)
|
|
case string:
|
|
escaped := escapeString(value.(string))
|
|
buffer += fmt.Sprintf("<string>%s</string>", escaped)
|
|
case int, int8, int16, int32, int64:
|
|
buffer += fmt.Sprintf("<int>%d</int>", v)
|
|
case float32, float64:
|
|
buffer += fmt.Sprintf("<double>%f</double>", v)
|
|
case bool:
|
|
buffer += buildBooleanElement(v)
|
|
case time.Time:
|
|
buffer += buildTimeElement(v)
|
|
default:
|
|
rv := reflect.ValueOf(value)
|
|
|
|
if rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array {
|
|
buffer += buildArrayElement(v)
|
|
} else {
|
|
fmt.Errorf("Unsupported value type")
|
|
}
|
|
}
|
|
|
|
buffer += `</value>`
|
|
|
|
return
|
|
}
|
|
|
|
func buildStructElement(param Struct) (buffer string) {
|
|
buffer = `<struct>`
|
|
|
|
for name, value := range param {
|
|
buffer += fmt.Sprintf("<member><name>%s</name>", name)
|
|
buffer += buildValueElement(value)
|
|
buffer += `</member>`
|
|
}
|
|
|
|
buffer += `</struct>`
|
|
|
|
return
|
|
}
|
|
|
|
func buildBooleanElement(value bool) (buffer string) {
|
|
if value {
|
|
buffer = `<boolean>1</boolean>`
|
|
} else {
|
|
buffer = `<boolean>0</boolean>`
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func buildTimeElement(t time.Time) string {
|
|
return fmt.Sprintf(
|
|
"<dateTime.iso8601>%d%d%dT%d:%d:%d</dateTime.iso8601>",
|
|
t.Year(), t.Month(),t.Day(),
|
|
t.Hour(), t.Minute(), t.Second(),
|
|
)
|
|
}
|
|
|
|
func buildArrayElement(array interface{}) string {
|
|
buffer := `<array><data>`
|
|
|
|
for _, value := range array.([]interface{}) {
|
|
buffer += `<value>`
|
|
buffer += buildValueElement(value)
|
|
buffer += `</value>`
|
|
}
|
|
|
|
buffer += `</data></array>`
|
|
|
|
return buffer
|
|
}
|
|
|
|
func escapeString(s string) string {
|
|
buffer := bytes.NewBuffer([]byte{})
|
|
xml.Escape(buffer, []byte(s))
|
|
|
|
return fmt.Sprintf("%v", buffer)
|
|
}
|