5 |
5 |
6 import ( |
6 import ( |
7 "encoding/xml" |
7 "encoding/xml" |
8 "fmt" |
8 "fmt" |
9 "io" |
9 "io" |
|
10 "log" |
10 "reflect" |
11 "reflect" |
11 "strings" |
12 "strings" |
12 ) |
13 ) |
13 |
14 |
14 // Read bytes from a reader, unmarshal them as XML into structures of |
15 // Read bytes from a reader, unmarshal them as XML into structures of |
15 // the appropriate type, and send those structures on a channel. |
16 // the appropriate type, and send those structures on a channel. |
16 func recvXml(r io.Reader, ch chan<- interface{}, |
17 func (cl *Client) recvXml(r io.Reader, ch chan<- interface{}, |
17 extStanza map[xml.Name]reflect.Type) { |
18 extStanza map[xml.Name]reflect.Type) { |
18 if _, ok := Debug.(*noLog); !ok { |
19 |
19 pr, pw := io.Pipe() |
|
20 go tee(r, pw, "S: ") |
|
21 r = pr |
|
22 } |
|
23 defer close(ch) |
20 defer close(ch) |
24 |
21 |
25 // This trick loads our namespaces into the parser. |
22 // This trick loads our namespaces into the parser. |
26 nsstr := fmt.Sprintf(`<a xmlns="%s" xmlns:stream="%s">`, |
23 nsstr := fmt.Sprintf(`<a xmlns="%s" xmlns:stream="%s">`, |
27 NsClient, NsStream) |
24 NsClient, NsStream) |
49 var obj interface{} |
46 var obj interface{} |
50 switch se.Name.Space + " " + se.Name.Local { |
47 switch se.Name.Space + " " + se.Name.Local { |
51 case NsStream + " stream": |
48 case NsStream + " stream": |
52 st, err := parseStream(se) |
49 st, err := parseStream(se) |
53 if err != nil { |
50 if err != nil { |
54 Warn.Logf("unmarshal stream: %s", err) |
51 cl.setError(fmt.Errorf("recv: %v", err)) |
55 break Loop |
52 break Loop |
56 } |
53 } |
57 ch <- st |
54 ch <- st |
58 continue |
55 continue |
59 case "stream error", NsStream + " error": |
56 case "stream error", NsStream + " error": |
71 obj = &Message{} |
68 obj = &Message{} |
72 case NsClient + " presence": |
69 case NsClient + " presence": |
73 obj = &Presence{} |
70 obj = &Presence{} |
74 default: |
71 default: |
75 obj = &Generic{} |
72 obj = &Generic{} |
76 Info.Logf("Ignoring unrecognized: %s %s", se.Name.Space, |
73 if Debug { |
77 se.Name.Local) |
74 log.Printf("Ignoring unrecognized: %s %s", |
|
75 se.Name.Space, se.Name.Local) |
|
76 } |
78 } |
77 } |
79 |
78 |
80 // Read the complete XML stanza. |
79 // Read the complete XML stanza. |
81 err = p.DecodeElement(obj, &se) |
80 err = p.DecodeElement(obj, &se) |
82 if err != nil { |
81 if err != nil { |
83 Warn.Logf("unmarshal: %s", err) |
82 cl.setError(fmt.Errorf("recv: %v", err)) |
84 break Loop |
83 break Loop |
85 } |
84 } |
86 |
85 |
87 // If it's a Stanza, we try to unmarshal its innerxml |
86 // If it's a Stanza, we try to unmarshal its innerxml |
88 // into objects of the appropriate respective |
87 // into objects of the appropriate respective |
89 // types. This is specified by our extensions. |
88 // types. This is specified by our extensions. |
90 if st, ok := obj.(Stanza); ok { |
89 if st, ok := obj.(Stanza); ok { |
91 err = parseExtended(st.GetHeader(), extStanza) |
90 err = parseExtended(st.GetHeader(), extStanza) |
92 if err != nil { |
91 if err != nil { |
93 Warn.Logf("ext unmarshal: %s", err) |
92 cl.setError(fmt.Errorf("recv: %v", err)) |
94 break Loop |
93 break Loop |
95 } |
94 } |
96 } |
95 } |
97 |
96 |
98 // Put it on the channel. |
97 // Put it on the channel. |
131 return nil |
130 return nil |
132 } |
131 } |
133 |
132 |
134 // Receive structures on a channel, marshal them to XML, and send the |
133 // Receive structures on a channel, marshal them to XML, and send the |
135 // bytes on a writer. |
134 // bytes on a writer. |
136 func sendXml(w io.Writer, ch <-chan interface{}) { |
135 func (cl *Client) sendXml(w io.Writer, ch <-chan interface{}) { |
137 if _, ok := Debug.(*noLog); !ok { |
|
138 pr, pw := io.Pipe() |
|
139 go tee(pr, w, "C: ") |
|
140 w = pw |
|
141 } |
|
142 defer func(w io.Writer) { |
136 defer func(w io.Writer) { |
143 if c, ok := w.(io.Closer); ok { |
137 if c, ok := w.(io.Closer); ok { |
144 c.Close() |
138 c.Close() |
145 } |
139 } |
146 }(w) |
140 }(w) |
149 |
143 |
150 for obj := range ch { |
144 for obj := range ch { |
151 if st, ok := obj.(*stream); ok { |
145 if st, ok := obj.(*stream); ok { |
152 _, err := w.Write([]byte(st.String())) |
146 _, err := w.Write([]byte(st.String())) |
153 if err != nil { |
147 if err != nil { |
154 Warn.Logf("write: %s", err) |
148 cl.setError(fmt.Errorf("send: %v", err)) |
|
149 break |
155 } |
150 } |
156 } else { |
151 } else { |
157 err := enc.Encode(obj) |
152 err := enc.Encode(obj) |
158 if err != nil { |
153 if err != nil { |
159 Warn.Logf("marshal: %s", err) |
154 cl.setError(fmt.Errorf("send: %v", err)) |
160 break |
155 break |
161 } |
156 } |
162 } |
157 } |
163 } |
158 } |
164 } |
159 } |