thunderer 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +5 -0
- data/README.md +71 -2
- data/lib/generators/thunderer/install_generator.rb +1 -0
- data/lib/generators/thunderer/templates/thunderer.rb +5 -0
- data/lib/thunderer.rb +28 -25
- data/lib/thunderer/{parser.rb → channel_parser.rb} +1 -1
- data/lib/thunderer/configuration.rb +38 -0
- data/lib/thunderer/controller_additions.rb +1 -1
- data/lib/thunderer/engine.rb +0 -17
- data/lib/thunderer/faye_extension.rb +2 -2
- data/lib/thunderer/messages/async_message.rb +32 -0
- data/lib/thunderer/messages/base.rb +40 -0
- data/lib/thunderer/publish_changes.rb +1 -1
- data/lib/thunderer/version.rb +1 -1
- data/spec/spec_helper.rb +3 -5
- data/spec/thunderer/controller_aditions_spec.rb +7 -1
- data/spec/thunderer/messages/async_message_spec.rb +45 -0
- data/spec/thunderer/messages/base_spec.rb +5 -0
- data/spec/thunderer/parser_spec.rb +2 -2
- data/spec/thunderer_spec.rb +23 -27
- data/thunderer.gemspec +1 -5
- metadata +15 -66
- data/lib/thunderer/messanger.rb +0 -50
- data/spec/thunderer/messanger_spec.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac9ccfa84ee7f79f531bfc0fd9fb47c75a6cb8af
|
4
|
+
data.tar.gz: a69cb3989a05b5f12cf5c5f8b0845b679702359a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ca8bb850cd751739ab961c15c2e5a60c9533a47fa9f6f33a1b6dedace7f54c8920d94c60280ab3a9a0d467745bfbb66010fd6682db1071ed550f690d9ba5e41
|
7
|
+
data.tar.gz: 241193c64ec37ffb4aeeae18ac38fa15a180b730b03e102b875c2ea9e51f9a3f3cce2cf0bd719028b61133a0619de02df169ad7b6eb80f99e4bbf06a51d85d14
|
data/Gemfile
CHANGED
@@ -3,10 +3,15 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in thunderer.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem 'rails', '4.2.0'
|
7
|
+
gem 'sqlite3'
|
8
|
+
gem 'jasmine'
|
9
|
+
|
6
10
|
group :development do
|
7
11
|
gem 'guard-rspec', require: false
|
8
12
|
gem 'guard-jasmine'
|
9
13
|
gem 'rsense'
|
14
|
+
gem 'sucker_punch'
|
10
15
|
end
|
11
16
|
|
12
17
|
|
data/README.md
CHANGED
@@ -20,10 +20,79 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
$ gem install thunderer
|
22
22
|
|
23
|
-
##
|
23
|
+
## Rails 4.2 integration
|
24
24
|
|
25
|
-
|
25
|
+
Now thunderer supports ActiveJob scheduling of notifications and can be configured by global setup of ActiveJob or
|
26
|
+
in thunderer.rb
|
26
27
|
|
28
|
+
Thunderer.configure do |config|
|
29
|
+
config.queue_adapter = :sucker_punch
|
30
|
+
config.environment = Rails.env
|
31
|
+
config.config_file_path = 'config/thunderer.yml'
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
## Setup
|
36
|
+
Run generator:
|
37
|
+
|
38
|
+
rails g thunderer:install
|
39
|
+
|
40
|
+
It will generate thunderer.ru and thunderer.yml files. Check it and setup domain for production
|
41
|
+
|
42
|
+
Next add the JavaScript file to your application.js file manifest.
|
43
|
+
|
44
|
+
//= require thunderer
|
45
|
+
|
46
|
+
## Usage with typical rails app
|
47
|
+
|
48
|
+
Use the `subscribe_to` helper method on any page to subscribe to a channel.
|
49
|
+
|
50
|
+
```rhtml
|
51
|
+
<%= subscribe_to "/comments" %>
|
52
|
+
```
|
53
|
+
|
54
|
+
Then setup active record models:
|
55
|
+
|
56
|
+
```
|
57
|
+
class Comment < ActiveRecord::Base
|
58
|
+
include Thunderer::PublishChanges
|
59
|
+
notify_client_to_channels '/comments/new'
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Usage with Angular single page application
|
64
|
+
|
65
|
+
Before start using with Angular add response interceptor (ThundererInterceptor) and service ($thunderer):
|
66
|
+
|
67
|
+
//= require thunderer_angular
|
68
|
+
|
69
|
+
Inject `'Thunderer'` module to your app, and setup `$http` service
|
70
|
+
|
71
|
+
```
|
72
|
+
...
|
73
|
+
provider.interceptors.push('ThundererInterceptor');
|
74
|
+
...
|
75
|
+
```
|
76
|
+
|
77
|
+
The main deference of usage is adding special headers to json responses:
|
78
|
+
|
79
|
+
```
|
80
|
+
class CommentsController < ApplicationController
|
81
|
+
include Thunderer::ControllerAdditions
|
82
|
+
|
83
|
+
thunderer_channels '/comments'
|
84
|
+
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
After that you can subscribe in your angular controllers and directives to Faye callbacks
|
89
|
+
|
90
|
+
```
|
91
|
+
commentAddOrChangedCallback = function(data) {
|
92
|
+
alert(data);
|
93
|
+
}
|
94
|
+
$thunderer.addListener("/comments", commentAddOrChangedCallback);
|
95
|
+
```
|
27
96
|
## Contributing
|
28
97
|
|
29
98
|
1. Fork it ( http://github.com/<my-github-username>/thunderer/fork )
|
@@ -13,6 +13,7 @@ module Thunderer
|
|
13
13
|
copy_file '../../../../app/assets/javascripts/thunderer_subscription_service.js', 'public/javascripts/thunderer_subscription_service.js'
|
14
14
|
end
|
15
15
|
copy_file 'thunderer.ru', 'thunderer.ru'
|
16
|
+
copy_file 'thunderer.rb', 'app/config/initializers/thunderer.rb'
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/thunderer.rb
CHANGED
@@ -1,30 +1,30 @@
|
|
1
1
|
require 'thunderer/version'
|
2
|
-
require 'thunderer/
|
3
|
-
require 'thunderer/messanger'
|
2
|
+
require 'thunderer/channel_parser'
|
4
3
|
require 'thunderer/faye_extension'
|
4
|
+
require 'thunderer/messages/async_message'
|
5
|
+
require 'thunderer/messages/base'
|
6
|
+
require 'thunderer/configuration'
|
5
7
|
require 'digest/sha1'
|
6
|
-
require '
|
8
|
+
require 'ostruct'
|
7
9
|
require 'thunderer/engine' if defined? Rails
|
8
10
|
|
9
11
|
module Thunderer
|
10
|
-
class Error < StandardError;
|
12
|
+
class Error < StandardError;
|
13
|
+
end
|
11
14
|
|
12
15
|
class << self
|
13
16
|
attr_reader :config
|
14
|
-
attr_reader :messanger
|
15
17
|
|
16
18
|
def reset_config
|
17
|
-
|
19
|
+
@config = Thunderer::Configuration.new
|
18
20
|
end
|
19
21
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
raise ArgumentError, "The #{environment} environment dose not exist" unless config_yaml
|
24
|
-
config_yaml.each { |k,v| config[k.to_sym] = v }
|
25
|
-
Thunderer::Messanger.configure( config[:local_server_url] || config[:server])
|
26
|
-
@messanger = Thunderer::Messanger
|
22
|
+
def config
|
23
|
+
@config ||= Thunderer::Configuration.new
|
24
|
+
end
|
27
25
|
|
26
|
+
def configure
|
27
|
+
yield config if block_given?
|
28
28
|
end
|
29
29
|
|
30
30
|
def publish_to channel, data
|
@@ -32,31 +32,34 @@ module Thunderer
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def publish_message(message)
|
35
|
-
raise Error, 'No server specified, ensure thunderer.yml was loaded properly.' unless config
|
36
|
-
|
37
|
-
|
35
|
+
raise Error, 'No server specified, ensure thunderer.yml was loaded properly.' unless config.server
|
36
|
+
if config.async
|
37
|
+
Thunderer::Messages::Base.new(message)
|
38
|
+
else
|
39
|
+
Thunderer::Messages::AsyncMessage.new(message)
|
40
|
+
end.deliver
|
38
41
|
end
|
39
42
|
|
40
43
|
def message(channel, data)
|
41
|
-
{:
|
42
|
-
:
|
43
|
-
|
44
|
-
|
45
|
-
:
|
44
|
+
{channel: channel,
|
45
|
+
data: {
|
46
|
+
channel: channel,
|
47
|
+
data: data},
|
48
|
+
ext: {thunderer_secret_token: config.secret_token}}
|
46
49
|
end
|
47
50
|
|
48
51
|
def subscription(options = {})
|
49
|
-
sub = {:
|
50
|
-
sub[:signature] = Digest::SHA1.hexdigest([config
|
52
|
+
sub = {server: config.server, timestamp: (Time.now.to_f * 1000).round}.merge(options)
|
53
|
+
sub[:signature] = Digest::SHA1.hexdigest([config.secret_token, sub[:channel], sub[:timestamp]].join)
|
51
54
|
sub
|
52
55
|
end
|
53
56
|
|
54
57
|
def signature_expired?(timestamp)
|
55
|
-
timestamp < ((Time.now.to_f - config
|
58
|
+
timestamp < ((Time.now.to_f - config.signature_expiration)*1000).round if config.signature_expiration
|
56
59
|
end
|
57
60
|
|
58
61
|
def faye_app(options = {})
|
59
|
-
options = {mount: '/faye', timeout: 45, extensions: [FayeExtension.new]
|
62
|
+
options = {mount: '/faye', timeout: 45, extensions: [FayeExtension.new]}.merge(options)
|
60
63
|
Faye::RackAdapter.new(options)
|
61
64
|
end
|
62
65
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
module Thunderer
|
3
|
+
class Configuration
|
4
|
+
attr_writer :environment
|
5
|
+
attr_accessor :queue_adapter
|
6
|
+
attr_accessor :server
|
7
|
+
attr_accessor :local_server_url
|
8
|
+
attr_accessor :async
|
9
|
+
attr_accessor :secret_token
|
10
|
+
attr_accessor :signature_expiration
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@config_file_path = ''
|
14
|
+
@queue_adapter = nil
|
15
|
+
@server = nil
|
16
|
+
@secret_token = nil
|
17
|
+
@signature_expiration = 3600
|
18
|
+
@local_server_url = nil
|
19
|
+
@async = false
|
20
|
+
@environment = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def config_file_path=(value)
|
24
|
+
load_configuration(value, @environment)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def load_configuration(path, environment)
|
30
|
+
config_yaml = YAML.load_file(path)[environment]
|
31
|
+
raise ArgumentError, "The #{environment} environment dose not exist" unless config_yaml
|
32
|
+
config_yaml.each do |k, v|
|
33
|
+
self.public_send("#{k}=",v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -14,7 +14,7 @@ module Thunderer
|
|
14
14
|
headers['channels'] = (self.class.channels || []).map do |channel|
|
15
15
|
new_str = if self.class.interpolation_object && channel
|
16
16
|
object = send(self.class.interpolation_object)
|
17
|
-
Thunderer::
|
17
|
+
Thunderer::ChannelParser.interpolate_channel channel, object
|
18
18
|
else
|
19
19
|
channel
|
20
20
|
end
|
data/lib/thunderer/engine.rb
CHANGED
@@ -4,11 +4,6 @@ require 'thunderer/controller_additions'
|
|
4
4
|
module Thunderer
|
5
5
|
class Engine < ::Rails::Engine
|
6
6
|
|
7
|
-
initializer 'thunderer.config' do
|
8
|
-
path = Rails.root.join('config/thunderer.yml')
|
9
|
-
Thunderer.load_config(path, Rails.env) if path.exist?
|
10
|
-
end
|
11
|
-
|
12
7
|
initializer :assets do |config|
|
13
8
|
Rails.application.config.assets.paths << File.join(
|
14
9
|
Gem.loaded_specs['faye'].full_gem_path, 'lib')
|
@@ -18,17 +13,5 @@ module Thunderer
|
|
18
13
|
ActionView::Base.send :include, ViewHelpers
|
19
14
|
end
|
20
15
|
|
21
|
-
# initializer 'thunderer.controller' do
|
22
|
-
# ActiveSupport.on_load(:action_controller) do
|
23
|
-
# include Thunderer::ControllerAdditions
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# initializer 'thunderer.active_record' do
|
28
|
-
# ActiveSupport.on_load(:active_record) do
|
29
|
-
# include Thunderer::PublishChanges
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
|
33
16
|
end
|
34
17
|
end
|
@@ -27,9 +27,9 @@ module Thunderer
|
|
27
27
|
|
28
28
|
# Ensures the secret token is correct before publishing.
|
29
29
|
def authenticate_publish(message)
|
30
|
-
if Thunderer.config
|
30
|
+
if Thunderer.config.secret_token.nil?
|
31
31
|
raise Error, 'No secret_token config set, ensure thunderer.yml is loaded properly.'
|
32
|
-
elsif message['ext']['thunderer_secret_token'] != Thunderer.config
|
32
|
+
elsif message['ext']['thunderer_secret_token'] != Thunderer.config.secret_token
|
33
33
|
|
34
34
|
message['error'] = 'Incorrect token.'
|
35
35
|
else
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
module Thunderer
|
3
|
+
module Messages
|
4
|
+
class AsyncMessage
|
5
|
+
class Job < ::ActiveJob::Base
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def queue_adapter
|
9
|
+
if Thunderer.config.queue_adapter
|
10
|
+
"ActiveJob::QueueAdapters::#{Thunderer.config.queue_adapter.to_s.camelize}Adapter".constantize
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform(message)
|
18
|
+
Thunderer::Messages::Base.new(message).deliver
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(message)
|
23
|
+
@message = message
|
24
|
+
end
|
25
|
+
|
26
|
+
def deliver
|
27
|
+
Job.perform_later(@message)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Thunderer
|
2
|
+
module Messages
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize(message)
|
6
|
+
@message = message
|
7
|
+
end
|
8
|
+
|
9
|
+
def deliver
|
10
|
+
form = build_form
|
11
|
+
form.set_form_data(message: @message.to_json)
|
12
|
+
protocol.start { |h| h.request(form) }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def build_form
|
18
|
+
Net::HTTP::Post.new(uri.path.empty? ? '/' : uri.path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def protocol
|
22
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
23
|
+
http.use_ssl = use_ssl?
|
24
|
+
if use_ssl?
|
25
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
26
|
+
end
|
27
|
+
http
|
28
|
+
end
|
29
|
+
|
30
|
+
def uri
|
31
|
+
@uri ||= URI.parse(Thunderer.config.local_server_url || Thunderer.config.server)
|
32
|
+
end
|
33
|
+
|
34
|
+
def use_ssl?
|
35
|
+
uri.scheme == 'https'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -19,7 +19,7 @@ module Thunderer
|
|
19
19
|
else
|
20
20
|
notification_message
|
21
21
|
end
|
22
|
-
Thunderer.publish_to Thunderer::
|
22
|
+
Thunderer.publish_to Thunderer::ChannelParser.interpolate_channel(channel, self), rooted_message
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/lib/thunderer/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -32,12 +32,10 @@ RSpec.configure do |config|
|
|
32
32
|
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
|
33
33
|
dep.autoload_paths.unshift FIXTURES_PATH
|
34
34
|
|
35
|
-
ActiveRecord::
|
36
|
-
|
37
|
-
load File.join(FIXTURES_PATH, 'schema.rb')
|
38
|
-
end
|
35
|
+
ActiveRecord::Migration.verbose = false
|
36
|
+
load File.join(FIXTURES_PATH, 'schema.rb')
|
39
37
|
|
40
|
-
ActiveRecord::
|
38
|
+
ActiveRecord::FixtureSet.create_fixtures(FIXTURES_PATH, ActiveRecord::Base.connection.tables)
|
41
39
|
|
42
40
|
config.order = 'random'
|
43
41
|
end
|
@@ -19,7 +19,12 @@ describe Thunderer::ControllerAdditions do
|
|
19
19
|
describe '#thunderer_channels' do
|
20
20
|
let(:config_file_path) { 'spec/fixtures/thunderer.yml' }
|
21
21
|
let(:environment) { 'production' }
|
22
|
-
before
|
22
|
+
before do
|
23
|
+
Thunderer.configure do |config|
|
24
|
+
config.environment = environment
|
25
|
+
config.config_file_path = config_file_path
|
26
|
+
end
|
27
|
+
end
|
23
28
|
|
24
29
|
it 'should affect channels class variable' do
|
25
30
|
controller_class.thunderer_channels('hello')
|
@@ -31,6 +36,7 @@ describe Thunderer::ControllerAdditions do
|
|
31
36
|
expect(controller_class.interpolation_object).to include('hello')
|
32
37
|
end
|
33
38
|
|
39
|
+
|
34
40
|
it 'should setup before filter for setting headers' do
|
35
41
|
expect(controller_class).to have_filters(:before, :add_channels_header)
|
36
42
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'thunderer/messages/async_message'
|
3
|
+
require 'rails/all'
|
4
|
+
describe Thunderer::Messages::AsyncMessage do
|
5
|
+
let(:message) { Thunderer::Messages::AsyncMessage.new }
|
6
|
+
before { Thunderer.reset_config }
|
7
|
+
|
8
|
+
describe Thunderer::Messages::AsyncMessage::Job do
|
9
|
+
let(:job) { Thunderer::Messages::AsyncMessage::Job }
|
10
|
+
describe '#queue_adapter' do
|
11
|
+
subject { job.queue_adapter }
|
12
|
+
|
13
|
+
context 'when no config' do
|
14
|
+
it { is_expected.to eq(ActiveJob::QueueAdapters::InlineAdapter) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when active job config set to sucker_punch' do
|
18
|
+
around do |ex|
|
19
|
+
ActiveJob::Base.queue_adapter = :sucker_punch
|
20
|
+
ex.run
|
21
|
+
ActiveJob::Base.queue_adapter = :inline
|
22
|
+
end
|
23
|
+
|
24
|
+
it { is_expected.to eq(ActiveJob::QueueAdapters::SuckerPunchAdapter) }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'but thunderer config is sucker_punch' do
|
28
|
+
before do
|
29
|
+
Thunderer.configure do |config|
|
30
|
+
config.queue_adapter = :sucker_punch
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'and active job config is inline' do
|
35
|
+
before { ActiveJob::Base.queue_adapter = :inline }
|
36
|
+
|
37
|
+
it { is_expected.to eq(ActiveJob::QueueAdapters::SuckerPunchAdapter) }
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
|
-
describe Thunderer::
|
4
|
+
describe Thunderer::ChannelParser do
|
5
5
|
|
6
6
|
let(:object) { OpenStruct.new(first: 1, second: 2) }
|
7
7
|
|
8
8
|
describe '#interpolate_channel' do
|
9
|
-
subject { Thunderer::
|
9
|
+
subject { Thunderer::ChannelParser.interpolate_channel(channel, object) }
|
10
10
|
|
11
11
|
context 'when channel have no interpolation' do
|
12
12
|
let(:channel) { 'without interpolation string' }
|
data/spec/thunderer_spec.rb
CHANGED
@@ -4,13 +4,18 @@ describe Thunderer do
|
|
4
4
|
before { Thunderer.reset_config }
|
5
5
|
let(:config_file_path) { 'spec/fixtures/thunderer.yml' }
|
6
6
|
let(:environment) { 'production' }
|
7
|
-
let(:load_config)
|
7
|
+
let(:load_config) do
|
8
|
+
Thunderer.configure do |config|
|
9
|
+
config.environment = environment
|
10
|
+
config.config_file_path = config_file_path
|
11
|
+
end
|
12
|
+
end
|
8
13
|
|
9
14
|
describe 'default state' do
|
10
15
|
describe '#config' do
|
11
16
|
subject { Thunderer.config }
|
12
17
|
|
13
|
-
it { is_expected.to
|
18
|
+
it { is_expected.to be_a(Thunderer::Configuration)}
|
14
19
|
|
15
20
|
end
|
16
21
|
end
|
@@ -22,11 +27,19 @@ describe Thunderer do
|
|
22
27
|
context 'when config environment was exists' do
|
23
28
|
before { load_config }
|
24
29
|
|
25
|
-
|
30
|
+
{
|
31
|
+
server: 'http://example.com/faye',
|
32
|
+
secret_token: 'PRODUCTION_SECRET_TOKEN',
|
33
|
+
signature_expiration: 600
|
34
|
+
}.each do |method, value|
|
35
|
+
context "#config.#{method}" do
|
36
|
+
subject { Thunderer.config.send(method)}
|
26
37
|
|
27
|
-
|
38
|
+
it { is_expected.to eq(value) }
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
28
42
|
|
29
|
-
it { is_expected.to include(:signature_expiration => 600) }
|
30
43
|
end
|
31
44
|
|
32
45
|
context 'when config environment was not exists' do
|
@@ -40,30 +53,13 @@ describe Thunderer do
|
|
40
53
|
|
41
54
|
end
|
42
55
|
|
43
|
-
describe 'Thunderer::Messanger configuration' do
|
44
|
-
subject { Thunderer::Messanger.config }
|
45
|
-
|
46
|
-
it { is_expected.not_to eq({}) }
|
47
|
-
|
48
|
-
context 'when config have local_server_url' do
|
49
|
-
let(:config_file_path) { 'spec/fixtures/thunderer_local_server.yml' }
|
50
|
-
let(:environment) { 'production' }
|
51
|
-
|
52
|
-
before { load_config }
|
53
|
-
|
54
|
-
it { is_expected.to include('uri'=>URI.parse('http://localhost:3000')) }
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
56
|
end
|
61
57
|
|
62
58
|
describe '#subscription' do
|
63
59
|
before { load_config }
|
64
60
|
let!(:time_mock) { Time.now }
|
65
61
|
before { allow(Time).to receive(:now) { time_mock } }
|
66
|
-
before { Thunderer.config
|
62
|
+
before { Thunderer.config.server = 'server' }
|
67
63
|
subject { Thunderer.subscription }
|
68
64
|
|
69
65
|
it { is_expected.to include(:timestamp => (time_mock.to_f * 1000).round) }
|
@@ -77,7 +73,7 @@ describe Thunderer do
|
|
77
73
|
end
|
78
74
|
|
79
75
|
describe 'signature' do
|
80
|
-
before { Thunderer.config
|
76
|
+
before { Thunderer.config.secret_token = 'token' }
|
81
77
|
subject { Thunderer.subscription(:timestamp => 123, :channel => 'channel') }
|
82
78
|
|
83
79
|
it { is_expected.to include(:signature => Digest::SHA1.hexdigest('tokenchannel123')) }
|
@@ -91,7 +87,7 @@ describe Thunderer do
|
|
91
87
|
|
92
88
|
describe 'formatting' do
|
93
89
|
let(:secret_token) { 'token' }
|
94
|
-
before { Thunderer.config
|
90
|
+
before { Thunderer.config.secret_token = secret_token }
|
95
91
|
|
96
92
|
subject { Thunderer.message('chan', :foo => 'bar') }
|
97
93
|
|
@@ -116,7 +112,7 @@ describe Thunderer do
|
|
116
112
|
before { load_config }
|
117
113
|
|
118
114
|
specify do
|
119
|
-
|
115
|
+
expect_any_instance_of(Thunderer::Messages::Base).to receive(:deliver)
|
120
116
|
subject
|
121
117
|
end
|
122
118
|
end
|
@@ -154,7 +150,7 @@ describe Thunderer do
|
|
154
150
|
|
155
151
|
describe 'signature_expired?' do
|
156
152
|
let(:expiration) { 30*60 }
|
157
|
-
before { Thunderer.config
|
153
|
+
before { Thunderer.config.signature_expiration = expiration }
|
158
154
|
subject { Thunderer.signature_expired?(time) }
|
159
155
|
|
160
156
|
context 'when time greater than expiration ' do
|
data/thunderer.gemspec
CHANGED
@@ -15,11 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
|
16
16
|
spec.add_dependency 'faye'
|
17
17
|
|
18
|
-
spec.add_runtime_dependency 'activesupport'
|
19
|
-
spec.add_development_dependency 'rails'
|
20
|
-
spec.add_development_dependency 'rspec'
|
21
|
-
spec.add_development_dependency 'jasmine'
|
22
|
-
spec.add_development_dependency 'sqlite3'
|
18
|
+
spec.add_runtime_dependency 'activesupport', '4.2.0'
|
23
19
|
|
24
20
|
spec.files = `git ls-files -z`.split("\x0")
|
25
21
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thunderer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Chubarov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faye
|
@@ -28,72 +28,16 @@ dependencies:
|
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 4.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rails
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rspec
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: jasmine
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
38
|
+
- - '='
|
81
39
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: sqlite3
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
40
|
+
version: 4.2.0
|
97
41
|
- !ruby/object:Gem::Dependency
|
98
42
|
name: bundler
|
99
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -140,14 +84,17 @@ files:
|
|
140
84
|
- app/assets/javascripts/thunderer.js
|
141
85
|
- app/assets/javascripts/thunderer_angular.js
|
142
86
|
- lib/generators/thunderer/install_generator.rb
|
87
|
+
- lib/generators/thunderer/templates/thunderer.rb
|
143
88
|
- lib/generators/thunderer/templates/thunderer.ru
|
144
89
|
- lib/generators/thunderer/templates/thunderer.yml
|
145
90
|
- lib/thunderer.rb
|
91
|
+
- lib/thunderer/channel_parser.rb
|
92
|
+
- lib/thunderer/configuration.rb
|
146
93
|
- lib/thunderer/controller_additions.rb
|
147
94
|
- lib/thunderer/engine.rb
|
148
95
|
- lib/thunderer/faye_extension.rb
|
149
|
-
- lib/thunderer/
|
150
|
-
- lib/thunderer/
|
96
|
+
- lib/thunderer/messages/async_message.rb
|
97
|
+
- lib/thunderer/messages/base.rb
|
151
98
|
- lib/thunderer/publish_changes.rb
|
152
99
|
- lib/thunderer/version.rb
|
153
100
|
- lib/thunderer/view_helpers.rb
|
@@ -166,7 +113,8 @@ files:
|
|
166
113
|
- spec/support/controller_macros.rb
|
167
114
|
- spec/support/matchers/have_filter.rb
|
168
115
|
- spec/thunderer/controller_aditions_spec.rb
|
169
|
-
- spec/thunderer/
|
116
|
+
- spec/thunderer/messages/async_message_spec.rb
|
117
|
+
- spec/thunderer/messages/base_spec.rb
|
170
118
|
- spec/thunderer/parser_spec.rb
|
171
119
|
- spec/thunderer/publish_changes_spec.rb
|
172
120
|
- spec/thunderer_spec.rb
|
@@ -211,7 +159,8 @@ test_files:
|
|
211
159
|
- spec/support/controller_macros.rb
|
212
160
|
- spec/support/matchers/have_filter.rb
|
213
161
|
- spec/thunderer/controller_aditions_spec.rb
|
214
|
-
- spec/thunderer/
|
162
|
+
- spec/thunderer/messages/async_message_spec.rb
|
163
|
+
- spec/thunderer/messages/base_spec.rb
|
215
164
|
- spec/thunderer/parser_spec.rb
|
216
165
|
- spec/thunderer/publish_changes_spec.rb
|
217
166
|
- spec/thunderer_spec.rb
|
data/lib/thunderer/messanger.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module Thunderer
|
2
|
-
module Messanger
|
3
|
-
class ConfigurationError < StandardError; end
|
4
|
-
|
5
|
-
class << self
|
6
|
-
attr_reader :config
|
7
|
-
|
8
|
-
def reset_config
|
9
|
-
@config = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def configure url
|
13
|
-
reset_config
|
14
|
-
uri = URI.parse(url)
|
15
|
-
@config['uri'] = uri
|
16
|
-
@config['use_ssl'] = uri.scheme == 'https'
|
17
|
-
end
|
18
|
-
|
19
|
-
def post( message )
|
20
|
-
raise ConfigurationError if not_configured?
|
21
|
-
|
22
|
-
form = build_form
|
23
|
-
form.set_form_data(:message => message.to_json)
|
24
|
-
protocol.start { |h| h.request(form) }
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def build_form
|
30
|
-
uri = @config['uri']
|
31
|
-
Net::HTTP::Post.new(uri.path.empty? ? '/' : uri.path)
|
32
|
-
end
|
33
|
-
|
34
|
-
def protocol
|
35
|
-
uri = @config['uri']
|
36
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
37
|
-
http.use_ssl = @config['use_ssl']
|
38
|
-
if @config['use_ssl']
|
39
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
40
|
-
end
|
41
|
-
http
|
42
|
-
end
|
43
|
-
|
44
|
-
def not_configured?
|
45
|
-
@config == {}
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'thunderer/messanger'
|
3
|
-
|
4
|
-
describe Thunderer::Messanger do
|
5
|
-
let(:messanger) { Thunderer::Messanger }
|
6
|
-
before { Thunderer::Messanger.reset_config }
|
7
|
-
|
8
|
-
it 'default have nil uri' do
|
9
|
-
expect(messanger.config['uri']).to eq(nil)
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'default have nil use_ssl' do
|
13
|
-
expect(messanger.config['use_ssl']).to eq(nil)
|
14
|
-
end
|
15
|
-
|
16
|
-
describe '#post' do
|
17
|
-
subject { messanger.post(message) }
|
18
|
-
|
19
|
-
context 'with default config' do
|
20
|
-
let(:message) { double(:message) }
|
21
|
-
|
22
|
-
specify do
|
23
|
-
expect { subject }.to raise_error Thunderer::Messanger::ConfigurationError
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'with correct config' do
|
29
|
-
before { Thunderer::Messanger.configure('http://localhost:3000') }
|
30
|
-
let(:http_form) { double(:form) }
|
31
|
-
let(:http) { double(:http) }
|
32
|
-
let(:message) { 'Hello world' }
|
33
|
-
before { allow(Net::HTTP::Post).to receive(:new).with('/').and_return(http_form) }
|
34
|
-
before { allow(Net::HTTP).to receive(:new).with('localhost', 3000).and_return(http) }
|
35
|
-
before { allow(http).to receive(:use_ssl=) }
|
36
|
-
|
37
|
-
|
38
|
-
specify do
|
39
|
-
expect(http_form).to receive(:set_form_data).with(message: message.to_json)
|
40
|
-
expect(http).to receive(:start).and_yield(http)
|
41
|
-
expect(http).to receive(:request).with(http_form).and_return(:result)
|
42
|
-
expect(subject).to eq(:result)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
describe '#configure' do
|
52
|
-
|
53
|
-
it 'parse url and set configuration' do
|
54
|
-
messanger.configure('http://google.ru')
|
55
|
-
expect(messanger.config).not_to eq({})
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'set use_ssl to false for http' do
|
59
|
-
messanger.configure('http://google.ru')
|
60
|
-
expect(messanger.config['use_ssl']).to eq(false)
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'set use_ssl to false for https' do
|
64
|
-
messanger.configure('https://google.ru')
|
65
|
-
expect(messanger.config['use_ssl']).to eq(true)
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|