Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates roster encoding for MIX channel. #87

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

tarun018
Copy link
Contributor

@tarun018 tarun018 commented Aug 4, 2017

Change-Id: Idb9683f45734ac58daa58736fe199dc014b9352a

Copy link
Collaborator

@tfar tfar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks okay for the parts that are provided. Would be great to have unit and integration tests that check that an account supports MIX and checks that on join of a MIX it's added to the roster.

@@ -58,6 +59,8 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender);
discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider());

mixRegistry = new MIXRegistry(roster);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably only allocate this if the account supports MIX.

@@ -191,6 +196,7 @@ namespace Swift {
PresenceOracle* presenceOracle;
DirectedPresenceSender* directedPresenceSender;
StanzaChannelPresenceSender* stanzaChannelPresenceSender;
MIXRegistry* mixRegistry;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialise with nullptr or better, keep as unique_ptr.

@@ -41,12 +41,16 @@ namespace Swift {
unknownContent_ += c;
}

void setChannel() { isChannel_ = true; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have a bool parameter.

class SWIFTEN_API MIXRegistry {
public:
MIXRegistry(XMPPRoster* xmppRoster);
virtual ~MIXRegistry();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No virtual method otherwise, so doesn't need a virtual d-tor.

@@ -74,6 +75,9 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
jingleSessionManager = new JingleSessionManager(getIQRouter());
blockListManager = new ClientBlockListManager(getIQRouter());

mixSupport = false;
requestFeatures();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should called when the client went online, not in the constructor.

@@ -74,6 +75,9 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
jingleSessionManager = new JingleSessionManager(getIQRouter());
blockListManager = new ClientBlockListManager(getIQRouter());

mixSupport = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This boolean is redundant, not? If MIX is supported, mixRegistry will be initialised. If not, it will not be initialised.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just used this as a bool to pass to requestRoster. However it is still redundant.

public:
boost::signals2::signal<void (const JID& /* joinedChannel */)> onChannelJoined;
boost::signals2::signal<void (ErrorPayload::ref /* joinResponse */)> onChannelJoinFailed;
boost::signals2::signal<void (const JID& /* leavedChannel */)> onChannelLeaved;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be onChannelLeft.

}
}

std::unordered_set<std::string> MIXRegistry::getJoinedChannels() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. If I read https://xmpp.org/extensions/xep-0369.html#usecase-roster-management correctly the roster only contains joined channels. So getChannels sounds like a better name.
  2. Shouldn't it return JIDs rather than strings?
  3. It should return a list of all channels in the roster.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update it to return JID rather than strings. As soon as a JID is added, the handler will check if it is a channel and add it to the map. So it will always return list of channels in the roster.

return results;
}

MIX::ref MIXRegistry::getMIXInstance(const JID& channelJID) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should return a MIXImpl instance for the channel JID, if and only if it is joined, so it is in the roster.

IQRouter* iqRouter_;
XMPPRoster* xmppRoster_;
bool rosterPopulated_;
typedef std::map<JID, MIX::ref> MIXInstanceMap;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this typedef? If it's really needed, it should probably be a using instead.

XMPPRoster* xmppRoster_;
bool rosterPopulated_;
typedef std::map<JID, MIX::ref> MIXInstanceMap;
MIXInstanceMap entries_;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably map JID to weak_ptr. The idea I'd think is:

  1. You create your Client instance and go online with it.
  2. Ask the MIXRegistry for the channels.
  3. Call MIXRegistry::getMIX(channelJID) to get a shared_ptr<MIX>. MIXRegistry holds a weak_ptr to it so it can hand out the same if another part of the app asks for the same channel.
  4. If the user doesn't need the channel info anymore, it can get rid of its shared_ptr and the MIX instance is freed.

What do you think @intosi ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that works, does it? I'd expect this to be a shared_ptr, or unique_ptr, personally. I'd consider the MIXRegistry to own all the channel objects.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have hundreds of MIX channels in your roster you probably don't want hundreds of MIX instances allocated all the time, right?


}

void MIXRegistry::joinChannel(const JID& channelJID, const std::unordered_set<std::string>& nodes) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably check if a channel with channelJID is already on the roster and log a warning instead of issuing a join.

@@ -148,13 +154,27 @@ void Client::handleConnected() {
discoManager->handleConnected();
}

