about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2016-08-18 15:49:51 +0200
committerEugen Rochko <eugen@zeonfederated.com>2016-08-18 15:49:51 +0200
commit6deb9f966eb9a280cc16428ba9324ffc15ea60a8 (patch)
treeec3574856544cad4766a6bb93905089d8086db0a /app
parent10ba09f5466fe3d34a5ed78202c35f4e4f9d30e6 (diff)
Live timelines using ActionCable
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/api/accounts.coffee3
-rw-r--r--app/assets/javascripts/api/accounts/lookup.coffee3
-rw-r--r--app/assets/javascripts/api/follows.coffee3
-rw-r--r--app/assets/javascripts/api/statuses.coffee3
-rw-r--r--app/assets/javascripts/application.js1
-rw-r--r--app/assets/javascripts/cable.js13
-rw-r--r--app/assets/javascripts/channels/timeline.js13
-rw-r--r--app/assets/javascripts/oauth/applications.coffee3
-rw-r--r--app/assets/javascripts/profiler.coffee5
-rw-r--r--app/assets/javascripts/settings.coffee3
-rw-r--r--app/assets/javascripts/statuses.coffee3
-rw-r--r--app/channels/application_cable/channel.rb5
-rw-r--r--app/channels/application_cable/connection.rb20
-rw-r--r--app/channels/timeline_channel.rb10
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/services/fan_out_on_write_service.rb35
-rw-r--r--app/services/precompute_feed_service.rb2
17 files changed, 88 insertions, 39 deletions
diff --git a/app/assets/javascripts/api/accounts.coffee b/app/assets/javascripts/api/accounts.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/api/accounts.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/api/accounts/lookup.coffee b/app/assets/javascripts/api/accounts/lookup.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/api/accounts/lookup.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/api/follows.coffee b/app/assets/javascripts/api/follows.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/api/follows.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/api/statuses.coffee b/app/assets/javascripts/api/statuses.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/api/statuses.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index e07c5a830..646c5aba4 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -12,5 +12,4 @@
 //
 //= require jquery
 //= require jquery_ujs
-//= require turbolinks
 //= require_tree .
diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js
new file mode 100644
index 000000000..71ee1e66d
--- /dev/null
+++ b/app/assets/javascripts/cable.js
@@ -0,0 +1,13 @@
+// Action Cable provides the framework to deal with WebSockets in Rails.
+// You can generate new channels where WebSocket features live using the rails generate channel command.
+//
+//= require action_cable
+//= require_self
+//= require_tree ./channels
+
+(function() {
+  this.App || (this.App = {});
+
+  App.cable = ActionCable.createConsumer();
+
+}).call(this);
diff --git a/app/assets/javascripts/channels/timeline.js b/app/assets/javascripts/channels/timeline.js
new file mode 100644
index 000000000..ca7c50d12
--- /dev/null
+++ b/app/assets/javascripts/channels/timeline.js
@@ -0,0 +1,13 @@
+App.timeline = App.cable.subscriptions.create("TimelineChannel", {
+  connected: function() {
+    console.log('Connected');
+  },
+
+  disconnected: function() {
+    console.log('Disconnected');
+  },
+
+  received: function(data) {
+    console.log(JSON.parse(data.message));
+  }
+});
diff --git a/app/assets/javascripts/oauth/applications.coffee b/app/assets/javascripts/oauth/applications.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/oauth/applications.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/profiler.coffee b/app/assets/javascripts/profiler.coffee
deleted file mode 100644
index 40dfd0af6..000000000
--- a/app/assets/javascripts/profiler.coffee
+++ /dev/null
@@ -1,5 +0,0 @@
-$ ->
-  $(document).on 'turbolinks:load', ->
-    unless typeof window.MiniProfiler == 'undefined'
-      window.MiniProfiler.init()
-      window.MiniProfiler.pageTransition()
diff --git a/app/assets/javascripts/settings.coffee b/app/assets/javascripts/settings.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/settings.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/statuses.coffee b/app/assets/javascripts/statuses.coffee
deleted file mode 100644
index 24f83d18b..000000000
--- a/app/assets/javascripts/statuses.coffee
+++ /dev/null
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
new file mode 100644
index 000000000..d56fa30f4
--- /dev/null
+++ b/app/channels/application_cable/channel.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
+module ApplicationCable
+  class Channel < ActionCable::Channel::Base
+  end
+end
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
new file mode 100644
index 000000000..f7cbe5485
--- /dev/null
+++ b/app/channels/application_cable/connection.rb
@@ -0,0 +1,20 @@
+# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
+module ApplicationCable
+  class Connection < ActionCable::Connection::Base
+    identified_by :current_user
+
+    def connect
+      self.current_user = find_verified_user
+    end
+
+    protected
+
+    def find_verified_user
+      if verified_user = env['warden'].user
+        verified_user
+      else
+        reject_unauthorized_connection
+      end
+    end
+  end
+end
diff --git a/app/channels/timeline_channel.rb b/app/channels/timeline_channel.rb
new file mode 100644
index 000000000..c128fae58
--- /dev/null
+++ b/app/channels/timeline_channel.rb
@@ -0,0 +1,10 @@
+# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
+class TimelineChannel < ApplicationCable::Channel
+  def subscribed
+    stream_from "timeline:#{current_user.id}"
+  end
+
+  def unsubscribed
+    # Any cleanup needed when channel is unsubscribed
+  end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index d5eaecdb1..f90628b0d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
 
   # Profiling
   before_action do
