render_sync 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +153 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +521 -0
- data/Rakefile +9 -0
- data/app/assets/javascripts/sync.coffee +355 -0
- data/app/controllers/sync/refetches_controller.rb +56 -0
- data/app/helpers/render_sync/config_helper.rb +15 -0
- data/config/routes.rb +3 -0
- data/config/sync.yml +21 -0
- data/lib/generators/render_sync/install_generator.rb +14 -0
- data/lib/generators/render_sync/templates/sync.ru +14 -0
- data/lib/generators/render_sync/templates/sync.yml +34 -0
- data/lib/render_sync.rb +174 -0
- data/lib/render_sync/action.rb +39 -0
- data/lib/render_sync/actions.rb +114 -0
- data/lib/render_sync/channel.rb +23 -0
- data/lib/render_sync/clients/dummy.rb +22 -0
- data/lib/render_sync/clients/faye.rb +104 -0
- data/lib/render_sync/clients/pusher.rb +77 -0
- data/lib/render_sync/controller_helpers.rb +33 -0
- data/lib/render_sync/engine.rb +24 -0
- data/lib/render_sync/erb_tracker.rb +49 -0
- data/lib/render_sync/faye_extension.rb +45 -0
- data/lib/render_sync/model.rb +174 -0
- data/lib/render_sync/model_actions.rb +60 -0
- data/lib/render_sync/model_change_tracking.rb +97 -0
- data/lib/render_sync/model_syncing.rb +65 -0
- data/lib/render_sync/model_touching.rb +35 -0
- data/lib/render_sync/partial.rb +112 -0
- data/lib/render_sync/partial_creator.rb +47 -0
- data/lib/render_sync/reactor.rb +48 -0
- data/lib/render_sync/refetch_model.rb +21 -0
- data/lib/render_sync/refetch_partial.rb +43 -0
- data/lib/render_sync/refetch_partial_creator.rb +21 -0
- data/lib/render_sync/renderer.rb +19 -0
- data/lib/render_sync/resource.rb +115 -0
- data/lib/render_sync/scope.rb +113 -0
- data/lib/render_sync/scope_definition.rb +30 -0
- data/lib/render_sync/view_helpers.rb +106 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/sync/users/_show.html.erb +1 -0
- data/test/dummy/app/views/sync/users/refetch/_show.html.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +22 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +8 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/log/test.log +626 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/em_minitest_spec.rb +100 -0
- data/test/fixtures/sync_auth_token_missing.yml +6 -0
- data/test/fixtures/sync_erb.yml +7 -0
- data/test/fixtures/sync_faye.yml +7 -0
- data/test/fixtures/sync_pusher.yml +8 -0
- data/test/models/group.rb +3 -0
- data/test/models/project.rb +2 -0
- data/test/models/todo.rb +8 -0
- data/test/models/user.rb +82 -0
- data/test/sync/abstract_controller.rb +3 -0
- data/test/sync/action_test.rb +82 -0
- data/test/sync/channel_test.rb +15 -0
- data/test/sync/config_test.rb +25 -0
- data/test/sync/erb_tracker_test.rb +72 -0
- data/test/sync/faye_extension_test.rb +87 -0
- data/test/sync/message_test.rb +159 -0
- data/test/sync/model_test.rb +315 -0
- data/test/sync/partial_creator_test.rb +35 -0
- data/test/sync/partial_test.rb +107 -0
- data/test/sync/protected_attributes_test.rb +39 -0
- data/test/sync/reactor_test.rb +18 -0
- data/test/sync/refetch_model_test.rb +26 -0
- data/test/sync/refetch_partial_creator_test.rb +16 -0
- data/test/sync/refetch_partial_test.rb +74 -0
- data/test/sync/renderer_test.rb +19 -0
- data/test/sync/resource_test.rb +181 -0
- data/test/sync/scope_definition_test.rb +39 -0
- data/test/sync/scope_test.rb +113 -0
- data/test/test_helper.rb +66 -0
- data/test/travis/sync.ru +14 -0
- data/test/travis/sync.yml +21 -0
- metadata +317 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module RenderSync
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
def self.source_root
|
5
|
+
File.dirname(__FILE__) + "/templates"
|
6
|
+
end
|
7
|
+
|
8
|
+
def copy_files
|
9
|
+
template "sync.yml", "config/sync.yml"
|
10
|
+
copy_file "sync.ru", "sync.ru"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Run with: rackup sync.ru -E production
|
2
|
+
require "bundler/setup"
|
3
|
+
require "yaml"
|
4
|
+
require "faye"
|
5
|
+
require "render_sync"
|
6
|
+
|
7
|
+
Faye::WebSocket.load_adapter 'thin'
|
8
|
+
|
9
|
+
RenderSync.load_config(
|
10
|
+
File.expand_path("../config/sync.yml", __FILE__),
|
11
|
+
ENV["RAILS_ENV"] || "development"
|
12
|
+
)
|
13
|
+
|
14
|
+
run RenderSync.pubsub_app
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Faye
|
2
|
+
development:
|
3
|
+
server: "http://localhost:9292/faye"
|
4
|
+
adapter_javascript_url: "http://localhost:9292/faye/faye.js"
|
5
|
+
auth_token: DEVELOPMENT_SECRET_TOKEN
|
6
|
+
adapter: "Faye"
|
7
|
+
async: true
|
8
|
+
|
9
|
+
# Pusher
|
10
|
+
# development:
|
11
|
+
# adapter_javascript_url: "http://js.pusher.com/2.0/pusher.min.js"
|
12
|
+
# app_id: "YOUR_PUSHER_APP_ID"
|
13
|
+
# api_key: "YOUR_PUSHER_API_KEY"
|
14
|
+
# auth_token: "YOUR_PUSHER_SECRET"
|
15
|
+
# adapter: "Pusher"
|
16
|
+
# async: true
|
17
|
+
|
18
|
+
# Disabled
|
19
|
+
# development:
|
20
|
+
# adapter: false
|
21
|
+
|
22
|
+
test:
|
23
|
+
server: "http://localhost:9292/faye"
|
24
|
+
adapter_javascript_url: "http://localhost:9292/faye/faye.js"
|
25
|
+
adapter: "Faye"
|
26
|
+
auth_token: "secret"
|
27
|
+
async: false
|
28
|
+
|
29
|
+
production:
|
30
|
+
server: "http://example.com/faye"
|
31
|
+
adapter_javascript_url: "http://localhost:9292/faye/faye.js"
|
32
|
+
adapter: "Faye"
|
33
|
+
auth_token: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
|
34
|
+
async: true
|
data/lib/render_sync.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'monitor'
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'erb'
|
5
|
+
require 'net/http'
|
6
|
+
require 'net/https'
|
7
|
+
require 'logger'
|
8
|
+
require 'render_sync/renderer'
|
9
|
+
require 'render_sync/actions'
|
10
|
+
require 'render_sync/action'
|
11
|
+
require 'render_sync/controller_helpers'
|
12
|
+
require 'render_sync/view_helpers'
|
13
|
+
require 'render_sync/model_change_tracking'
|
14
|
+
require 'render_sync/model_actions'
|
15
|
+
require 'render_sync/model_syncing'
|
16
|
+
require 'render_sync/model_touching'
|
17
|
+
require 'render_sync/model'
|
18
|
+
require 'render_sync/scope'
|
19
|
+
require 'render_sync/scope_definition'
|
20
|
+
require 'render_sync/refetch_model'
|
21
|
+
require 'render_sync/faye_extension'
|
22
|
+
require 'render_sync/partial_creator'
|
23
|
+
require 'render_sync/refetch_partial_creator'
|
24
|
+
require 'render_sync/partial'
|
25
|
+
require 'render_sync/refetch_partial'
|
26
|
+
require 'render_sync/channel'
|
27
|
+
require 'render_sync/resource'
|
28
|
+
require 'render_sync/clients/faye'
|
29
|
+
require 'render_sync/clients/pusher'
|
30
|
+
require 'render_sync/clients/dummy'
|
31
|
+
require 'render_sync/reactor'
|
32
|
+
if defined? Rails
|
33
|
+
require 'render_sync/erb_tracker'
|
34
|
+
require 'render_sync/engine'
|
35
|
+
end
|
36
|
+
|
37
|
+
module RenderSync
|
38
|
+
|
39
|
+
class << self
|
40
|
+
attr_accessor :config, :client, :logger
|
41
|
+
|
42
|
+
def config
|
43
|
+
@config || {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def config_json
|
47
|
+
@config_json ||= begin
|
48
|
+
{
|
49
|
+
server: server,
|
50
|
+
api_key: api_key,
|
51
|
+
pusher_ws_host: pusher_ws_host,
|
52
|
+
pusher_ws_port: pusher_ws_port,
|
53
|
+
pusher_wss_port: pusher_wss_port,
|
54
|
+
pusher_encrypted: pusher_encrypted,
|
55
|
+
adapter: adapter
|
56
|
+
}.reject { |k, v| v.nil? }.to_json
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Resets the configuration to the default (empty hash)
|
61
|
+
def reset_config
|
62
|
+
@config = {}
|
63
|
+
@config_json = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# Loads the configuration from a given YAML file and environment (such as production)
|
67
|
+
def load_config(filename, environment)
|
68
|
+
reset_config
|
69
|
+
yaml = YAML.load(ERB.new(File.read(filename)).result)[environment.to_s]
|
70
|
+
raise ArgumentError, "The #{environment} environment does not exist in #{filename}" if yaml.nil?
|
71
|
+
yaml.each{|key, value| config[key.to_sym] = value }
|
72
|
+
setup_logger
|
73
|
+
|
74
|
+
if adapter
|
75
|
+
setup_client
|
76
|
+
else
|
77
|
+
setup_dummy_client
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def setup_client
|
82
|
+
raise ArgumentError, "auth_token missing" if config[:auth_token].nil?
|
83
|
+
@client = RenderSync::Clients.const_get(adapter).new
|
84
|
+
@client.setup
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup_dummy_client
|
88
|
+
config[:auth_token] = 'dummy_auth_token'
|
89
|
+
@client = RenderSync::Clients::Dummy.new
|
90
|
+
end
|
91
|
+
|
92
|
+
def setup_logger
|
93
|
+
@logger = (defined?(Rails) && Rails.logger) ? Rails.logger : Logger.new(STDOUT)
|
94
|
+
end
|
95
|
+
|
96
|
+
def async?
|
97
|
+
config[:async]
|
98
|
+
end
|
99
|
+
|
100
|
+
def server
|
101
|
+
config[:server]
|
102
|
+
end
|
103
|
+
|
104
|
+
def adapter_javascript_url
|
105
|
+
config[:adapter_javascript_url]
|
106
|
+
end
|
107
|
+
|
108
|
+
def auth_token
|
109
|
+
config[:auth_token]
|
110
|
+
end
|
111
|
+
|
112
|
+
def adapter
|
113
|
+
config[:adapter]
|
114
|
+
end
|
115
|
+
|
116
|
+
def app_id
|
117
|
+
config[:app_id]
|
118
|
+
end
|
119
|
+
|
120
|
+
def api_key
|
121
|
+
config[:api_key]
|
122
|
+
end
|
123
|
+
|
124
|
+
def pusher_api_scheme
|
125
|
+
config[:pusher_api_scheme]
|
126
|
+
end
|
127
|
+
|
128
|
+
def pusher_api_host
|
129
|
+
config[:pusher_api_host]
|
130
|
+
end
|
131
|
+
|
132
|
+
def pusher_api_port
|
133
|
+
config[:pusher_api_port]
|
134
|
+
end
|
135
|
+
|
136
|
+
def pusher_ws_host
|
137
|
+
config[:pusher_ws_host]
|
138
|
+
end
|
139
|
+
|
140
|
+
def pusher_ws_port
|
141
|
+
config[:pusher_ws_port]
|
142
|
+
end
|
143
|
+
|
144
|
+
def pusher_wss_port
|
145
|
+
config[:pusher_wss_port]
|
146
|
+
end
|
147
|
+
|
148
|
+
def pusher_encrypted
|
149
|
+
if config[:pusher_encrypted].nil?
|
150
|
+
true
|
151
|
+
else
|
152
|
+
config[:pusher_encrypted]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def reactor
|
157
|
+
@reactor ||= Reactor.new
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the Faye Rack application.
|
161
|
+
# Any options given are passed to the Faye::RackAdapter.
|
162
|
+
def pubsub_app(options = {})
|
163
|
+
Faye::RackAdapter.new({
|
164
|
+
mount: config[:mount] || "/faye",
|
165
|
+
timeout: config[:timeout] || 45,
|
166
|
+
extensions: [FayeExtension.new]
|
167
|
+
}.merge(options))
|
168
|
+
end
|
169
|
+
|
170
|
+
def views_root
|
171
|
+
Rails.root.join('app', 'views', 'sync')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RenderSync
|
2
|
+
class Action
|
3
|
+
include Actions
|
4
|
+
|
5
|
+
attr_accessor :record, :name, :scope
|
6
|
+
|
7
|
+
def initialize(record, name, *args)
|
8
|
+
options = args.extract_options!
|
9
|
+
@record = record
|
10
|
+
@name = name
|
11
|
+
@scope = get_scope_from_options(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def perform
|
15
|
+
case name
|
16
|
+
when :new
|
17
|
+
sync_new record, scope: scope
|
18
|
+
when :update
|
19
|
+
sync_update record, scope: scope
|
20
|
+
when :destroy
|
21
|
+
sync_destroy record, scope: scope
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Just for testing purposes (see test/sync/model_test.rb)
|
26
|
+
def test_path
|
27
|
+
Resource.new(record, scope).polymorphic_path.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Merge default_scope and scope from options Hash
|
33
|
+
# compact array to remove nil elements
|
34
|
+
def get_scope_from_options(options)
|
35
|
+
[options[:default_scope], options[:scope]].compact
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module RenderSync
|
2
|
+
module Actions
|
3
|
+
|
4
|
+
# Render all sync'd partials for resource to string and publish update action
|
5
|
+
# to pubsub server with rendered resource messages
|
6
|
+
#
|
7
|
+
# resource - The ActiveModel resource
|
8
|
+
# options - The Hash of options
|
9
|
+
# default_scope - The ActiveModel resource to scope the update channel to
|
10
|
+
# scope - Either a String, a symbol, an instance of ActiveModel or
|
11
|
+
# RenderSync::Scope or an Array containing a combination to scope
|
12
|
+
# the update channel to. Will be concatenated to an optional
|
13
|
+
# default_scope
|
14
|
+
#
|
15
|
+
def sync_update(resource, options = {})
|
16
|
+
sync resource, :update, options
|
17
|
+
end
|
18
|
+
|
19
|
+
# Render all sync'd partials for resource to string and publish destroy action
|
20
|
+
# to pubsub server with rendered resource messages
|
21
|
+
#
|
22
|
+
# resource - The ActiveModel resource
|
23
|
+
# options - The Hash of options
|
24
|
+
# default_scope - The ActiveModel resource to scope the update channel to
|
25
|
+
# scope - Either a String, a symbol, an instance of ActiveModel or
|
26
|
+
# RenderSync::Scope or an Array containing a combination to scope
|
27
|
+
# the destroy channel to. Will be concatenated to an optional
|
28
|
+
# default_scope
|
29
|
+
#
|
30
|
+
def sync_destroy(resource, options = {})
|
31
|
+
sync resource, :destroy, options
|
32
|
+
end
|
33
|
+
|
34
|
+
# Render all sync'd partials for resource to string and publish action
|
35
|
+
# to pubsub server with rendered resource messages
|
36
|
+
#
|
37
|
+
# resource - The ActiveModel resource
|
38
|
+
# action - The Symbol action to publish. One of :update, :destroy
|
39
|
+
# options - The Hash of options
|
40
|
+
# default_scope - The ActiveModel resource to scope the action channel to
|
41
|
+
# scope - Either a String, a symbol, an instance of ActiveModel or
|
42
|
+
# RenderSync::Scope or an Array containing a combination to scope
|
43
|
+
# the channel to. Will be concatenated to an optional default_scope
|
44
|
+
#
|
45
|
+
def sync(resource, action, options = {})
|
46
|
+
scope = options[:scope]
|
47
|
+
partial_name = options[:partial]
|
48
|
+
resources = [resource].flatten
|
49
|
+
messages = resources.collect do |resource|
|
50
|
+
if partial_name
|
51
|
+
specified_partials(resource, sync_render_context, partial_name).collect do |partial|
|
52
|
+
partial.message(action)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
all_partials(resource, sync_render_context, scope).collect do |partial|
|
56
|
+
partial.message(action)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
RenderSync.client.batch_publish(messages.flatten)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Render all sync'd partials for resource to string and publish
|
65
|
+
# new action to pubsub server with rendered resource messages
|
66
|
+
#
|
67
|
+
# resource - The ActiveModel resource, or Array of ActiveModel resources
|
68
|
+
# action - The Symbol action to publish. One of :update, :destroy
|
69
|
+
# options - The Hash of options
|
70
|
+
# default_scope - The ActiveModel resource to scope the new channel to
|
71
|
+
# scope - Either a String, a symbol, an instance of ActiveModel or
|
72
|
+
# RenderSync::Scope or an Array containing any combination to scope
|
73
|
+
# the new channel to. Will be concatenated to an optional
|
74
|
+
# default_scope
|
75
|
+
#
|
76
|
+
def sync_new(resource, options = {})
|
77
|
+
scope = options[:scope]
|
78
|
+
partial_name = options[:partial]
|
79
|
+
resources = [resource].flatten
|
80
|
+
messages = resources.collect do |resource|
|
81
|
+
if partial_name
|
82
|
+
specified_partials(resource, sync_render_context, partial_name).collect do |partial|
|
83
|
+
partial.creator_for_scope(scope).message
|
84
|
+
end
|
85
|
+
else
|
86
|
+
all_partials(resource, sync_render_context, scope).collect do |partial|
|
87
|
+
partial.creator_for_scope(scope).message
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
RenderSync.client.batch_publish(messages.flatten)
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# The Context class handling partial rendering
|
98
|
+
def sync_render_context
|
99
|
+
@sync_render_context ||= Renderer.new
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns Array of Partials for all given resource and context, including
|
103
|
+
# both Partial and RefetchPartial instances
|
104
|
+
def all_partials(resource, context, scope = nil)
|
105
|
+
Partial.all(resource, context, scope) + RefetchPartial.all(resource, context, scope)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns an Array containing both the Partial and RefetchPartial instances
|
109
|
+
# for a given resource, context and partial name
|
110
|
+
def specified_partials(resource, context, partial_name)
|
111
|
+
[Partial.find(resource, partial_name, context), RefetchPartial.find(resource, partial_name, context)].compact
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RenderSync
|
2
|
+
|
3
|
+
class Channel
|
4
|
+
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
self.name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def signature
|
12
|
+
OpenSSL::HMAC.hexdigest(
|
13
|
+
OpenSSL::Digest.new('sha1'),
|
14
|
+
RenderSync.auth_token,
|
15
|
+
self.name
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
RenderSync.client.normalize_channel(self.signature)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RenderSync
|
2
|
+
module Clients
|
3
|
+
class Dummy
|
4
|
+
def method_missing(*args, &block)
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
|
8
|
+
class Message
|
9
|
+
def self.method_missing(*args, &block)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*)
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(*args, &block)
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module RenderSync
|
2
|
+
module Clients
|
3
|
+
class Faye
|
4
|
+
|
5
|
+
def setup
|
6
|
+
require 'faye'
|
7
|
+
# nothing to set up
|
8
|
+
end
|
9
|
+
|
10
|
+
def batch_publish(*args)
|
11
|
+
Message.batch_publish(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_message(*args)
|
15
|
+
Message.new(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Public: Normalize channel to adapter supported format
|
19
|
+
#
|
20
|
+
# channel - The string channel name
|
21
|
+
#
|
22
|
+
# Returns The normalized channel prefixed with supported format for Faye
|
23
|
+
def normalize_channel(channel)
|
24
|
+
"/#{channel}"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
class Message
|
29
|
+
|
30
|
+
attr_accessor :channel, :data
|
31
|
+
|
32
|
+
def self.batch_publish(messages)
|
33
|
+
if RenderSync.async?
|
34
|
+
batch_publish_asynchronous(messages)
|
35
|
+
else
|
36
|
+
batch_publish_synchronous(messages)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.batch_publish_synchronous(messages)
|
41
|
+
Net::HTTP.post_form(
|
42
|
+
URI.parse(RenderSync.server),
|
43
|
+
message: batch_messages_query_hash(messages).to_json
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.batch_publish_asynchronous(messages)
|
48
|
+
RenderSync.reactor.perform do
|
49
|
+
EM::HttpRequest.new(RenderSync.server).post(body: {
|
50
|
+
message: batch_messages_query_hash(messages).to_json
|
51
|
+
})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.batch_messages_query_hash(messages)
|
56
|
+
{
|
57
|
+
channel: "/batch_publish",
|
58
|
+
data: messages.collect(&:to_hash),
|
59
|
+
ext: { auth_token: RenderSync.auth_token }
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(channel, data)
|
64
|
+
self.channel = channel
|
65
|
+
self.data = data
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_hash
|
69
|
+
{
|
70
|
+
channel: channel,
|
71
|
+
data: data,
|
72
|
+
ext: {
|
73
|
+
auth_token: RenderSync.auth_token
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_json
|
79
|
+
to_hash.to_json
|
80
|
+
end
|
81
|
+
|
82
|
+
def publish
|
83
|
+
if RenderSync.async?
|
84
|
+
publish_asynchronous
|
85
|
+
else
|
86
|
+
publish_synchronous
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def publish_synchronous
|
91
|
+
Net::HTTP.post_form URI.parse(RenderSync.server), message: to_json
|
92
|
+
end
|
93
|
+
|
94
|
+
def publish_asynchronous
|
95
|
+
RenderSync.reactor.perform do
|
96
|
+
EM::HttpRequest.new(RenderSync.server).post(body: {
|
97
|
+
message: self.to_json
|
98
|
+
})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|