go-xmpp/_examples/xmpp_pubsub_client/xmpp_ps_client.go

279 lines
7.1 KiB
Go
Raw Normal View History

2020-01-14 10:12:54 -08:00
package main
import (
"context"
"encoding/xml"
"errors"
2020-01-14 10:12:54 -08:00
"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")
2020-01-14 10:12:54 -08:00
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)
2020-01-14 14:13:13 -08:00
log.Println("Received a message ! => \n" + string(data))
2020-01-14 10:12:54 -08:00
})
2020-03-06 07:44:01 -08:00
client, err := xmpp.NewClient(&config, router, func(err error) { log.Println(err) })
2020-01-14 10:12:54 -08:00
if err != nil {
log.Fatalf("%+v", err)
}
// ==========================
// Client connection
err = client.Connect()
if err != nil {
log.Fatalf("%+v", err)
}
// ==========================
// Create a node
2020-01-14 14:13:13 -08:00
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
createNode(ctx, cancel, client)
// ================================================================================
2020-01-14 14:13:13 -08:00
// 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)
}
2020-01-14 14:13:13 -08:00
select {
case purgeResp := <-purgeCh:
if purgeResp.Type == stanza.IQTypeError {
2020-01-14 14:13:13 -08:00
cancel()
if vld, err := purgeResp.IsValid(); !vld {
log.Fatalf(invalidResp.Error()+" %v"+" reason: %v", purgeResp, err)
}
2020-01-14 14:13:13 -08:00
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) {
2020-01-14 10:12:54 -08:00
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)
}
2020-01-14 10:12:54 -08:00
if respCr.Error.Reason != "conflict" {
log.Fatalf("%+v", respCr.Error.Text)
}
2020-01-14 14:13:13 -08:00
log.Println(respCr.Error.Text)
2020-01-14 10:12:54 -08:00
} else {
fmt.Print("successfully created channel")
}
case <-time.After(100 * time.Millisecond):
cancel()
2020-01-14 14:13:13 -08:00
log.Fatal("No iq response was received in time while creating node")
2020-01-14 10:12:54 -08:00
}
}
}
2020-01-14 14:13:13 -08:00
}
2020-01-14 10:12:54 -08:00
2020-01-14 14:13:13 -08:00
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 {
2020-01-14 14:13:13 -08:00
cancel()
if vld, err := confResp.IsValid(); !vld {
log.Fatalf(invalidResp.Error()+" %v"+" reason: %v", confResp, err)
}
2020-01-14 14:13:13 -08:00
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{
2020-01-14 10:12:54 -08:00
Node: nodeName,
Jid: userJID,
})
if err != nil {
log.Fatalf("%+v", err)
}
subRespCh, _ := client.SendIQ(ctx, rqSubscribe)
if subRespCh != nil {
select {
case <-subRespCh:
2020-01-14 14:13:13 -08:00
log.Println("Subscribed to the service")
case <-time.After(300 * time.Millisecond):
2020-01-14 10:12:54 -08:00
cancel()
2020-01-14 14:13:13 -08:00
log.Fatal("No iq response was received in time while subscribing")
2020-01-14 10:12:54 -08:00
}
}
2020-01-14 14:13:13 -08:00
}
2020-01-14 10:12:54 -08:00
2020-01-14 14:13:13 -08:00
func pubToNode(ctx context.Context, cancel context.CancelFunc, client *xmpp.Client) {
2020-01-14 10:12:54 -08:00
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:
2020-01-14 14:13:13 -08:00
log.Println("Published item to the service")
2020-01-14 13:47:49 -08:00
case <-time.After(300 * time.Millisecond):
cancel()
2020-01-14 14:13:13 -08:00
log.Fatal("No iq response was received in time while publishing")
2020-01-14 13:47:49 -08:00
}
}
2020-01-14 10:12:54 -08:00
}