void Client::requestFeatures() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this happening automatically is consistent with the design elsewhere, where network traffic isn't generally generated without being requested. It might be sensible, but it's not plugged in anywhere else, which means it's going to end up duplicated by the current disco logic in Swift isn't it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Currently it would be duplicated.

void Client::handleFeaturesReceived(DiscoInfo::ref payload, ErrorPayload::ref /*error*/) {
if (payload && payload->hasFeature(DiscoInfo::MIXFeature)) {
mixSupport = true;
mixRegistry = std::make_unique<MIXRegistry>(getJID(), getIQRouter(), getRoster());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always having a mixRegistry, but it being empty when not supported, probably makes more sense, doesn't it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Already mentioned it in #87 (comment) .

@@ -7,6 +7,8 @@
#pragma once

#include <Swiften/Base/API.h>
#include <Swiften/Elements/DiscoInfo.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the include ordering please.

@@ -41,12 +41,16 @@ namespace Swift {
unknownContent_ += c;
}

void setChannel(bool isChannel) { isChannel_ = isChannel; }
bool getChannel() const { return isChannel_; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually name bools like this isX, rather than getX. Also, does it make sense to explicitly call it a MIXChannel, rather than Channel, to avoid ambiguity with other channels?


void MIXRegistry::handleJIDAdded(const JID& jid) {
if (rosterPopulated_ && xmppRoster_->isChannel(jid)) {
std::map<JID, MIX::ref>::iterator i = entries_.find(jid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not auto?

}
}

std::unordered_set<std::string> MIXRegistry::getJoinedChannels() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't you expect this to return a list of the channel objects, rather than their JIDs?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on whether you always want to have the objects in memory even when you don't need them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd have expected that, if you request the mix bits of the roster, it'd then sort it all out for you populate them and you'd then use them. Is that not the likely use case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are joined to 100 MIX channels but are currently not interested in the messages as you are on mobile or so, you probably don't want to allocate 100 MIXImpl instances. This way a MIXController could ask for the MIX shared_ptr it needs for its channel which is then created for it on demand. Allocating memory for stuff that isn't really used ultimately leads to bloated applications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless MIXImpls are much bigger than I think they should be, this doesn't seem like a particularly big issue - 100 MIXs worth of messages you're not interested in seems likely to be a bigger issue (which needs sorting out with protocol).
OK, I'll go along with JIDs here for the moment as it's relatively easy to change later.


void joinChannel(const JID& channelJID, const std::unordered_set<std::string>& nodes);

void leaveChannel(const JID& channelJID);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is leave being on the registry or on the object itself more sensible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say if registry is handling the join and keeping track of joined channels, leave should also be here as successfully leaving a channel depends on (onJIDRemoved).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely convinced, but not a hill for me to die on.

XMPPRoster* xmppRoster_;
bool rosterPopulated_;
typedef std::map<JID, MIX::ref> MIXInstanceMap;
MIXInstanceMap entries_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that works, does it? I'd expect this to be a shared_ptr, or unique_ptr, personally. I'd consider the MIXRegistry to own all the channel objects.

@@ -52,11 +52,15 @@ void RosterParser::handleStartElement(const std::string& element, const std::str
if (attributes.getAttribute("ask") == "subscribe") {
currentItem_.setSubscriptionRequested();
}
} else if (element == "annotate" && ns == "urn:xmpp:mix:roster:0") {
getPayloadInternal()->setAnnotate(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is MIX-specific, shouldn't it be obvious from the method name? setSupportsMIX or setSupportsMIXAnnotations or something?

}

void MIXRegistry::handleJIDRemoved(const JID& jid) {
if (rosterPopulated_ && xmppRoster_->isChannel(jid)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't isChannel always be false at this point, because it's been removed from the roster?

@tfar
Copy link
Collaborator

tfar commented Aug 7, 2017

@Kev suggested adding bool includeMIX = false to Client::requestRoster and do away with automatic feature discovery. Client::getMIXRegistry() should always return a registry. Feature discovery on whether an account supports MIX or not is supposed to happen by the user of Client.

Update roster encoding for MIX channel
Update roster parser and serializer

License:
This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.

Test-Information:
Added tests for joining and leaving channels via MIXRegistry, which passes.
Tested on Ubuntu 16.04 LTS.

Change-Id: Idb9683f45734ac58daa58736fe199dc014b9352a
@tarun018
Copy link
Contributor Author

tarun018 commented Aug 9, 2017

Updated based on feedback with unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants