Merge pull request #140 from remicorniere/Roster_Chat_Example

Added roster update to chat client example
This commit is contained in:
remicorniere 2019-12-23 09:07:56 +00:00 committed by GitHub
commit 26114d40eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 13 deletions

View file

@ -6,5 +6,5 @@ require (
github.com/awesome-gocui/gocui v0.6.1-0.20191115151952-a34ffb055986
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.1
gosrc.io/xmpp v0.3.1-0.20191212145100-27130d72926b
gosrc.io/xmpp v0.3.1-0.20191223080939-f8f820170e08
)

View file

@ -9,7 +9,7 @@ import (
)
const (
// Windows
// Windows
chatLogWindow = "clw" // Where (received and sent) messages are logged
chatInputWindow = "iw" // Where messages are written
rawInputWindow = "rw" // Where raw stanzas are written
@ -71,7 +71,11 @@ func layout(g *gocui.Gui) error {
}
v.Title = "Contacts"
v.Wrap = true
v.Autoscroll = true
// If we set this to true, the contacts list will "fit" in the window but if the number
// of contacts exceeds the maximum height, some contacts will be hidden...
// If set to false, we can scroll up and down the contact list... infinitely. Meaning lower lines
// will be unlimited and empty... Didn't find a way to quickfix yet.
v.Autoscroll = false
}
if v, err := g.SetView(menuWindow, 0, 0, maxX/5-1, 5*maxY/6-2, 0); err != nil {
@ -215,7 +219,7 @@ func getLine(g *gocui.Gui, v *gocui.View) error {
if len(cv.ViewBufferLines()) == 0 {
printContactsToWindow(g, viewState.contacts)
}
} else if l == disconnect {
} else if l == disconnect {
maxX, maxY := g.Size()
msg := "You disconnected from the server. Press enter to quit."
if v, err := g.SetView(disconnectMsg, maxX/2-30, maxY/2, maxX/2-29+len(msg), maxY/2+2, 0); err != nil {
@ -226,11 +230,12 @@ func getLine(g *gocui.Gui, v *gocui.View) error {
if _, err := g.SetCurrentView(disconnectMsg); err != nil {
return err
}
}
}
killChan <- disconnectErr
} else if l == askServerForRoster {
chlw, _ := g.View(chatLogWindow)
fmt.Fprintln(chlw, infoFormat+" Not yet implemented !")
fmt.Fprintln(chlw, infoFormat+"Asking server for contacts list...")
rosterChan <- struct{}{}
} else if l == rawMode {
mw, _ := g.View(menuWindow)
viewState.input = rawInputWindow

View file

@ -5,6 +5,7 @@ xmpp_chat_client is a demo client that connect on an XMPP server to chat with ot
*/
import (
"context"
"encoding/xml"
"errors"
"flag"
@ -19,6 +20,7 @@ import (
"path"
"strconv"
"strings"
"time"
)
const (
@ -43,6 +45,7 @@ var (
rawTextChan = make(chan string, 5)
killChan = make(chan error, 1)
errChan = make(chan error)
rosterChan = make(chan struct{})
logger *log.Logger
disconnectErr = errors.New("disconnecting client")
@ -182,7 +185,6 @@ func startClient(g *gocui.Gui, config *config) {
// ==========================
// Start working
//askForRoster(client, g)
updateRosterFromConfig(g, config)
// Sending the default contact in a channel. Default value is the first contact in the list from the config.
viewState.currentContact = strings.Split(config.Contacts, configContactSep)[0]
@ -190,10 +192,10 @@ func startClient(g *gocui.Gui, config *config) {
clw, _ := g.View(chatLogWindow)
fmt.Fprintf(clw, infoFormat+"Now sending messages to "+viewState.currentContact+" in a private conversation\n")
CorrespChan <- viewState.currentContact
startMessaging(client, config)
startMessaging(client, config, g)
}
func startMessaging(client xmpp.Sender, config *config) {
func startMessaging(client xmpp.Sender, config *config, g *gocui.Gui) {
var text string
var correspondent string
for {
@ -228,6 +230,8 @@ func startMessaging(client xmpp.Sender, config *config) {
}
case crrsp := <-CorrespChan:
correspondent = crrsp
case <-rosterChan:
askForRoster(client, g, config)
}
}
@ -282,10 +286,43 @@ func updateRosterFromConfig(g *gocui.Gui, config *config) {
viewState.contacts = append(strings.Split(config.Contacts, configContactSep), backFromContacts)
}
// Updates the menu panel of the view with the current user's roster.
// Need to add support for Roster IQ stanzas to make this work.
func askForRoster(client *xmpp.Client, g *gocui.Gui) {
// Not implemented yet !
// Updates the menu panel of the view with the current user's roster, by asking the server.
func askForRoster(client xmpp.Sender, g *gocui.Gui, config *config) {
// Craft a roster request
req := stanza.NewIQ(stanza.Attrs{From: config.Client[clientJid], Type: stanza.IQTypeGet})
req.RosterItems()
if logger != nil {
m, _ := xml.Marshal(req)
logger.Println(string(m))
}
ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
// Send the roster request to the server
c, err := client.SendIQ(ctx, req)
if err != nil {
logger.Panicln(err)
}
// Sending a IQ has a channel spawned to process the response once we receive it.
// In order not to block the client, we spawn a goroutine to update the TUI once the server has responded.
go func() {
serverResp := <-c
if logger != nil {
m, _ := xml.Marshal(serverResp)
logger.Println(string(m))
}
// Update contacts with the response from the server
chlw, _ := g.View(chatLogWindow)
if rosterItems, ok := serverResp.Payload.(*stanza.RosterItems); ok {
viewState.contacts = []string{}
for _, item := range rosterItems.Items {
viewState.contacts = append(viewState.contacts, item.Jid)
}
fmt.Fprintln(chlw, infoFormat+"Contacts list updated !")
return
}
fmt.Fprintln(chlw, infoFormat+"Failed to update contact list !")
}()
}
func isDirectory(path string) (bool, error) {