xmpp/roster.go
changeset 153 bbd4166df95d
parent 142 0ff033eed887
child 155 fdd637733628
--- a/xmpp/roster.go	Sun Sep 22 17:43:34 2013 -0500
+++ b/xmpp/roster.go	Sat Sep 28 13:02:17 2013 -0600
@@ -22,15 +22,9 @@
 	Group        []string
 }
 
-type rosterCb struct {
-	id string
-	cb func()
-}
-
 type Roster struct {
 	Extension
 	get       chan []RosterItem
-	callbacks chan rosterCb
 	toServer  chan Stanza
 }
 
@@ -41,24 +35,21 @@
 
 func (r *Roster) rosterMgr(upd <-chan Stanza) {
 	roster := make(map[string]RosterItem)
-	waits := make(map[string]func())
 	var snapshot []RosterItem
+	var get chan<- []RosterItem
 	for {
 		select {
+		case get <- snapshot:
+
 		case stan, ok := <-upd:
 			if !ok {
 				return
 			}
-			hdr := stan.GetHeader()
-			if f := waits[hdr.Id]; f != nil {
-				delete(waits, hdr.Id)
-				f()
-			}
 			iq, ok := stan.(*Iq)
 			if !ok {
 				continue
 			}
-			if iq.Type != "result" {
+			if iq.Type != "result" && iq.Type != "set" {
 				continue
 			}
 			var rq *RosterQuery
@@ -78,9 +69,7 @@
 			for _, ri := range roster {
 				snapshot = append(snapshot, ri)
 			}
-		case r.get <- snapshot:
-		case cb := <-r.callbacks:
-			waits[cb.id] = cb.cb
+			get = r.get
 		}
 	}
 }
@@ -119,33 +108,22 @@
 	r.StanzaHandlers[rName] = reflect.TypeOf(RosterQuery{})
 	r.RecvFilter, r.SendFilter = r.makeFilters()
 	r.get = make(chan []RosterItem)
-	r.callbacks = make(chan rosterCb)
 	r.toServer = make(chan Stanza)
 	return &r
 }
 
 // Return the most recent snapshot of the roster status. This is
 // updated automatically as roster updates are received from the
-// server, but especially in response to calls to Update().
+// server. This function may block immediately after the XMPP
+// connection has been established, until the first roster update is
+// received from the server.
 func (r *Roster) Get() []RosterItem {
 	return <-r.get
 }
 
-// Synchronously fetch this entity's roster from the server and cache
-// that information. The client can access the roster by watching for
-// RosterQuery objects or by calling Get().
-func (r *Roster) Update() {
+// Asynchronously fetch this entity's roster from the server.
+func (r *Roster) update() {
 	iq := &Iq{Header: Header{Type: "get", Id: NextId(),
 		Nested: []interface{}{RosterQuery{}}}}
-	waitchan := make(chan int)
-	done := func() {
-		close(waitchan)
-	}
-	r.waitFor(iq.Id, done)
 	r.toServer <- iq
-	<-waitchan
 }
-
-func (r *Roster) waitFor(id string, cb func()) {
-	r.callbacks <- rosterCb{id: id, cb: cb}
-}