Use data type (un)marshal in generated DCP code.
This commit is contained in:
		@@ -6,7 +6,14 @@ import (
 | 
			
		||||
 | 
			
		||||
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}} = "{{.URN}}"
 | 
			
		||||
@@ -32,12 +39,12 @@ type {{$srvIdent}} struct {
 | 
			
		||||
 | 
			
		||||
// {{$reqType}} is the XML structure for the input arguments for action {{.Name}}.
 | 
			
		||||
type {{$reqType}} struct {{"{"}}{{range .Arguments}}{{if .IsInput}}
 | 
			
		||||
	{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}}
 | 
			
		||||
	{{.Name}} string
 | 
			
		||||
{{end}}{{end}}}
 | 
			
		||||
 | 
			
		||||
// {{$respType}} is the XML structure for the output arguments for action {{.Name}}.
 | 
			
		||||
type {{$respType}} struct {{"{"}}{{range .Arguments}}{{if .IsOutput}}
 | 
			
		||||
	{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}}
 | 
			
		||||
	{{.Name}} string
 | 
			
		||||
{{end}}{{end}}}
 | 
			
		||||
 | 
			
		||||
// {{.Name}} action.
 | 
			
		||||
@@ -63,26 +70,35 @@ type {{$respType}} struct {{"{"}}{{range .Arguments}}{{if .IsOutput}}
 | 
			
		||||
// (unknown){{end}}
 | 
			
		||||
//{{end}}{{end}}
 | 
			
		||||
func (client *{{$srvIdent}}) {{.Name}}({{range .Arguments}}{{if .IsInput}}
 | 
			
		||||
	{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}},
 | 
			
		||||
{{end}}{{end}}) ({{range .Arguments}}{{if .IsOutput}}
 | 
			
		||||
	{{.Name}} {{$srv.SCPD.GoKindNameForVariable .RelatedStateVariable "string"}},
 | 
			
		||||
{{end}}{{end}} err error) {
 | 
			
		||||
	request := {{$reqType}}{
 | 
			
		||||
{{range .Arguments}}{{if .IsInput}}
 | 
			
		||||
	{{.Name}}: {{.Name}},
 | 
			
		||||
{{end}}{{end}}
 | 
			
		||||
	}
 | 
			
		||||
	var response {{$respType}}
 | 
			
		||||
	err = client.SOAPClient.PerformAction({{$srv.URNParts.Const}}, "{{.Name}}", &request, &response)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	{{$argWrap := $srv.Argument .}}{{$argWrap.AsParameter}},{{end}}{{end}}
 | 
			
		||||
) ({{range .Arguments}}{{if .IsOutput}}
 | 
			
		||||
	{{$argWrap := $srv.Argument .}}{{$argWrap.AsParameter}},{{end}}{{end}}
 | 
			
		||||
	err error,
 | 
			
		||||
) {
 | 
			
		||||
	var request {{$reqType}}
 | 
			
		||||
	// BEGIN Marshal arguments into request.
 | 
			
		||||
{{range .Arguments}}{{if .IsInput}}{{$argWrap := $srv.Argument .}}
 | 
			
		||||
	if request.{{.Name}}, err = {{$argWrap.Marshal}}; err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
{{range .Arguments}}{{if .IsOutput}}
 | 
			
		||||
	{{.Name}} = response.{{.Name}}
 | 
			
		||||
{{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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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 .Services */}}
 | 
			
		||||
`))
 | 
			
		||||
 
 | 
			
		||||
@@ -199,6 +199,72 @@ type SCPDWithURN struct {
 | 
			
		||||
	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 {
 | 
			
		||||
	io.Closer
 | 
			
		||||
	*zip.Reader
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user