diff -r f464f14e39a7 -r 367e76b3028e roster.go --- a/roster.go Mon Sep 02 20:46:23 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xmpp - -// This file contains support for roster management, RFC 3921, Section 7. - -import ( - "encoding/xml" -) - -// Roster query/result -type RosterQuery struct { - XMLName xml.Name `xml:"jabber:iq:roster query"` - Item []RosterItem `xml:"item"` -} - -// See RFC 3921, Section 7.1. -type RosterItem struct { - XMLName xml.Name `xml:"jabber:iq:roster item"` - Jid string `xml:"jid,attr"` - Subscription string `xml:"subscription,attr"` - Name string `xml:"name,attr"` - Group []string -} - -type rosterCb struct { - id string - cb func() -} - -type Roster struct { - Extension - get chan []RosterItem - callbacks chan rosterCb - toServer chan Stanza -} - -type rosterClient struct { - rosterChan <-chan []RosterItem - rosterUpdate chan<- RosterItem -} - -// Implicitly becomes part of NewClient's extStanza arg. -func newRosterQuery(name *xml.Name) interface{} { - return &RosterQuery{} -} - -func (r *Roster) rosterMgr(upd <-chan Stanza) { - roster := make(map[string]RosterItem) - waits := make(map[string]func()) - var snapshot []RosterItem - for { - select { - 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 iq.Type != "set" { - continue - } - var rq *RosterQuery - for _, ele := range iq.Nested { - if q, ok := ele.(*RosterQuery); ok { - rq = q - break - } - } - if rq == nil { - continue - } - for _, item := range rq.Item { - roster[item.Jid] = item - } - snapshot = []RosterItem{} - for _, ri := range roster { - snapshot = append(snapshot, ri) - } - case r.get <- snapshot: - case cb := <- r.callbacks: - waits[cb.id] = cb.cb - } - } -} - -func (r *Roster) makeFilters() (Filter, Filter) { - rosterUpdate := make(chan Stanza) - go r.rosterMgr(rosterUpdate) - recv := func(in <-chan Stanza, out chan<- Stanza) { - defer close(out) - for stan := range in { - rosterUpdate <- stan - out <- stan - } - } - send := func(in <-chan Stanza, out chan<- Stanza) { - defer close(out) - for { - select { - case stan, ok := <- in: - if !ok { - return - } - out <- stan - case stan := <- r.toServer: - out <- stan - } - } - } - return recv, send -} - -func newRosterExt() *Roster { - r := Roster{} - r.StanzaHandlers = make(map[string]func(*xml.Name) interface{}) - r.StanzaHandlers[NsRoster] = newRosterQuery - 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(). -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() { - 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} -}