-    if current_user && current_user.admin?
+    if (current_user && current_user.admin?) || Rails.env == 'development'
       Rack::MiniProfiler.authorize_request
     end
   end
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index c8c775b93..34684a06f 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -10,13 +10,13 @@ class FanOutOnWriteService < BaseService
   private
 
   def deliver_to_self(status)
-    push(:home, status.account.id, status)
+    push(:home, status.account, status)
   end
 
   def deliver_to_followers(status)
     status.account.followers.each do |follower|
       next if !follower.local? || FeedManager.filter_status?(status, follower)
-      push(:home, follower.id, status)
+      push(:home, follower, status)
     end
   end
 
@@ -24,23 +24,38 @@ class FanOutOnWriteService < BaseService
     status.mentions.each do |mention|
       mentioned_account = mention.account
       next unless mentioned_account.local?
-      push(:mentions, mentioned_account.id, status)
+      push(:mentions, mentioned_account, status)
     end
   end
 
-  def push(type, receiver_id, status)
-    redis.zadd(FeedManager.key(type, receiver_id), status.id, status.id)
-    trim(type, receiver_id)
+  def push(type, receiver, status)
+    redis.zadd(FeedManager.key(type, receiver.id), status.id, status.id)
+    trim(type, receiver)
+    ActionCable.server.broadcast("timeline:#{receiver.id}", message: inline_render(receiver, status))
   end
 
-  def trim(type, receiver_id)
-    return unless redis.zcard(FeedManager.key(type, receiver_id)) > FeedManager::MAX_ITEMS
+  def trim(type, receiver)
+    return unless redis.zcard(FeedManager.key(type, receiver.id)) > FeedManager::MAX_ITEMS
 
-    last = redis.zrevrange(FeedManager.key(type, receiver_id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1)
-    redis.zremrangebyscore(FeedManager.key(type, receiver_id), '-inf', "(#{last.last}")
+    last = redis.zrevrange(FeedManager.key(type, receiver.id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1)
+    redis.zremrangebyscore(FeedManager.key(type, receiver.id), '-inf', "(#{last.last}")
   end
 
   def redis
     $redis
   end
+
+  def inline_render(receiver, status)
+    rabl_scope = Class.new(BaseService) do
+      def initialize(account)
+        @account = account
+      end
+
+      def current_user
+        @account.user
+      end
+    end
+
+    Rabl::Renderer.new('api/statuses/show', status,  view_path: 'app/views', format: :json, scope: rabl_scope.new(receiver)).render
+  end
 end
diff --git a/app/services/precompute_feed_service.rb b/app/services/precompute_feed_service.rb
index de4201a8f..c8050bbd0 100644
--- a/app/services/precompute_feed_service.rb
+++ b/app/services/precompute_feed_service.rb
@@ -8,7 +8,7 @@ class PrecomputeFeedService < BaseService
 
     Status.send("as_#{type}_timeline", account).order('created_at desc').limit(FeedManager::MAX_ITEMS).each do |status|
       next if type == :home && FeedManager.filter_status?(status, account)
-      redis.zadd(FeedManager.key(type, receiver_id), status.id, status.id)
+      redis.zadd(FeedManager.key(type, account.id), status.id, status.id)
       instant_return << status unless instant_return.size > limit
     end