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

Unified Diff: webrtc/libjingle/xmpp/pubsubstateclient.h

Issue 2618633003: Revert of 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/libjingle/xmpp/pubsubclient_unittest.cc ('k') | webrtc/libjingle/xmpp/pubsubstateclient.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/libjingle/xmpp/pubsubstateclient.h
diff --git a/webrtc/libjingle/xmpp/pubsubstateclient.h b/webrtc/libjingle/xmpp/pubsubstateclient.h
new file mode 100644
index 0000000000000000000000000000000000000000..07aa26dbad5eb3e429011241df8bdb9662b43ab7
--- /dev/null
+++ b/webrtc/libjingle/xmpp/pubsubstateclient.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
+#define WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/libjingle/xmpp/pubsubclient.h"
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sigslotrepeater.h"
+
+namespace buzz {
+
+// To handle retracts correctly, we need to remember certain details
+// about an item. We could just cache the entire XML element, but
+// that would take more memory and require re-parsing.
+struct StateItemInfo {
+ std::string published_nick;
+ std::string publisher_nick;
+};
+
+// Represents a PubSub state change. Usually, the key is the nick,
+// but not always. It's a per-state-type thing. Look below on how keys are
+// computed.
+template <typename C>
+struct PubSubStateChange {
+ // The nick of the user changing the state.
+ std::string publisher_nick;
+ // The nick of the user whose state is changing.
+ std::string published_nick;
+ C old_state;
+ C new_state;
+};
+
+// Knows how to handle specific states and XML.
+template <typename C>
+class PubSubStateSerializer {
+ public:
+ virtual ~PubSubStateSerializer() {}
+ virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
+ virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
+};
+
+// Knows how to create "keys" for states, which determines their
+// uniqueness. Most states are per-nick, but block is
+// per-blocker-and-blockee. This is independent of itemid, especially
+// in the case of presenter state.
+class PubSubStateKeySerializer {
+ public:
+ virtual ~PubSubStateKeySerializer() {}
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick) = 0;
+};
+
+class PublishedNickKeySerializer : public PubSubStateKeySerializer {
+ public:
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick);
+};
+
+class PublisherAndPublishedNicksKeySerializer
+ : public PubSubStateKeySerializer {
+ public:
+ virtual std::string GetKey(const std::string& publisher_nick,
+ const std::string& published_nick);
+};
+
+// Adapts PubSubClient to be specifically suited for pub sub call
+// states. Signals state changes and keeps track of keys, which are
+// normally nicks.
+template <typename C>
+class PubSubStateClient : public sigslot::has_slots<> {
+ public:
+ // Gets ownership of the serializers, but not the client.
+ PubSubStateClient(const std::string& publisher_nick,
+ PubSubClient* client,
+ const QName& state_name,
+ C default_state,
+ PubSubStateKeySerializer* key_serializer,
+ PubSubStateSerializer<C>* state_serializer)
+ : publisher_nick_(publisher_nick),
+ client_(client),
+ state_name_(state_name),
+ default_state_(default_state) {
+ key_serializer_.reset(key_serializer);
+ state_serializer_.reset(state_serializer);
+ client_->SignalItems.connect(
+ this, &PubSubStateClient<C>::OnItems);
+ client_->SignalPublishResult.connect(
+ this, &PubSubStateClient<C>::OnPublishResult);
+ client_->SignalPublishError.connect(
+ this, &PubSubStateClient<C>::OnPublishError);
+ client_->SignalRetractResult.connect(
+ this, &PubSubStateClient<C>::OnRetractResult);
+ client_->SignalRetractError.connect(
+ this, &PubSubStateClient<C>::OnRetractError);
+ }
+
+ virtual ~PubSubStateClient() {}
+
+ virtual void Publish(const std::string& published_nick,
+ const C& state,
+ std::string* task_id_out) {
+ std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
+ std::string itemid = state_name_.LocalPart() + ":" + key;
+ if (StatesEqual(state, default_state_)) {
+ client_->RetractItem(itemid, task_id_out);
+ } else {
+ XmlElement* state_elem = state_serializer_->Write(state_name_, state);
+ state_elem->AddAttr(QN_NICK, published_nick);
+ client_->PublishItem(itemid, state_elem, task_id_out);
+ }
+ }
+
+ sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
+ // Signal (task_id, item). item is NULL for retract.
+ sigslot::signal2<const std::string&,
+ const XmlElement*> SignalPublishResult;
+ // Signal (task_id, item, error stanza). item is NULL for retract.
+ sigslot::signal3<const std::string&,
+ const XmlElement*,
+ const XmlElement*> SignalPublishError;
+
+ protected:
+ // return false if retracted item (no info or state given)
+ virtual bool ParseStateItem(const PubSubItem& item,
+ StateItemInfo* info_out,
+ C* state_out) {
+ const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
+ if (state_elem == NULL) {
+ return false;
+ }
+
+ info_out->publisher_nick =
+ client_->GetPublisherNickFromPubSubItem(item.elem);
+ info_out->published_nick = state_elem->Attr(QN_NICK);
+ state_serializer_->Parse(state_elem, state_out);
+ return true;
+ }
+
+ virtual bool StatesEqual(const C& state1, const C& state2) {
+ return state1 == state2;
+ }
+
+ PubSubClient* client() { return client_; }
+ const QName& state_name() { return state_name_; }
+
+ private:
+ void OnItems(PubSubClient* pub_sub_client,
+ const std::vector<PubSubItem>& items) {
+ for (std::vector<PubSubItem>::const_iterator item = items.begin();
+ item != items.end(); ++item) {
+ OnItem(*item);
+ }
+ }
+
+ void OnItem(const PubSubItem& item) {
+ const std::string& itemid = item.itemid;
+ StateItemInfo info;
+ C new_state;
+
+ bool retracted = !ParseStateItem(item, &info, &new_state);
+ if (retracted) {
+ bool known_itemid =
+ (info_by_itemid_.find(itemid) != info_by_itemid_.end());
+ if (!known_itemid) {
+ // Nothing to retract, and nothing to publish.
+ // Probably a different state type.
+ return;
+ } else {
+ info = info_by_itemid_[itemid];
+ info_by_itemid_.erase(itemid);
+ new_state = default_state_;
+ }
+ } else {
+ // TODO: Assert new key matches the known key. It
+ // shouldn't change!
+ info_by_itemid_[itemid] = info;
+ }
+
+ std::string key = key_serializer_->GetKey(
+ info.publisher_nick, info.published_nick);
+ bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
+ C old_state = has_old_state ? state_by_key_[key] : default_state_;
+ if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
+ // Nothing change, so don't bother signalling.
+ return;
+ }
+
+ if (retracted || StatesEqual(new_state, default_state_)) {
+ // We treat a default state similar to a retract.
+ state_by_key_.erase(key);
+ } else {
+ state_by_key_[key] = new_state;
+ }
+
+ PubSubStateChange<C> change;
+ if (!retracted) {
+ // Retracts do not have publisher information.
+ change.publisher_nick = info.publisher_nick;
+ }
+ change.published_nick = info.published_nick;
+ change.old_state = old_state;
+ change.new_state = new_state;
+ SignalStateChange(change);
+ }
+
+ void OnPublishResult(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const XmlElement* item) {
+ SignalPublishResult(task_id, item);
+ }
+
+ void OnPublishError(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const buzz::XmlElement* item,
+ const buzz::XmlElement* stanza) {
+ SignalPublishError(task_id, item, stanza);
+ }
+
+ void OnRetractResult(PubSubClient* pub_sub_client,
+ const std::string& task_id) {
+ // There's no point in differentiating between publish and retract
+ // errors, so we simplify by making them both signal a publish
+ // result.
+ const XmlElement* item = NULL;
+ SignalPublishResult(task_id, item);
+ }
+
+ void OnRetractError(PubSubClient* pub_sub_client,
+ const std::string& task_id,
+ const buzz::XmlElement* stanza) {
+ // There's no point in differentiating between publish and retract
+ // errors, so we simplify by making them both signal a publish
+ // error.
+ const XmlElement* item = NULL;
+ SignalPublishError(task_id, item, stanza);
+ }
+
+ std::string publisher_nick_;
+ PubSubClient* client_;
+ const QName state_name_;
+ C default_state_;
+ std::unique_ptr<PubSubStateKeySerializer> key_serializer_;
+ std::unique_ptr<PubSubStateSerializer<C> > state_serializer_;
+ // key => state
+ std::map<std::string, C> state_by_key_;
+ // itemid => StateItemInfo
+ std::map<std::string, StateItemInfo> info_by_itemid_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
+};
+} // namespace buzz
+
+#endif // WEBRTC_LIBJINGLE_XMPP_PUBSUBSTATECLIENT_H_
« 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