From 57944a06948360607db8279b945b9a42059ff512 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 6 Jan 2016 20:35:27 +1100 Subject: [PATCH] PERF: only subscribe to a topic once for polls in the past as views were created and destroyed poll subscriptions would change this caused a lot of load on messaging bus and uneeded traffic --- .../javascripts/controllers/poll.js.es6 | 2 +- .../initializers/extend-for-poll.js.es6 | 61 +++++++++++++------ plugins/poll/plugin.rb | 12 ++-- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/plugins/poll/assets/javascripts/controllers/poll.js.es6 b/plugins/poll/assets/javascripts/controllers/poll.js.es6 index 1a9c3943d34..576bf7433c0 100644 --- a/plugins/poll/assets/javascripts/controllers/poll.js.es6 +++ b/plugins/poll/assets/javascripts/controllers/poll.js.es6 @@ -15,7 +15,7 @@ export default Ember.Controller.extend({ showResultsDisabled: Em.computed.equal("poll.voters", 0), hideResultsDisabled: Em.computed.or("isClosed", "post.topic.closed", "post.topic.archived"), - @computed("model", "vote") + @computed("model", "vote", "model.voters", "model.options", "model.status") poll(poll, vote) { if (poll) { const options = _.map(poll.get("options"), o => Em.Object.create(o)); diff --git a/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 b/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 index 2e086fbc5ec..f96da54dd7c 100644 --- a/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 +++ b/plugins/poll/assets/javascripts/initializers/extend-for-poll.js.es6 @@ -1,4 +1,7 @@ import PostView from "discourse/views/post"; +import TopicController from "discourse/controllers/topic"; +import Post from "discourse/models/post"; + import { on } from "ember-addons/ember-computed-decorators"; function createPollView(container, post, poll, vote) { @@ -6,7 +9,7 @@ function createPollView(container, post, poll, vote) { view = container.lookup("view:poll"); controller.set("vote", vote); - controller.setProperties({ model: Em.Object.create(poll), post }); + controller.setProperties({ model: poll, post }); view.set("controller", controller); return view; @@ -17,13 +20,39 @@ export default { initialize(container) { - const messageBus = container.lookup("message-bus:main"); + Post.reopen({ + // we need a proper ember object so it is bindable + pollsChanged: function(){ + const polls = this.get("polls"); + if (polls) { + this._polls = this._polls || {}; + _.map(polls, (v,k) => { + const existing = this._polls[k]; + if (existing) { + this._polls[k].setProperties(v); + } else { + this._polls[k] = Em.Object.create(v); + } + }); + this.set("pollsObject", this._polls); + } + }.observes("polls") + }); - // listen for back-end to tell us when a post has a poll - messageBus.subscribe("/polls", data => { - const post = container.lookup("controller:topic").get('model.postStream').findLoadedPost(data.post_id); - // HACK to trigger the "postViewUpdated" event - Em.run.next(() => post.set("cooked", post.get("cooked") + " ")); + TopicController.reopen({ + subscribe(){ + this._super(); + this.messageBus.subscribe("/polls/" + this.get("model.id"), msg => { + const post = this.get('model.postStream').findLoadedPost(msg.post_id); + if (post) { + post.set('polls', msg.polls); + } + }); + }, + unsubscribe(){ + this.messageBus.unsubscribe('/polls/*'); + this._super(); + } }); // overwrite polls @@ -32,12 +61,16 @@ export default { @on("postViewInserted", "postViewUpdated") _createPollViews($post) { const post = this.get("post"), - polls = post.get("polls"), votes = post.get("polls_votes") || {}; + post.pollsChanged(); + const polls = post.get("pollsObject"); + // don't even bother when there's no poll if (!polls) { return; } + // TODO inject cleanly into + // clean-up if needed this._cleanUpPollViews(); @@ -55,23 +88,11 @@ export default { pollViews[pollName] = pollView; }); - messageBus.subscribe(`/polls/${this.get("post.id")}`, results => { - if (results && results.polls) { - _.forEach(results.polls, poll => { - if (pollViews[poll.name]) { - pollViews[poll.name].get("controller").set("model", Em.Object.create(poll)); - } - }); - } - }); - this.set("pollViews", pollViews); }, @on("willClearRender") _cleanUpPollViews() { - messageBus.unsubscribe(`/polls/${this.get("post.id")}`); - if (this.get("pollViews")) { _.forEach(this.get("pollViews"), v => v.destroy()); } diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index 18306e86cc7..45fb14e630f 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -81,7 +81,7 @@ after_initialize do post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"] ||= {} post.custom_fields[VOTES_CUSTOM_FIELD]["#{user_id}"][poll_name] = options - post.custom_fields[VOTES_CUSTOM_FIELD].each do |user_id, user_votes| + post.custom_fields[VOTES_CUSTOM_FIELD].each do |_, user_votes| next unless votes = user_votes[poll_name] votes.each { |option| all_options[option] += 1 } poll["voters"] += 1 if (available_options & votes.to_set).size > 0 @@ -92,7 +92,7 @@ after_initialize do post.custom_fields[POLLS_CUSTOM_FIELD] = polls post.save_custom_fields(true) - MessageBus.publish("/polls/#{post_id}", { polls: polls }) + MessageBus.publish("/polls/#{post.topic_id}", { post_id: post_id, polls: polls }) return [poll, options] end @@ -128,7 +128,7 @@ after_initialize do post.save_custom_fields(true) - MessageBus.publish("/polls/#{post_id}", { polls: polls }) + MessageBus.publish("/polls/#{post.topic_id}", {post_id: post.id, polls: polls }) polls[poll_name] end @@ -350,7 +350,7 @@ after_initialize do post.save_custom_fields(true) # publish the changes - MessageBus.publish("/polls/#{post.id}", { polls: polls }) + MessageBus.publish("/polls/#{post.topic_id}", { post_id: post.id, polls: polls }) end end else @@ -370,7 +370,9 @@ after_initialize do # tells the front-end we have a poll for that post on(:post_created) do |post| next if post.is_first_post? || post.custom_fields[POLLS_CUSTOM_FIELD].blank? - MessageBus.publish("/polls", { post_id: post.id }) + MessageBus.publish("/polls/#{post.topic_id}", { + post_id: post.id, + polls: post.custom_fields[POLLS_CUSTOM_FIELD]}) end add_to_serializer(:post, :polls, false) { post_custom_fields[POLLS_CUSTOM_FIELD] }