279 lines
7.1 KiB
Go
279 lines
7.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/xml"
|
|
"errors"
|
|
"fmt"
|
|
"gosrc.io/xmpp"
|
|
"gosrc.io/xmpp/stanza"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
userJID = "testuser2@localhost"
|
|
serverAddress = "localhost:5222"
|
|
nodeName = "lel_node"
|
|
serviceName = "pubsub.localhost"
|
|
)
|
|
|
|
var invalidResp = errors.New("invalid response")
|
|
|
|
func main() {
|
|
|
|
config := xmpp.Config{
|
|
TransportConfiguration: xmpp.TransportConfiguration{
|
|
Address: serverAddress,
|
|
},
|
|
Jid: userJID,
|
|
Credential: xmpp.Password("pass123"),
|
|
// StreamLogger: os.Stdout,
|
|
Insecure: true,
|
|
}
|
|
router := xmpp.NewRouter()
|
|
router.NewRoute().Packet("message").
|
|
HandlerFunc(func(s xmpp.Sender, p stanza.Packet) {
|
|
data, _ := xml.Marshal(p)
|
|
log.Println("Received a message ! => \n" + string(data))
|
|
})
|
|
|
|
client, err := xmpp.NewClient(&config, router, func(err error) { log.Println(err) })
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
}
|
|
|
|
// ==========================
|
|
// Client connection
|
|
err = client.Connect()
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
}
|
|
|
|
// ==========================
|
|
// Create a node
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
createNode(ctx, cancel, client)
|
|
|
|
// ================================================================================
|
|
// Configure the node. This can also be done in a single message with the creation
|
|
configureNode(ctx, cancel, client)
|
|
|
|
// ====================================
|
|
// Subscribe to this node :
|
|
subToNode(ctx, cancel, client)
|
|
|
|
// ==========================
|
|
// Publish to that node
|
|
pubToNode(ctx, cancel, client)
|
|
|
|
// =============================
|
|
// Let's purge the node :
|
|
purgeRq, _ := stanza.NewPurgeAllItems(serviceName, nodeName)
|
|
purgeCh, err := client.SendIQ(ctx, purgeRq)
|
|
if err != nil {
|
|
log.Fatalf("could not send purge request: %v", err)
|
|
}
|
|
select {
|
|
case purgeResp := <-purgeCh:
|
|
|
|
if purgeResp.Type == stanza.IQTypeError {
|
|
cancel()
|
|
if vld, err := purgeResp.IsValid(); !vld {
|
|
log.Fatalf(invalidResp.Error()+" %v"+" reason: %v", purgeResp, err)
|
|
}
|
|
log.Fatalf("error while purging node : %s", purgeResp.Error.Text)
|
|
}
|
|
log.Println("node successfully purged")
|
|
case <-time.After(1000 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while purging node")
|
|
}
|
|
|
|
cancel()
|
|
}
|
|
|
|
func createNode(ctx context.Context, cancel context.CancelFunc, client *xmpp.Client) {
|
|
rqCreate, err := stanza.NewCreateNode(serviceName, nodeName)
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
}
|
|
createCh, err := client.SendIQ(ctx, rqCreate)
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
} else {
|
|
|
|
if createCh != nil {
|
|
select {
|
|
case respCr := <-createCh:
|
|
// Got response from server
|
|
if respCr.Type == stanza.IQTypeError {
|
|
if vld, err := respCr.IsValid(); !vld {
|
|
log.Fatalf(invalidResp.Error()+" %+v"+" reason: %s", respCr, err)
|
|
}
|
|
if respCr.Error.Reason != "conflict" {
|
|
log.Fatalf("%+v", respCr.Error.Text)
|
|
}
|
|
log.Println(respCr.Error.Text)
|
|
} else {
|
|
fmt.Print("successfully created channel")
|
|
}
|
|
case <-time.After(100 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while creating node")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func configureNode(ctx context.Context, cancel context.CancelFunc, client *xmpp.Client) {
|
|
// First, ask for a form with the config options
|
|
confRq, _ := stanza.NewConfigureNode(serviceName, nodeName)
|
|
confReqCh, err := client.SendIQ(ctx, confRq)
|
|
if err != nil {
|
|
log.Fatalf("could not send iq : %v", err)
|
|
}
|
|
select {
|
|
case confForm := <-confReqCh:
|
|
// If the request was successful, we now have a form with configuration options to update
|
|
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"
|
|
}
|
|
|
|
// Send the modified fields as a form
|
|
submitConf, err := stanza.NewFormSubmissionOwner(serviceName,
|
|
nodeName,
|
|
[]*stanza.Field{
|
|
fields["pubsub#max_payload_size"],
|
|
fields["pubsub#notification_type"],
|
|
})
|
|
|
|
c, _ := client.SendIQ(ctx, submitConf)
|
|
select {
|
|
case confResp := <-c:
|
|
if confResp.Type == stanza.IQTypeError {
|
|
cancel()
|
|
if vld, err := confResp.IsValid(); !vld {
|
|
log.Fatalf(invalidResp.Error()+" %v"+" reason: %v", confResp, err)
|
|
}
|
|
log.Fatalf("node configuration failed : %s", confResp.Error.Text)
|
|
}
|
|
log.Println("node configuration was successful")
|
|
return
|
|
|
|
case <-time.After(300 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while configuring the node")
|
|
}
|
|
|
|
case <-time.After(300 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while asking for the config form")
|
|
}
|
|
}
|
|
|
|
func subToNode(ctx context.Context, cancel context.CancelFunc, client *xmpp.Client) {
|
|
rqSubscribe, err := stanza.NewSubRq(serviceName, stanza.SubInfo{
|
|
Node: nodeName,
|
|
Jid: userJID,
|
|
})
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
}
|
|
subRespCh, _ := client.SendIQ(ctx, rqSubscribe)
|
|
if subRespCh != nil {
|
|
select {
|
|
case <-subRespCh:
|
|
log.Println("Subscribed to the service")
|
|
case <-time.After(300 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while subscribing")
|
|
}
|
|
}
|
|
}
|
|
|
|
func pubToNode(ctx context.Context, cancel context.CancelFunc, client *xmpp.Client) {
|
|
pub, err := stanza.NewPublishItemRq(serviceName, nodeName, "", stanza.Item{
|
|
Publisher: "testuser2",
|
|
Any: &stanza.Node{
|
|
XMLName: xml.Name{
|
|
Space: "http://www.w3.org/2005/Atom",
|
|
Local: "entry",
|
|
},
|
|
Nodes: []stanza.Node{
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "title"},
|
|
Attrs: nil,
|
|
Content: "My pub item title",
|
|
Nodes: nil,
|
|
},
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "summary"},
|
|
Attrs: nil,
|
|
Content: "My pub item content summary",
|
|
Nodes: nil,
|
|
},
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "link"},
|
|
Attrs: []xml.Attr{
|
|
{
|
|
Name: xml.Name{Space: "", Local: "rel"},
|
|
Value: "alternate",
|
|
},
|
|
{
|
|
Name: xml.Name{Space: "", Local: "type"},
|
|
Value: "text/html",
|
|
},
|
|
{
|
|
Name: xml.Name{Space: "", Local: "href"},
|
|
Value: "http://denmark.lit/2003/12/13/atom03",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "id"},
|
|
Attrs: nil,
|
|
Content: "My pub item content ID",
|
|
Nodes: nil,
|
|
},
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "published"},
|
|
Attrs: nil,
|
|
Content: "2003-12-13T18:30:02Z",
|
|
Nodes: nil,
|
|
},
|
|
{
|
|
XMLName: xml.Name{Space: "", Local: "updated"},
|
|
Attrs: nil,
|
|
Content: "2003-12-13T18:30:02Z",
|
|
Nodes: nil,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
log.Fatalf("%+v", err)
|
|
}
|
|
pubRespCh, _ := client.SendIQ(ctx, pub)
|
|
if pubRespCh != nil {
|
|
select {
|
|
case <-pubRespCh:
|
|
log.Println("Published item to the service")
|
|
case <-time.After(300 * time.Millisecond):
|
|
cancel()
|
|
log.Fatal("No iq response was received in time while publishing")
|
|
}
|
|
}
|
|
}
|