Use data type (un)marshal in generated DCP code.
This commit is contained in:
parent
9db0302a13
commit
d2cd2978d9
@ -6,7 +6,14 @@ import (
|
|||||||
|
|
||||||
var packageTmpl = template.Must(template.New("package").Parse(`package {{.Name}}
|
var packageTmpl = template.Must(template.New("package").Parse(`package {{.Name}}
|
||||||
|
|
||||||
import "github.com/huin/goupnp/soap"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/huin/goupnp/soap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hack to avoid Go complaining if time isn't used.
|
||||||
|
var _ time.Time
|
||||||
|
|
||||||
const ({{range .DeviceTypes}}
|
const ({{range .DeviceTypes}}
|
||||||
{{.Const}} = "{{.URN}}"
|
{{.Const}} = "{{.URN}}"
|
||||||
@ -32,12 +39,12 @@ type {{$srvIdent}} struct {
|
|||||||
|
|
||||||
// {{$reqType}} is the XML structure for the input arguments for action {{.Name}}.
|
// {{$reqType}} is the XML structure for the input arguments for action {{.Name}}.
|
||||||
type {{$reqType}} struct {{"{"}}{{range .Arguments}}{{if .IsInput}}
|
type {{$reqType}} struct {{"{"}}{{range .Arguments}}{{if .IsInput}}
|
||||||
{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}}
|
{{.Name}} string
|
||||||
{{end}}{{end}}}
|
{{end}}{{end}}}
|
||||||
|
|
||||||
// {{$respType}} is the XML structure for the output arguments for action {{.Name}}.
|
// {{$respType}} is the XML structure for the output arguments for action {{.Name}}.
|
||||||
type {{$respType}} struct {{"{"}}{{range .Arguments}}{{if .IsOutput}}
|
type {{$respType}} struct {{"{"}}{{range .Arguments}}{{if .IsOutput}}
|
||||||
{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}}
|
{{.Name}} string
|
||||||
{{end}}{{end}}}
|
{{end}}{{end}}}
|
||||||
|
|
||||||
// {{.Name}} action.
|
// {{.Name}} action.
|
||||||
@ -63,26 +70,35 @@ type {{$respType}} struct {{"{"}}{{range .Arguments}}{{if .IsOutput}}
|
|||||||
// (unknown){{end}}
|
// (unknown){{end}}
|
||||||
//{{end}}{{end}}
|
//{{end}}{{end}}
|
||||||
func (client *{{$srvIdent}}) {{.Name}}({{range .Arguments}}{{if .IsInput}}
|
func (client *{{$srvIdent}}) {{.Name}}({{range .Arguments}}{{if .IsInput}}
|
||||||
{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}},
|
{{$argWrap := $srv.Argument .}}{{$argWrap.AsParameter}},{{end}}{{end}}
|
||||||
{{end}}{{end}}) ({{range .Arguments}}{{if .IsOutput}}
|
) ({{range .Arguments}}{{if .IsOutput}}
|
||||||
{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}},
|
{{$argWrap := $srv.Argument .}}{{$argWrap.AsParameter}},{{end}}{{end}}
|
||||||
{{end}}{{end}} err error) {
|
err error,
|
||||||
request := {{$reqType}}{
|
) {
|
||||||
{{range .Arguments}}{{if .IsInput}}
|
var request {{$reqType}}
|
||||||
{{.Name}}: {{.Name}},
|
// BEGIN Marshal arguments into request.
|
||||||
{{end}}{{end}}
|
{{range .Arguments}}{{if .IsInput}}{{$argWrap := $srv.Argument .}}
|
||||||
}
|
if request.{{.Name}}, err = {{$argWrap.Marshal}}; err != nil {
|
||||||
var response {{$respType}}
|
|
||||||
err = client.SOAPClient.PerformAction({{$srv.URNParts.Const}}, "{{.Name}}", &request, &response)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
{{range .Arguments}}{{if .IsOutput}}
|
|
||||||
{{.Name}} = response.{{.Name}}
|
|
||||||
{{end}}{{end}}
|
{{end}}{{end}}
|
||||||
|
// END Marshal arguments into request.
|
||||||
|
|
||||||
|
// Perform the SOAP call.
|
||||||
|
var response {{$respType}}
|
||||||
|
if err = client.SOAPClient.PerformAction({{$srv.URNParts.Const}}, "{{.Name}}", &request, &response); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BEGIN Unmarshal arguments from response.
|
||||||
|
{{range .Arguments}}{{if .IsOutput}}{{$argWrap := $srv.Argument .}}
|
||||||
|
if {{.Name}}, err = {{$argWrap.Unmarshal "response"}}; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
{{end}}{{end}}
|
||||||
|
// END Unmarshal arguments from response.
|
||||||
|
return
|
||||||
|
}
|
||||||
{{end}}{{/* range .SCPD.Actions */}}
|
{{end}}{{/* range .SCPD.Actions */}}
|
||||||
{{end}}{{/* range .Services */}}
|
{{end}}{{/* range .Services */}}
|
||||||
`))
|
`))
|
||||||
|
@ -199,6 +199,72 @@ type SCPDWithURN struct {
|
|||||||
SCPD *scpd.SCPD
|
SCPD *scpd.SCPD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SCPDWithURN) Argument(arg scpd.Argument) (*argumentWrapper, error) {
|
||||||
|
relVar := s.SCPD.GetStateVariable(arg.RelatedStateVariable)
|
||||||
|
if relVar == nil {
|
||||||
|
return nil, fmt.Errorf("no such state variable: %q, for argument %q", arg.RelatedStateVariable, arg.Name)
|
||||||
|
}
|
||||||
|
cnv, ok := typeConvs[relVar.DataType.Name]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown data type: %q, for state variable %q, for argument %q", relVar.DataType.Type, arg.RelatedStateVariable, arg.Name)
|
||||||
|
}
|
||||||
|
return &argumentWrapper{
|
||||||
|
Argument: arg,
|
||||||
|
relVar: relVar,
|
||||||
|
conv: cnv,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type argumentWrapper struct {
|
||||||
|
scpd.Argument
|
||||||
|
relVar *scpd.StateVariable
|
||||||
|
conv conv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg *argumentWrapper) AsParameter() string {
|
||||||
|
return fmt.Sprintf("%s %s", arg.Name, arg.conv.ExtType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg *argumentWrapper) Marshal() string {
|
||||||
|
return fmt.Sprintf("soap.Marshal%s(%s)", arg.conv.FuncSuffix, arg.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg *argumentWrapper) Unmarshal(objVar string) string {
|
||||||
|
return fmt.Sprintf("soap.Unmarshal%s(%s.%s)", arg.conv.FuncSuffix, objVar, arg.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
type conv struct {
|
||||||
|
FuncSuffix string
|
||||||
|
ExtType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeConvs maps from a SOAP type (e.g "fixed.14.4") to the function name
|
||||||
|
// suffix inside the soap module (e.g "Fixed14_4") and the Go type.
|
||||||
|
var typeConvs = map[string]conv{
|
||||||
|
"ui1": conv{"Ui1", "uint8"},
|
||||||
|
"ui2": conv{"Ui2", "uint16"},
|
||||||
|
"ui4": conv{"Ui4", "uint32"},
|
||||||
|
"i1": conv{"I1", "int8"},
|
||||||
|
"i2": conv{"I2", "int16"},
|
||||||
|
"i4": conv{"I4", "int32"},
|
||||||
|
"int": conv{"Int", "int64"},
|
||||||
|
"r4": conv{"R4", "float32"},
|
||||||
|
"r8": conv{"R8", "float64"},
|
||||||
|
"number": conv{"R8", "float64"}, // Alias for r8.
|
||||||
|
"fixed.14.4": conv{"Fixed14_4", "float64"},
|
||||||
|
"float": conv{"R8", "float64"},
|
||||||
|
"char": conv{"Char", "rune"},
|
||||||
|
"string": conv{"String", "string"},
|
||||||
|
"date": conv{"Date", "time.Time"},
|
||||||
|
"dateTime": conv{"DateTime", "time.Time"},
|
||||||
|
"dateTime.tz": conv{"DateTimeTz", "time.Time"},
|
||||||
|
"time": conv{"TimeOfDay", "soap.TimeOfDay"},
|
||||||
|
"time.tz": conv{"TimeOfDayTz", "soap.TimeOfDay"},
|
||||||
|
"boolean": conv{"Boolean", "bool"},
|
||||||
|
"bin.base64": conv{"BinBase64", "[]byte"},
|
||||||
|
"bin.hex": conv{"BinHex", "[]byte"},
|
||||||
|
}
|
||||||
|
|
||||||
type closeableZipReader struct {
|
type closeableZipReader struct {
|
||||||
io.Closer
|
io.Closer
|
||||||
*zip.Reader
|
*zip.Reader
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
40
scpd/scpd.go
40
scpd/scpd.go
@ -37,31 +37,6 @@ func (scpd *SCPD) Clean() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataTypeToGoKindName = map[string]string{
|
|
||||||
"ui1": "byte",
|
|
||||||
"ui2": "uint16",
|
|
||||||
"ui4": "uint32",
|
|
||||||
"i1": "int8",
|
|
||||||
"i2": "int16",
|
|
||||||
"i4": "int32",
|
|
||||||
"int": "int64",
|
|
||||||
"float": "float32",
|
|
||||||
"r4": "float32",
|
|
||||||
"r8": "float64",
|
|
||||||
// "fixed.14.4" ~ "float64"
|
|
||||||
"number": "float64",
|
|
||||||
"char": "string",
|
|
||||||
"string": "string",
|
|
||||||
// "date"
|
|
||||||
// "dateTime"
|
|
||||||
// "dateTime.tz"
|
|
||||||
// "boolean"
|
|
||||||
// "bin.base64"
|
|
||||||
// "bin.hex"
|
|
||||||
// "uri"
|
|
||||||
// "uuid"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (scpd *SCPD) GetStateVariable(variable string) *StateVariable {
|
func (scpd *SCPD) GetStateVariable(variable string) *StateVariable {
|
||||||
for i := range scpd.StateVariables {
|
for i := range scpd.StateVariables {
|
||||||
v := &scpd.StateVariables[i]
|
v := &scpd.StateVariables[i]
|
||||||
@ -72,21 +47,6 @@ func (scpd *SCPD) GetStateVariable(variable string) *StateVariable {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the name of the Go "kind" of type for the named state variable. If
|
|
||||||
// the state variable is unknown, returns default_.
|
|
||||||
func (scpd *SCPD) GoKindNameForVariable(variable string, default_ string) string {
|
|
||||||
v := scpd.GetStateVariable(variable)
|
|
||||||
if v == nil {
|
|
||||||
return default_
|
|
||||||
}
|
|
||||||
|
|
||||||
if kindName, ok := dataTypeToGoKindName[v.DataType.Name]; ok {
|
|
||||||
return kindName
|
|
||||||
} else {
|
|
||||||
return default_
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpecVersion is part of a SCPD document, describes the version of the
|
// SpecVersion is part of a SCPD document, describes the version of the
|
||||||
// specification that the data adheres to.
|
// specification that the data adheres to.
|
||||||
type SpecVersion struct {
|
type SpecVersion struct {
|
||||||
|
@ -139,6 +139,14 @@ func UnmarshalChar(s string) (rune, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MarshalString(v string) (string, error) {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalString(v string) (string, error) {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseInt(s string, err *error) int {
|
func parseInt(s string, err *error) int {
|
||||||
v, parseErr := strconv.ParseInt(s, 10, 64)
|
v, parseErr := strconv.ParseInt(s, 10, 64)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user