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

Websockets - check for subscriptions before proceeding #1906

Conversation

guilhermelawless
Copy link
Contributor

If the websocket server is active via config but there are no active subscriptions, currently the observer will still create and try to broadcast the block confirmation message.

A simple check would have been to go through all sessions and check if any topics are subscribed. However, since this would be done every time a new block arrives, I have added a map topic -> subscription count in the listener to do this lookup in constant time. I'm open to suggestions as I am not sure what the right pattern would be here.

Small test added for this as well.

Copy link
Contributor

@cryptocode cryptocode left a comment

Choose a reason for hiding this comment

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

Broadcasting is essentially free if there are no sessions. For the case where there are sessions: if you open up websockets to potentially malicious clients, they'd probably subscribe since that's more severe than connecting and not subscribing.

I can see the need for something like this if we get a lot more topics. Is the added complexity worth it for the current confirmation topic / do you think it solves a problem now? The only scenario I can think of is applications connecting but only occasionally listening to confirmations, but not sure what the use case would be.

@guilhermelawless
Copy link
Contributor Author

guilhermelawless commented Apr 14, 2019

@cryptocode it was definitely with the case of different subscriptions in mind. In that case this becomes crucial.

Most likely anyone with websocket enabled will be connecting to it, but maybe not always? I will have something that I will connect only occasionally to gather information about votes/blocks, so it wouldn't make sense to always go through the message building process if that is not currently connected.

The added complexity is to avoid the following for every block:

if (this->block_arrival.recent (block_a->hash ()))
{
	std::string subtype;
	if (is_state_send_a)
	{
		subtype = "send";
	}
	else if (block_a->type () == nano::block_type::state)
	{
		if (block_a->link ().is_zero ())
		{
			subtype = "change";
		}
		else if (amount_a == 0 && !this->ledger.epoch_link.is_zero () && this->ledger.is_epoch_link (block_a->link ()))
		{
			subtype = "epoch";
		}
		else
		{
			subtype = "receive";
		}
	}
	nano::websocket::message_builder builder;
	auto msg (builder.block_confirmed (block_a, account_a, amount_a, subtype));
	this->websocket_server->broadcast (msg);
}

If we have other subscription types in the future, their processing might be more resource heavy so it should be avoided.

@cryptocode
Copy link
Contributor

@guilhermelawless makes sense, I think we should add this.

@cryptocode cryptocode added this to the V19.0 milestone Apr 14, 2019
std::vector<std::weak_ptr<session>> sessions;
std::unordered_map<topic, std::size_t> topic_subscription_count;
Copy link
Contributor

@clemahieu clemahieu Apr 14, 2019

Choose a reason for hiding this comment

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

Since the number of topics is small, this could be an array indexed by the enum value.

Copy link
Contributor

@cryptocode cryptocode Apr 14, 2019

Choose a reason for hiding this comment

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

Doing so would also fix the CI build error (missing hash specialization for the enum class I think, required on some compilers)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, also could change to atomic size_t and thus remove the mutex. Getting the length of the enum is cumbersome.

@clemahieu
Copy link
Contributor

clemahieu commented Apr 15, 2019

You should be able to size an enum by creating a value at the end called something like topic_count which doesn’t represent an actual topic.

@guilhermelawless
Copy link
Contributor Author

Ok that's how I did it in 9e8471f

@cryptocode cryptocode merged commit ac89b64 into nanocurrency:master Apr 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants