Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: webrtc/libjingle/xmpp/pubsubstateclient.h

Issue 2617443003: Remove webrtc/libjingle/{xmllite,xmpp} (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
12 #define WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
13
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <vector>
18
19 #include "webrtc/libjingle/xmllite/qname.h"
20 #include "webrtc/libjingle/xmllite/xmlelement.h"
21 #include "webrtc/libjingle/xmpp/constants.h"
22 #include "webrtc/libjingle/xmpp/jid.h"
23 #include "webrtc/libjingle/xmpp/pubsubclient.h"
24 #include "webrtc/base/constructormagic.h"
25 #include "webrtc/base/sigslot.h"
26 #include "webrtc/base/sigslotrepeater.h"
27
28 namespace buzz {
29
30 // To handle retracts correctly, we need to remember certain details
31 // about an item. We could just cache the entire XML element, but
32 // that would take more memory and require re-parsing.
33 struct StateItemInfo {
34 std::string published_nick;
35 std::string publisher_nick;
36 };
37
38 // Represents a PubSub state change. Usually, the key is the nick,
39 // but not always. It's a per-state-type thing. Look below on how keys are
40 // computed.
41 template <typename C>
42 struct PubSubStateChange {
43 // The nick of the user changing the state.
44 std::string publisher_nick;
45 // The nick of the user whose state is changing.
46 std::string published_nick;
47 C old_state;
48 C new_state;
49 };
50
51 // Knows how to handle specific states and XML.
52 template <typename C>
53 class PubSubStateSerializer {
54 public:
55 virtual ~PubSubStateSerializer() {}
56 virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
57 virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
58 };
59
60 // Knows how to create "keys" for states, which determines their
61 // uniqueness. Most states are per-nick, but block is
62 // per-blocker-and-blockee. This is independent of itemid, especially
63 // in the case of presenter state.
64 class PubSubStateKeySerializer {
65 public:
66 virtual ~PubSubStateKeySerializer() {}
67 virtual std::string GetKey(const std::string& publisher_nick,
68 const std::string& published_nick) = 0;
69 };
70
71 class PublishedNickKeySerializer : public PubSubStateKeySerializer {
72 public:
73 virtual std::string GetKey(const std::string& publisher_nick,
74 const std::string& published_nick);
75 };
76
77 class PublisherAndPublishedNicksKeySerializer
78 : public PubSubStateKeySerializer {
79 public:
80 virtual std::string GetKey(const std::string& publisher_nick,
81 const std::string& published_nick);
82 };
83
84 // Adapts PubSubClient to be specifically suited for pub sub call
85 // states. Signals state changes and keeps track of keys, which are
86 // normally nicks.
87 template <typename C>
88 class PubSubStateClient : public sigslot::has_slots<> {
89 public:
90 // Gets ownership of the serializers, but not the client.
91 PubSubStateClient(const std::string& publisher_nick,
92 PubSubClient* client,
93 const QName& state_name,
94 C default_state,
95 PubSubStateKeySerializer* key_serializer,
96 PubSubStateSerializer<C>* state_serializer)
97 : publisher_nick_(publisher_nick),
98 client_(client),
99 state_name_(state_name),
100 default_state_(default_state) {
101 key_serializer_.reset(key_serializer);
102 state_serializer_.reset(state_serializer);
103 client_->SignalItems.connect(
104 this, &PubSubStateClient<C>::OnItems);
105 client_->SignalPublishResult.connect(
106 this, &PubSubStateClient<C>::OnPublishResult);
107 client_->SignalPublishError.connect(
108 this, &PubSubStateClient<C>::OnPublishError);
109 client_->SignalRetractResult.connect(
110 this, &PubSubStateClient<C>::OnRetractResult);
111 client_->SignalRetractError.connect(
112 this, &PubSubStateClient<C>::OnRetractError);
113 }
114
115 virtual ~PubSubStateClient() {}
116
117 virtual void Publish(const std::string& published_nick,
118 const C& state,
119 std::string* task_id_out) {
120 std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
121 std::string itemid = state_name_.LocalPart() + ":" + key;
122 if (StatesEqual(state, default_state_)) {
123 client_->RetractItem(itemid, task_id_out);
124 } else {
125 XmlElement* state_elem = state_serializer_->Write(state_name_, state);
126 state_elem->AddAttr(QN_NICK, published_nick);
127 client_->PublishItem(itemid, state_elem, task_id_out);
128 }
129 }
130
131 sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
132 // Signal (task_id, item). item is NULL for retract.
133 sigslot::signal2<const std::string&,
134 const XmlElement*> SignalPublishResult;
135 // Signal (task_id, item, error stanza). item is NULL for retract.
136 sigslot::signal3<const std::string&,
137 const XmlElement*,
138 const XmlElement*> SignalPublishError;
139
140 protected:
141 // return false if retracted item (no info or state given)
142 virtual bool ParseStateItem(const PubSubItem& item,
143 StateItemInfo* info_out,
144 C* state_out) {
145 const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
146 if (state_elem == NULL) {
147 return false;
148 }
149
150 info_out->publisher_nick =
151 client_->GetPublisherNickFromPubSubItem(item.elem);
152 info_out->published_nick = state_elem->Attr(QN_NICK);
153 state_serializer_->Parse(state_elem, state_out);
154 return true;
155 }
156
157 virtual bool StatesEqual(const C& state1, const C& state2) {
158 return state1 == state2;
159 }
160
161 PubSubClient* client() { return client_; }
162 const QName& state_name() { return state_name_; }
163
164 private:
165 void OnItems(PubSubClient* pub_sub_client,
166 const std::vector<PubSubItem>& items) {
167 for (std::vector<PubSubItem>::const_iterator item = items.begin();
168 item != items.end(); ++item) {
169 OnItem(*item);
170 }
171 }
172
173 void OnItem(const PubSubItem& item) {
174 const std::string& itemid = item.itemid;
175 StateItemInfo info;
176 C new_state;
177
178 bool retracted = !ParseStateItem(item, &info, &new_state);
179 if (retracted) {
180 bool known_itemid =
181 (info_by_itemid_.find(itemid) != info_by_itemid_.end());
182 if (!known_itemid) {
183 // Nothing to retract, and nothing to publish.
184 // Probably a different state type.
185 return;
186 } else {
187 info = info_by_itemid_[itemid];
188 info_by_itemid_.erase(itemid);
189 new_state = default_state_;
190 }
191 } else {
192 // TODO: Assert new key matches the known key. It
193 // shouldn't change!
194 info_by_itemid_[itemid] = info;
195 }
196
197 std::string key = key_serializer_->GetKey(
198 info.publisher_nick, info.published_nick);
199 bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
200 C old_state = has_old_state ? state_by_key_[key] : default_state_;
201 if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
202 // Nothing change, so don't bother signalling.
203 return;
204 }
205
206 if (retracted || StatesEqual(new_state, default_state_)) {
207 // We treat a default state similar to a retract.
208 state_by_key_.erase(key);
209 } else {
210 state_by_key_[key] = new_state;
211 }
212
213 PubSubStateChange<C> change;
214 if (!retracted) {
215 // Retracts do not have publisher information.
216 change.publisher_nick = info.publisher_nick;
217 }
218 change.published_nick = info.published_nick;
219 change.old_state = old_state;
220 change.new_state = new_state;
221 SignalStateChange(change);
222 }
223
224 void OnPublishResult(PubSubClient* pub_sub_client,
225 const std::string& task_id,
226 const XmlElement* item) {
227 SignalPublishResult(task_id, item);
228 }
229
230 void OnPublishError(PubSubClient* pub_sub_client,
231 const std::string& task_id,
232 const buzz::XmlElement* item,
233 const buzz::XmlElement* stanza) {
234 SignalPublishError(task_id, item, stanza);
235 }
236
237 void OnRetractResult(PubSubClient* pub_sub_client,
238 const std::string& task_id) {
239 // There's no point in differentiating between publish and retract
240 // errors, so we simplify by making them both signal a publish
241 // result.
242 const XmlElement* item = NULL;
243 SignalPublishResult(task_id, item);
244 }
245
246 void OnRetractError(PubSubClient* pub_sub_client,
247 const std::string& task_id,
248 const buzz::XmlElement* stanza) {
249 // There's no point in differentiating between publish and retract
250 // errors, so we simplify by making them both signal a publish
251 // error.
252 const XmlElement* item = NULL;
253 SignalPublishError(task_id, item, stanza);
254 }
255
256 std::string publisher_nick_;
257 PubSubClient* client_;
258 const QName state_name_;
259 C default_state_;
260 std::unique_ptr<PubSubStateKeySerializer> key_serializer_;
261 std::unique_ptr<PubSubStateSerializer<C> > state_serializer_;
262 // key => state
263 std::map<std::string, C> state_by_key_;
264 // itemid => StateItemInfo
265 std::map<std::string, StateItemInfo> info_by_itemid_;
266
267 RTC_DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
268 };
269 } // namespace buzz
270
271 #endif // WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
OLDNEW
« no previous file with comments | « webrtc/libjingle/xmpp/pubsubclient_unittest.cc ('k') | webrtc/libjingle/xmpp/pubsubstateclient.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698