From 20e02cc9ad460e6519cf6d89c4722f00dfd4f49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?CORNIERE=20R=C3=A9mi?= Date: Tue, 14 Jan 2020 22:47:49 +0100 Subject: [PATCH] Added node config --- .../xmpp_pubsub_client/xmpp_ps_client.go | 42 +++++++++++++++++++ stanza/form.go | 4 +- stanza/form_test.go | 2 +- stanza/pubsub_owner.go | 31 +++++++++++--- stanza/pubsub_owner_test.go | 4 +- stanza/pubsub_test.go | 4 +- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/_examples/xmpp_pubsub_client/xmpp_ps_client.go b/_examples/xmpp_pubsub_client/xmpp_ps_client.go index 972b94d..eba9bbd 100644 --- a/_examples/xmpp_pubsub_client/xmpp_ps_client.go +++ b/_examples/xmpp_pubsub_client/xmpp_ps_client.go @@ -178,5 +178,47 @@ func main() { purgeRq, _ := stanza.NewPurgeAllItems(serviceName, nodeName) client.SendIQ(ctx, purgeRq) + // ============================= + // Configure the node : + confRq, _ := stanza.NewConfigureNode(serviceName, nodeName) + confReqCh, err := client.SendIQ(ctx, confRq) + select { + case confForm := <-confReqCh: + fields, err := confForm.GetFormFields() + if err != nil { + log.Fatal("No config fields found !") + } + + // These are some common fields expected to be present. Change processing to your liking + if fields["pubsub#max_payload_size"] != nil { + fields["pubsub#max_payload_size"].ValuesList[0] = "100000" + } + + if fields["pubsub#notification_type"] != nil { + fields["pubsub#notification_type"].ValuesList[0] = "headline" + } + + submitConf, err := stanza.NewFormSubmissionOwner(serviceName, + nodeName, + []*stanza.Field{ + fields["pubsub#max_payload_size"], + fields["pubsub#notification_type"], + }) + + c, _ := client.SendIQ(ctx, submitConf) + select { + case <-c: + fmt.Println("node configuration was successful") + case <-time.After(300 * time.Millisecond): + cancel() + log.Fatal("No iq response was received in time") + + } + + case <-time.After(300 * time.Millisecond): + cancel() + log.Fatal("No iq response was received in time") + } + cancel() } diff --git a/stanza/form.go b/stanza/form.go index b9a9932..f22c6ce 100644 --- a/stanza/form.go +++ b/stanza/form.go @@ -17,7 +17,7 @@ type Form struct { XMLName xml.Name `xml:"jabber:x:data x"` Instructions []string `xml:"instructions"` Title string `xml:"title,omitempty"` - Fields []Field `xml:"field,omitempty"` + Fields []*Field `xml:"field,omitempty"` Reported *FormItem `xml:"reported"` Items []FormItem Type string `xml:"type,attr"` @@ -38,7 +38,7 @@ type Field struct { Label string `xml:"label,attr,omitempty"` } -func NewForm(fields []Field, formType string) *Form { +func NewForm(fields []*Field, formType string) *Form { return &Form{ Type: formType, Fields: fields, diff --git a/stanza/form_test.go b/stanza/form_test.go index a68d88e..7346db2 100644 --- a/stanza/form_test.go +++ b/stanza/form_test.go @@ -57,7 +57,7 @@ func TestMarshalFormSubmit(t *testing.T) { Node: serviceNode, Form: &Form{ Type: FormTypeSubmit, - Fields: []Field{ + Fields: []*Field{ {Var: "FORM_TYPE", Type: FieldTypeHidden, ValuesList: []string{"http://jabber.org/protocol/pubsub#node_config"}}, {Var: "pubsub#title", ValuesList: []string{"Princely Musings (Atom)"}}, {Var: "pubsub#deliver_notifications", ValuesList: []string{"1"}}, diff --git a/stanza/pubsub_owner.go b/stanza/pubsub_owner.go index 054303f..9adfbef 100644 --- a/stanza/pubsub_owner.go +++ b/stanza/pubsub_owner.go @@ -198,7 +198,7 @@ func NewApprovePendingSubRequest(serviceId, sessionId, nodeId string) (IQ, error form := &Form{ Type: FormTypeSubmit, - Fields: []Field{{Var: "pubsub#node", ValuesList: []string{nodeId}}}, + Fields: []*Field{{Var: "pubsub#node", ValuesList: []string{nodeId}}}, } data, err := xml.Marshal(form) if err != nil { @@ -262,25 +262,44 @@ func NewAffiliationListRequest(serviceId, nodeID string) (IQ, error) { return iq, nil } +// NewFormSubmission builds a form submission pubsub IQ, in the Owner namespace +// This is typically used to respond to a form issued by the server when configuring a node. +// See 8.2.4 Form Submission +func NewFormSubmissionOwner(serviceId, nodeName string, fields []*Field) (IQ, error) { + if serviceId == "" || nodeName == "" { + return IQ{}, errors.New("serviceId and nodeName must be filled for this request to be valid") + } + + submitConf := NewIQ(Attrs{Type: IQTypeSet, To: serviceId}) + submitConf.Payload = &PubSubOwner{ + OwnerUseCase: &ConfigureOwner{ + Node: nodeName, + Form: NewForm(fields, + FormTypeSubmit)}, + } + + return submitConf, nil +} + // GetFormFields gets the fields from a form in a IQ stanza of type result, as a map. // Key is the "var" attribute of the field, and field is the value. // The user can then select and modify the fields they want to alter, and submit a new form to the service using the // NewFormSubmission function to build the IQ. // TODO : remove restriction on IQ type ? -func (iq *IQ) GetFormFields() (map[string]Field, error) { +func (iq *IQ) GetFormFields() (map[string]*Field, error) { if iq.Type != IQTypeResult { return nil, errors.New("this IQ is not a result type IQ. Cannot extract the form from it") } switch payload := iq.Payload.(type) { // We support IOT Control IQ case *PubSubGeneric: - fieldMap := make(map[string]Field) + fieldMap := make(map[string]*Field) for _, elt := range payload.Configure.Form.Fields { fieldMap[elt.Var] = elt } return fieldMap, nil case *PubSubOwner: - fieldMap := make(map[string]Field) + fieldMap := make(map[string]*Field) co, ok := payload.OwnerUseCase.(*ConfigureOwner) if !ok { return nil, errors.New("this IQ does not contain a PubSub payload with a configure tag for the owner namespace") @@ -291,7 +310,7 @@ func (iq *IQ) GetFormFields() (map[string]Field, error) { return fieldMap, nil default: if iq.Any != nil { - fieldMap := make(map[string]Field) + fieldMap := make(map[string]*Field) if iq.Any.XMLName.Local != "command" { return nil, errors.New("this IQ does not contain a form") } @@ -307,7 +326,7 @@ func (iq *IQ) GetFormFields() (map[string]Field, error) { } err = xml.Unmarshal(data, &f) if err == nil { - fieldMap[f.Var] = f + fieldMap[f.Var] = &f } } } diff --git a/stanza/pubsub_owner_test.go b/stanza/pubsub_owner_test.go index 8af6194..665fba3 100644 --- a/stanza/pubsub_owner_test.go +++ b/stanza/pubsub_owner_test.go @@ -357,7 +357,7 @@ func TestNewApproveSubRequest(t *testing.T) { apprForm := &stanza.Form{ Type: stanza.FormTypeSubmit, - Fields: []stanza.Field{ + Fields: []*stanza.Field{ {Var: "FORM_TYPE", Type: stanza.FieldTypeHidden, ValuesList: []string{"http://jabber.org/protocol/pubsub#subscribe_authorization"}}, {Var: "pubsub#subid", ValuesList: []string{"123-abc"}}, {Var: "pubsub#node", ValuesList: []string{"princely_musings"}}, @@ -381,7 +381,7 @@ func TestNewApproveSubRequest(t *testing.T) { for _, f := range frm.Fields { if f.Var == "pubsub#allow" { - allowField = &f + allowField = f } } if allowField == nil || allowField.ValuesList[0] != "true" { diff --git a/stanza/pubsub_test.go b/stanza/pubsub_test.go index 95bf640..6b413c4 100644 --- a/stanza/pubsub_test.go +++ b/stanza/pubsub_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -var submitFormExample = stanza.NewForm([]stanza.Field{ +var submitFormExample = stanza.NewForm([]*stanza.Field{ {Var: "FORM_TYPE", Type: stanza.FieldTypeHidden, ValuesList: []string{"http://jabber.org/protocol/pubsub#node_config"}}, {Var: "pubsub#title", ValuesList: []string{"Princely Musings (Atom)"}}, {Var: "pubsub#deliver_notifications", ValuesList: []string{"1"}}, @@ -741,7 +741,7 @@ func TestNewCreateAndConfigNode(t *testing.T) { "princely_musings", &stanza.Form{ Type: stanza.FormTypeSubmit, - Fields: []stanza.Field{ + Fields: []*stanza.Field{ {Var: "FORM_TYPE", Type: stanza.FieldTypeHidden, ValuesList: []string{"http://jabber.org/protocol/pubsub#node_config"}}, {Var: "pubsub#notify_retract", ValuesList: []string{"0"}}, {Var: "pubsub#notify_sub", ValuesList: []string{"0"}},