private_pub 0.1.0 → 0.2.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.
- data/CHANGELOG.rdoc +9 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -7
- data/lib/generators/private_pub/install_generator.rb +4 -3
- data/lib/generators/private_pub/templates/faye.ru +10 -5
- data/lib/generators/private_pub/templates/private_pub.yml +9 -0
- data/lib/private_pub/faye_extension.rb +6 -4
- data/lib/private_pub/railtie.rb +14 -0
- data/lib/private_pub/view_helpers.rb +17 -0
- data/lib/private_pub.rb +15 -26
- data/spec/fixtures/private_pub.yml +10 -0
- data/spec/private_pub/faye_extension_spec.rb +12 -3
- data/spec/private_pub_spec.rb +39 -13
- metadata +7 -4
- data/lib/generators/private_pub/templates/private_pub_helper.rb +0 -15
- data/lib/generators/private_pub/templates/private_pub_initializer.rb +0 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
0.2.0 (April 7, 2011)
|
2
|
+
|
3
|
+
* switched to YAML file for config. BACKWARDS INCOMPATIBLE: you will need to remove config/initializers/private_pub.rb
|
4
|
+
|
5
|
+
* moved view helpers into Railtie so helper file is no longer generated
|
6
|
+
|
7
|
+
* error out when signature has expired
|
8
|
+
|
9
|
+
|
1
10
|
0.1.0 (April 4, 2011)
|
2
11
|
|
3
12
|
* initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Bates
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
= Private Pub
|
2
2
|
|
3
|
-
This is a Ruby gem for use with Rails to publish and subscribe to messages through
|
3
|
+
This is a Ruby gem for use with Rails to publish and subscribe to messages through {Faye}[http://faye.jcoglan.com/]. All channels are automatically made private.
|
4
|
+
|
5
|
+
This project was motivated by {Railscasts episode #260}[http://railscasts.com/episodes/260-messaging-with-faye].
|
4
6
|
|
5
7
|
|
6
8
|
== Setup
|
@@ -22,7 +24,7 @@ Next, install and start up Faye using the rackup file that was generated.
|
|
22
24
|
gem install faye
|
23
25
|
rackup faye.ru -s thin -E production
|
24
26
|
|
25
|
-
It's not necessary to
|
27
|
+
It's not necessary to include faye.js since that will be handled automatically.
|
26
28
|
|
27
29
|
|
28
30
|
== Usage
|
@@ -31,13 +33,13 @@ Use the +subscribe_to+ helper method on any page to subscribe to a channel.
|
|
31
33
|
|
32
34
|
<%= subscribe_to "/messages/new" %>
|
33
35
|
|
34
|
-
Use the +publish_to+ helper method to publish messages to that channel. If a block of JavaScript is passed it will be evaluated automatically. This is usually done
|
36
|
+
Use the +publish_to+ helper method to publish messages to that channel. If a block of JavaScript is passed it will be evaluated automatically. This is usually done in a JavaScript AJAX response (such as a <tt>create.js.erb</tt> file).
|
35
37
|
|
36
38
|
<% publish_to "/messages/new" do %>
|
37
39
|
$("#chat").append("<%= escape_javascript render(@messages) %>");
|
38
40
|
<% end %>
|
39
41
|
|
40
|
-
There will be alternative ways to publish/subscribe to
|
42
|
+
There will be alternative ways to publish/subscribe to channels in the future.
|
41
43
|
|
42
44
|
|
43
45
|
== Security
|
@@ -48,8 +50,17 @@ Here's how it works. The +subscribe_to+ helper will output an element containing
|
|
48
50
|
|
49
51
|
<span class="private_pub_subscription" data-channel="/messages/new" data-signature="2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" data-timestamp="13019431281234"></span>
|
50
52
|
|
51
|
-
The data-signature is a combination of the channel, timestamp, and secret token set in the Rails app. This is checked by the Faye extension when subscribing to a channel to ensure the signature is correct. The signature is automatically expired after 1 hour but this can be configured.
|
53
|
+
The data-signature is a combination of the channel, timestamp, and secret token set in the Rails app. This is checked by the Faye extension when subscribing to a channel to ensure the signature is correct. The signature is automatically expired after 1 hour but this can be configured in the generated YAML file.
|
54
|
+
|
55
|
+
signature_expiration: 600 # 10 minutes, expressed in seconds
|
56
|
+
|
57
|
+
Or use a blank value for no expiration.
|
58
|
+
|
59
|
+
signature_expiration:
|
60
|
+
|
61
|
+
Note: if Faye is on a separate server from the Rails app it's important that the system clocks be in sync.
|
62
|
+
|
52
63
|
|
53
|
-
|
64
|
+
== Development & Feedback
|
54
65
|
|
55
|
-
|
66
|
+
Questions or comments? Please use the {issue tracker}[https://github.com/ryanb/private_pub/issues]. If you would like to contribue to this project, clone this repository and run +bundle+ and +rake+ to run the tests.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module PrivatePub
|
2
2
|
module Generators
|
3
3
|
class InstallGenerator < Rails::Generators::Base
|
4
4
|
def self.source_root
|
@@ -6,8 +6,9 @@ class PrivatePub
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def copy_files
|
9
|
-
|
10
|
-
|
9
|
+
remove_file "config/initializers/private_pub.rb"
|
10
|
+
remove_file "app/helpers/private_pub_helper.rb"
|
11
|
+
template "private_pub.yml", "config/private_pub.yml"
|
11
12
|
copy_file "private_pub.js", "public/javascripts/private_pub.js"
|
12
13
|
copy_file "faye.ru", "faye.ru"
|
13
14
|
end
|
@@ -1,7 +1,12 @@
|
|
1
|
+
# Run with: rackup faye.ru -s thin -E production
|
2
|
+
require "yaml"
|
1
3
|
require "faye"
|
2
|
-
|
3
|
-
require
|
4
|
+
begin
|
5
|
+
require "private_pub"
|
6
|
+
rescue LoadError
|
7
|
+
require "bundler/setup"
|
8
|
+
require "private_pub"
|
9
|
+
end
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
run faye_server
|
11
|
+
PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development")
|
12
|
+
run Faye::RackAdapter.new(:mount => "/faye", :timeout => 45, :extensions => [PrivatePub.faye_extension])
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module PrivatePub
|
2
2
|
class FayeExtension
|
3
3
|
def incoming(message, callback)
|
4
4
|
if message["channel"] == "/meta/subscribe"
|
@@ -15,13 +15,15 @@ class PrivatePub
|
|
15
15
|
subscription = PrivatePub.subscription(:channel => message["subscription"], :timestamp => message["ext"]["private_pub_timestamp"])
|
16
16
|
if message["ext"]["private_pub_signature"] != subscription[:signature]
|
17
17
|
message["error"] = "Incorrect signature."
|
18
|
+
elsif PrivatePub.signature_expired? message["ext"]["private_pub_timestamp"].to_i
|
19
|
+
message["error"] = "Signature has expired."
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def authenticate_publish(message)
|
22
|
-
if PrivatePub.secret_token.nil?
|
23
|
-
raise Error, "No
|
24
|
-
elsif message["ext"]["private_pub_token"] != PrivatePub.secret_token
|
24
|
+
if PrivatePub.config[:secret_token].nil?
|
25
|
+
raise Error, "No secret_token config set, ensure private_pub.yml is loaded properly."
|
26
|
+
elsif message["ext"]["private_pub_token"] != PrivatePub.config[:secret_token]
|
25
27
|
message["error"] = "Incorrect token."
|
26
28
|
end
|
27
29
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "private_pub/view_helpers"
|
2
|
+
|
3
|
+
module PrivatePub
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
initializer "private_pub.config" do
|
6
|
+
path = Rails.root.join("config/private_pub.yml")
|
7
|
+
PrivatePub.load_config(path, Rails.env) if path.exist?
|
8
|
+
end
|
9
|
+
|
10
|
+
initializer "private_pub.view_helpers" do
|
11
|
+
ActionView::Base.send :include, ViewHelpers
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module PrivatePub
|
2
|
+
module ViewHelpers
|
3
|
+
def publish_to(channel, &block)
|
4
|
+
message = {:channel => channel, :data => {:_eval => capture(&block)}, :ext => {:private_pub_token => PrivatePub.config[:secret_token]}}
|
5
|
+
PrivatePub.publish(:message => message.to_json)
|
6
|
+
end
|
7
|
+
|
8
|
+
def subscribe_to(channel)
|
9
|
+
subscription = PrivatePub.subscription(:channel => channel)
|
10
|
+
content_tag :span, "", :class => "private_pub_subscription",
|
11
|
+
"data-server" => PrivatePub.config[:server],
|
12
|
+
"data-channel" => subscription[:channel],
|
13
|
+
"data-signature" => subscription[:signature],
|
14
|
+
"data-timestamp" => subscription[:timestamp]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/private_pub.rb
CHANGED
@@ -2,34 +2,13 @@ require "digest/sha1"
|
|
2
2
|
require "net/http"
|
3
3
|
|
4
4
|
require "private_pub/faye_extension"
|
5
|
+
require "private_pub/railtie" if defined? Rails
|
5
6
|
|
6
|
-
|
7
|
+
module PrivatePub
|
7
8
|
class Error < StandardError; end
|
8
9
|
|
9
10
|
class << self
|
10
|
-
|
11
|
-
@config[:server] = server
|
12
|
-
end
|
13
|
-
|
14
|
-
def server
|
15
|
-
@config[:server]
|
16
|
-
end
|
17
|
-
|
18
|
-
def signature_expiration=(signature_expiration)
|
19
|
-
@config[:signature_expiration] = signature_expiration
|
20
|
-
end
|
21
|
-
|
22
|
-
def signature_expiration
|
23
|
-
@config[:signature_expiration]
|
24
|
-
end
|
25
|
-
|
26
|
-
def secret_token=(secret_token)
|
27
|
-
@config[:secret_token] = secret_token
|
28
|
-
end
|
29
|
-
|
30
|
-
def secret_token
|
31
|
-
@config[:secret_token]
|
32
|
-
end
|
11
|
+
attr_reader :config
|
33
12
|
|
34
13
|
def reset_config
|
35
14
|
@config = {
|
@@ -38,19 +17,29 @@ class PrivatePub
|
|
38
17
|
}
|
39
18
|
end
|
40
19
|
|
20
|
+
def load_config(filename, environment)
|
21
|
+
yaml = YAML.load_file(filename)[environment.to_s]
|
22
|
+
raise ArgumentError, "The #{environment} environment does not exist in #{filename}" if yaml.nil?
|
23
|
+
yaml.each { |k, v| config[k.to_sym] = v }
|
24
|
+
end
|
25
|
+
|
41
26
|
def subscription(options = {})
|
42
27
|
sub = {:timestamp => (Time.now.to_f * 1000).round}.merge(options)
|
43
|
-
sub[:signature] = Digest::SHA1.hexdigest([secret_token, sub[:channel], sub[:timestamp]].join)
|
28
|
+
sub[:signature] = Digest::SHA1.hexdigest([config[:secret_token], sub[:channel], sub[:timestamp]].join)
|
44
29
|
sub
|
45
30
|
end
|
46
31
|
|
47
32
|
def publish(data)
|
48
|
-
Net::HTTP.post_form(URI.parse(
|
33
|
+
Net::HTTP.post_form(URI.parse(config[:server]), data)
|
49
34
|
end
|
50
35
|
|
51
36
|
def faye_extension
|
52
37
|
FayeExtension.new
|
53
38
|
end
|
39
|
+
|
40
|
+
def signature_expired?(timestamp)
|
41
|
+
timestamp < ((Time.now.to_f - config[:signature_expiration])*1000).round if config[:signature_expiration]
|
42
|
+
end
|
54
43
|
end
|
55
44
|
|
56
45
|
reset_config
|
@@ -0,0 +1,10 @@
|
|
1
|
+
development:
|
2
|
+
server: http://dev.local:9292/faye
|
3
|
+
secret_token: DEVELOPMENT_SECRET_TOKEN
|
4
|
+
signature_expiration: 600
|
5
|
+
production:
|
6
|
+
server: http://example.com/faye
|
7
|
+
secret_token: PRODUCTION_SECRET_TOKEN
|
8
|
+
signature_expiration: 600
|
9
|
+
no_signature_expiration:
|
10
|
+
signature_expiration:
|
@@ -16,7 +16,7 @@ describe PrivatePub::FayeExtension do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "has no error when the signature matches the subscription" do
|
19
|
-
sub = PrivatePub.subscription(:
|
19
|
+
sub = PrivatePub.subscription(:channel => "hello")
|
20
20
|
@message["subscription"] = sub[:channel]
|
21
21
|
@message["ext"]["private_pub_signature"] = sub[:signature]
|
22
22
|
@message["ext"]["private_pub_timestamp"] = sub[:timestamp]
|
@@ -24,8 +24,17 @@ describe PrivatePub::FayeExtension do
|
|
24
24
|
message["error"].should be_nil
|
25
25
|
end
|
26
26
|
|
27
|
+
it "has an error when signature is just expired" do
|
28
|
+
sub = PrivatePub.subscription(:timestamp => 123, :channel => "hello")
|
29
|
+
@message["subscription"] = sub[:channel]
|
30
|
+
@message["ext"]["private_pub_signature"] = sub[:signature]
|
31
|
+
@message["ext"]["private_pub_timestamp"] = sub[:timestamp]
|
32
|
+
message = @faye.incoming(@message, lambda { |m| m })
|
33
|
+
message["error"].should == "Signature has expired."
|
34
|
+
end
|
35
|
+
|
27
36
|
it "has an error when trying to publish to a custom channel with a bad token" do
|
28
|
-
PrivatePub.secret_token = "good"
|
37
|
+
PrivatePub.config[:secret_token] = "good"
|
29
38
|
@message["channel"] = "/custom/channel"
|
30
39
|
@message["ext"]["private_pub_token"] = "bad"
|
31
40
|
message = @faye.incoming(@message, lambda { |m| m })
|
@@ -37,7 +46,7 @@ describe PrivatePub::FayeExtension do
|
|
37
46
|
@message["ext"]["private_pub_token"] = "bad"
|
38
47
|
lambda {
|
39
48
|
message = @faye.incoming(@message, lambda { |m| m })
|
40
|
-
}.should raise_error("No
|
49
|
+
}.should raise_error("No secret_token config set, ensure private_pub.yml is loaded properly.")
|
41
50
|
end
|
42
51
|
|
43
52
|
it "has no error on other meta calls" do
|
data/spec/private_pub_spec.rb
CHANGED
@@ -5,21 +5,12 @@ describe PrivatePub do
|
|
5
5
|
PrivatePub.reset_config
|
6
6
|
end
|
7
7
|
|
8
|
-
it "has secret token, server, and signature expiration settings" do
|
9
|
-
PrivatePub.secret_token = "secret token"
|
10
|
-
PrivatePub.secret_token.should == "secret token"
|
11
|
-
PrivatePub.server = "http://localhost/"
|
12
|
-
PrivatePub.server.should == "http://localhost/"
|
13
|
-
PrivatePub.signature_expiration = 1000
|
14
|
-
PrivatePub.signature_expiration.should == 1000
|
15
|
-
end
|
16
|
-
|
17
8
|
it "defaults server to localhost:9292/faye" do
|
18
|
-
PrivatePub.server.should == "http://localhost:9292/faye"
|
9
|
+
PrivatePub.config[:server].should == "http://localhost:9292/faye"
|
19
10
|
end
|
20
11
|
|
21
12
|
it "defaults signature_expiration to 1 hour" do
|
22
|
-
PrivatePub.signature_expiration.should == 60 * 60
|
13
|
+
PrivatePub.config[:signature_expiration].should == 60 * 60
|
23
14
|
end
|
24
15
|
|
25
16
|
it "defaults subscription timestamp to current time in milliseconds" do
|
@@ -28,6 +19,24 @@ describe PrivatePub do
|
|
28
19
|
PrivatePub.subscription[:timestamp].should == (time.to_f * 1000).round
|
29
20
|
end
|
30
21
|
|
22
|
+
it "loads a simple configuration file via load_config" do
|
23
|
+
PrivatePub.load_config("spec/fixtures/private_pub.yml", "production")
|
24
|
+
PrivatePub.config[:server].should == "http://example.com/faye"
|
25
|
+
PrivatePub.config[:secret_token].should == "PRODUCTION_SECRET_TOKEN"
|
26
|
+
PrivatePub.config[:signature_expiration].should == 600
|
27
|
+
end
|
28
|
+
|
29
|
+
it "supports a nil signature_expiration via a blank value in the configuration file" do
|
30
|
+
PrivatePub.load_config("spec/fixtures/private_pub.yml", :no_signature_expiration)
|
31
|
+
PrivatePub.config[:signature_expiration].should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises an exception if an invalid environment is passed to load_config" do
|
35
|
+
lambda {
|
36
|
+
PrivatePub.load_config("spec/fixtures/private_pub.yml", :test)
|
37
|
+
}.should raise_error ArgumentError
|
38
|
+
end
|
39
|
+
|
31
40
|
it "includes channel and custom time in subscription" do
|
32
41
|
subscription = PrivatePub.subscription(:timestamp => 123, :channel => "hello")
|
33
42
|
subscription[:timestamp].should == 123
|
@@ -35,17 +44,34 @@ describe PrivatePub do
|
|
35
44
|
end
|
36
45
|
|
37
46
|
it "does a sha1 digest of channel, timestamp, and secret token" do
|
38
|
-
PrivatePub.secret_token = "token"
|
47
|
+
PrivatePub.config[:secret_token] = "token"
|
39
48
|
subscription = PrivatePub.subscription(:timestamp => 123, :channel => "channel")
|
40
49
|
subscription[:signature].should == Digest::SHA1.hexdigest("tokenchannel123")
|
41
50
|
end
|
42
51
|
|
43
52
|
it "publishes to server using Net::HTTP" do
|
44
|
-
Net::HTTP.should_receive(:post_form).with(URI.parse(PrivatePub.server), "hello world").and_return(:result)
|
53
|
+
Net::HTTP.should_receive(:post_form).with(URI.parse(PrivatePub.config[:server]), "hello world").and_return(:result)
|
45
54
|
PrivatePub.publish("hello world").should == :result
|
46
55
|
end
|
47
56
|
|
48
57
|
it "has a FayeExtension instance" do
|
49
58
|
PrivatePub.faye_extension.should be_kind_of(PrivatePub::FayeExtension)
|
50
59
|
end
|
60
|
+
|
61
|
+
it "says signature has expired when time passed in is greater than expiration" do
|
62
|
+
PrivatePub.config[:signature_expiration] = 30*60
|
63
|
+
time = PrivatePub.subscription[:timestamp] - 31*60*1000
|
64
|
+
PrivatePub.signature_expired?(time).should be_true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "says signature has not expired when time passed in is less than expiration" do
|
68
|
+
PrivatePub.config[:signature_expiration] = 30*60
|
69
|
+
time = PrivatePub.subscription[:timestamp] - 29*60*1000
|
70
|
+
PrivatePub.signature_expired?(time).should be_false
|
71
|
+
end
|
72
|
+
|
73
|
+
it "says signature has not expired when expiration is nil" do
|
74
|
+
PrivatePub.config[:signature_expiration] = nil
|
75
|
+
PrivatePub.signature_expired?(0).should be_false
|
76
|
+
end
|
51
77
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: private_pub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ryan Bates
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04-
|
13
|
+
date: 2011-04-07 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -36,15 +36,18 @@ files:
|
|
36
36
|
- lib/generators/private_pub/install_generator.rb
|
37
37
|
- lib/generators/private_pub/templates/faye.ru
|
38
38
|
- lib/generators/private_pub/templates/private_pub.js
|
39
|
-
- lib/generators/private_pub/templates/
|
40
|
-
- lib/generators/private_pub/templates/private_pub_initializer.rb
|
39
|
+
- lib/generators/private_pub/templates/private_pub.yml
|
41
40
|
- lib/private_pub/faye_extension.rb
|
41
|
+
- lib/private_pub/railtie.rb
|
42
|
+
- lib/private_pub/view_helpers.rb
|
42
43
|
- lib/private_pub.rb
|
44
|
+
- spec/fixtures/private_pub.yml
|
43
45
|
- spec/private_pub/faye_extension_spec.rb
|
44
46
|
- spec/private_pub_spec.rb
|
45
47
|
- spec/spec_helper.rb
|
46
48
|
- CHANGELOG.rdoc
|
47
49
|
- Gemfile
|
50
|
+
- LICENSE
|
48
51
|
- Rakefile
|
49
52
|
- README.rdoc
|
50
53
|
has_rdoc: true
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module PrivatePubHelper
|
2
|
-
def publish_to(channel, &block)
|
3
|
-
message = {:channel => channel, :data => {:_eval => capture(&block)}, :ext => {:private_pub_token => PrivatePub.secret_token}}
|
4
|
-
PrivatePub.publish(:message => message.to_json)
|
5
|
-
end
|
6
|
-
|
7
|
-
def subscribe_to(channel)
|
8
|
-
subscription = PrivatePub.subscription(:channel => channel)
|
9
|
-
content_tag :span, "", :class => "private_pub_subscription",
|
10
|
-
"data-server" => PrivatePub.server,
|
11
|
-
"data-channel" => subscription[:channel],
|
12
|
-
"data-signature" => subscription[:signature],
|
13
|
-
"data-timestamp" => subscription[:timestamp]
|
14
|
-
end
|
15
|
-
end
|