pubnub-publisher 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea389b2bbe81e52d0c3789f85d8f3f6acce213bc
4
+ data.tar.gz: dd0a6ef4720d420f44748ec81ee78873c5e81399
5
+ SHA512:
6
+ metadata.gz: 683fe19193c0d1b374415cb6e2c119f6fd58d9fda28f054c89b73231852219bb495919265a2e048d8a3d33e8d7b48310b6c2db611952caea9e05fc3222d9740f
7
+ data.tar.gz: 66f62daa6f402c9e0065fa30c8b9103446aa560813dc05cae72ff740db222d35818d467b97641abeab24579fc6866ea9bd98d86d4db9b0d8edf0663f2dd8e272
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pubnub-publisher.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Matt Aimonetti
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,127 @@
1
+ # Pubnub::Publisher
2
+
3
+ This gem is a addon for the official [PubNub's Ruby
4
+ gem](https://github.com/pubnub/ruby). Unlike the official gem, this
5
+ doesn't have any dependencies, it relies entirely on Ruby's stdlib.
6
+
7
+ But unlike the official gem, this gem only provides one pub sub feature:
8
+ publication.
9
+
10
+ Use this library when your Ruby application only publishes events to
11
+ PubNub. For instance you might have a Go/Scala/Node.js app and many JS
12
+ clients listening on a few channels. But you need to broadcast a
13
+ message and want to do that after a trigger in your Rails app.
14
+ The cleanest way to do that is to use this gem to simply publish the
15
+ message and disconnect. This is done via PubNub's REST API.
16
+
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ gem 'pubnub-publisher'
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install pubnub-publisher
31
+
32
+ ## Usage
33
+
34
+ Look at the test suite in the spec folder for more details.
35
+ The easiest way to use this library is to register a shared config at
36
+ the class level:
37
+
38
+ ```ruby
39
+ Pubnub::Publisher.setup(publish_key: "your pub key", subscribe_key: "your sub key")
40
+ ```
41
+
42
+ Note: I don't quite understand why Pubnub requires a subscribe key to
43
+ publish but you need to provide it otherwise the API call will fail.
44
+
45
+ You can set the following shared config keys:
46
+
47
+ * publish_key
48
+ * subscribe_key
49
+ * secret_key
50
+ * cipher_key
51
+ * origin (defaults to "pubsub.pubnub.com")
52
+ * ssl (defaults to true)
53
+ * session_uuid (randomly generated if you don't provide one)
54
+
55
+ Once you have the shared config setup, you can create an instance which
56
+ will use the default config unless instructed differently:
57
+
58
+ ```ruby
59
+ pub_client = Pubnub::Publisher.new
60
+ ```
61
+
62
+ You can override any of the shared config an instantiation or by using
63
+ the accessors:
64
+
65
+ ```ruby
66
+ pub_client = Pubnub::Publisher.new(publish_key: "demo_pub_key", subscribe_key: "demo_sub_key", origin: "demo.pubnub.com")
67
+ ```
68
+
69
+ or
70
+
71
+ ```ruby
72
+ pub_client = Pubnub::Publisher.new
73
+ pub_client.session_uuid = "ruby-app"
74
+ ```
75
+
76
+ To publish a message, you call the `#publish` method passing the
77
+ channel name and a data structure that will be passed as a json.
78
+
79
+ ```ruby
80
+ pub_client = Pubnub::Publisher.new
81
+ pub_client.publish("test", {text: "Hi there, this is Matt"})
82
+ ```
83
+
84
+ The publication is currently blocking and will return a boolean value
85
+ so you can handle retries on your own.
86
+ Eventually, publication might have an option to happen via a thread pool
87
+ and callbacks. I would also like to persist the http connection to
88
+ improve performance.
89
+
90
+ ```ruby
91
+ if pub_client.publish("test", {text: "Hi there, this is Matt"})
92
+ Rails.logger.info "The Pubnub publishing was successful sir!"
93
+ else
94
+ Rails.logger.error "Something went bad with PubNub :( #wasntme"
95
+ end
96
+ ```
97
+
98
+ ## TODOs
99
+
100
+ * Use a thread pool to go non blocking publishing.
101
+ * use a persistent http connection to pubnub.
102
+
103
+
104
+ ## Test suite
105
+
106
+ The test suite is a simple Rspec test suite, with 1 specificity: the
107
+ "integration" tag. By default, when you run the specs, the test suite
108
+ will connect to PubNub to verify that things work well. You can turn
109
+ off the integration specs by excluding them:
110
+
111
+ ```
112
+ $ rspec . --tag ~integration
113
+ ```
114
+
115
+ To run the full test suite:
116
+
117
+ ```
118
+ $ rake
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ 1. Fork it
124
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
125
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
126
+ 4. Push to the branch (`git push origin my-new-feature`)
127
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.rspec_opts = "--format documentation"
6
+ end
7
+
8
+ task :default => :spec
@@ -0,0 +1,116 @@
1
+ require "pubnub/publisher/version"
2
+
3
+ module Pubnub
4
+ class Publisher
5
+
6
+ CONFIG_KEYS = [:publish_key, :subscribe_key, :secret_key, :cipher_key, :ssl, :origin, :session_uuid]
7
+ REQUIRED_KEYS = [:publish_key, :subscribe_key, :origin]
8
+ DEFAULT_ORIGIN = "pubsub.pubnub.com"
9
+ attr_accessor *CONFIG_KEYS
10
+
11
+ class ConfigNotSet < StandardError; end
12
+
13
+ # sets up the class so instances can inherit from the default config.
14
+ #
15
+ # @param opts [hash] keyed by symbols, stores the connection config that is
16
+ # then used by default by all instances.
17
+ def self.setup(opts={})
18
+ @publish_key = opts[:publish_key] if opts[:publish_key]
19
+ @subscribe_key = opts[:subscribe_key] if opts[:subscribe_key]
20
+ @secret_key = opts[:secret_key] if opts[:secret_key]
21
+ @cipher_key = opts[:cipher_key] if opts[:cipher_key]
22
+ @origin = opts[:origin] || DEFAULT_ORIGIN
23
+ @session_uuid = opts[:session_uuid] || SecureRandom.uuid
24
+ @ssl = opts[:ssl].nil? ? true : opts[:ssl]
25
+ end
26
+
27
+ # resets the shared config
28
+ def self.clear
29
+ @publish_key, @subscribe_key, @secret_key, @cipher_key, @origin, @session_uuid, @ssl = nil, nil, nil, nil, "pubsub.pubnub.com", nil, true
30
+ end
31
+
32
+ def self.set_default_values(instance)
33
+ instance.publish_key ||= @publish_key if @publish_key
34
+ instance.subscribe_key ||= @subscribe_key if @subscribe_key
35
+ instance.secret_key ||= @secret_key if @secret_key
36
+ instance.cipher_key ||= @cipher_key if @cipher_key
37
+ instance.origin ||= (@origin || DEFAULT_ORIGIN)
38
+ instance.session_uuid ||= (@session_uuid || SecureRandom.uuid)
39
+ if instance.ssl.nil?
40
+ instance.ssl = !@ssl.nil? ? @ssl : true
41
+ end
42
+ instance
43
+ end
44
+
45
+ def initialize(opts={})
46
+ opts.each do |k,v|
47
+ next unless CONFIG_KEYS.include?(k)
48
+ self.send("#{k}=", v)
49
+ end
50
+ # load the default values
51
+ self.class.set_default_values(self)
52
+ self
53
+ end
54
+
55
+ def publish(channel, message)
56
+ check_config
57
+ http, request = prepare_message_publishing(channel, message)
58
+ response = http.request(request)
59
+ if response.code == "200"
60
+ # check response
61
+ # [1 good!
62
+ # [0 bad!
63
+ if response.body =~ /\[1,/
64
+ true
65
+ else
66
+ $stderr << response.body[/\[\d,"(.*)"/]
67
+ false
68
+ end
69
+ else
70
+ $stderr << response.inspect
71
+ false
72
+ end
73
+ end
74
+
75
+ def check_config
76
+ if @config_ok
77
+ true
78
+ else
79
+ REQUIRED_KEYS.each do |k|
80
+ value = self.send(k)
81
+ raise ConfigNotSet.new("#{k} not set") if value.nil? || value == ""
82
+ end
83
+ @config_ok = true
84
+ end
85
+ end
86
+
87
+ #http://pubsub.pubnub.com
88
+ # /publish
89
+ # /pub-key
90
+ # /sub-key
91
+ # /signature
92
+ # /channel
93
+ # /callback
94
+ def publish_url(channel)
95
+ (ssl ? "https" : "http") << "://#{origin}/publish/#{publish_key}/#{subscribe_key}/#{secret_key || 0}/#{channel}/0"
96
+ end
97
+
98
+ def prepare_message_publishing(channel, message)
99
+ raise ArgumentError if (channel.nil? || channel == "" || message.nil? || message == "")
100
+
101
+ # prepare a GET request (come on pubnub, GET???)
102
+ url = publish_url(channel) << "/#{URI.escape(message.to_json)}"
103
+ uri = URI.parse(url)
104
+ http = Net::HTTP.new(uri.host, uri.port)
105
+
106
+ # gonna have to deal with certs
107
+ if ssl
108
+ http.use_ssl = true
109
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
110
+ end
111
+ request = Net::HTTP::Get.new(uri.request_uri)
112
+ return http, request
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,12 @@
1
+ require "base64"
2
+ require "net/https"
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+ require "securerandom"
7
+
8
+ module Pubnub
9
+ class Publisher
10
+ VERSION = "1.0.0"
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pubnub/publisher/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pubnub-publisher"
8
+ spec.version = Pubnub::Publisher::VERSION
9
+ spec.authors = ["Matt Aimonetti"]
10
+ spec.email = ["mattaimonetti@gmail.com"]
11
+ spec.description = %q{The simplest PubNub gem possible to simply publish events. Nothing more.}
12
+ spec.summary = %q{Because when you only care to publish events, you don't want to load a bunch of unneeded dependencies.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+
3
+ describe Pubnub::Publisher do
4
+ context "Class setup" do
5
+
6
+ it "has default values" do
7
+ pub_client = Pubnub::Publisher.new
8
+ expect(pub_client.publish_key).to be_nil
9
+ expect(pub_client.subscribe_key).to be_nil
10
+ expect(pub_client.secret_key).to be_nil
11
+ expect(pub_client.cipher_key).to be_nil
12
+ expect(pub_client.origin).to eq("pubsub.pubnub.com")
13
+ expect(pub_client.session_uuid).to_not be_empty
14
+ expect(pub_client.ssl).to be_true
15
+ end
16
+
17
+ it "allows a dev to set some shared config options" do
18
+ Pubnub::Publisher.setup(publish_key: "test pub key")
19
+ pub_client = Pubnub::Publisher.new
20
+ expect(pub_client.publish_key).to eq("test pub key")
21
+
22
+ Pubnub::Publisher.setup(subscribe_key: "test sub key")
23
+ pub_client = Pubnub::Publisher.new
24
+ expect(pub_client.subscribe_key).to eq("test sub key")
25
+
26
+ Pubnub::Publisher.setup(secret_key: "test secret key")
27
+ pub_client = Pubnub::Publisher.new
28
+ expect(pub_client.secret_key).to eq("test secret key")
29
+
30
+ Pubnub::Publisher.setup(cipher_key: "test cipher key")
31
+ pub_client = Pubnub::Publisher.new
32
+ expect(pub_client.cipher_key).to eq("test cipher key")
33
+
34
+ Pubnub::Publisher.setup(origin: "matt.pubnub.com")
35
+ pub_client = Pubnub::Publisher.new
36
+ expect(pub_client.origin).to eq("matt.pubnub.com")
37
+
38
+ Pubnub::Publisher.setup(session_uuid: "test-runner")
39
+ pub_client = Pubnub::Publisher.new
40
+ expect(pub_client.session_uuid).to eq("test-runner")
41
+
42
+ Pubnub::Publisher.setup(ssl: false)
43
+ pub_client = Pubnub::Publisher.new
44
+ expect(pub_client.ssl).to be_false
45
+ end
46
+
47
+ it "can be cleared" do
48
+ Pubnub::Publisher.clear
49
+ pub_client = Pubnub::Publisher.new
50
+ expect(pub_client.publish_key).to be_nil
51
+ expect(pub_client.subscribe_key).to be_nil
52
+ expect(pub_client.secret_key).to be_nil
53
+ expect(pub_client.cipher_key).to be_nil
54
+ expect(pub_client.origin).to eq("pubsub.pubnub.com")
55
+ expect(pub_client.session_uuid).to_not be_empty
56
+ expect(pub_client.ssl).to be_true
57
+ end
58
+
59
+ end
60
+
61
+ context "new instance" do
62
+ before :each do
63
+ Pubnub::Publisher.clear
64
+ end
65
+
66
+ it "can have custom config values" do
67
+ pub_client = Pubnub::Publisher.new(publish_key: "test pub key")
68
+ expect(pub_client.publish_key).to eq("test pub key")
69
+
70
+ pub_client = Pubnub::Publisher.new(subscribe_key: "test sub key")
71
+ expect(pub_client.subscribe_key).to eq("test sub key")
72
+
73
+ pub_client = Pubnub::Publisher.new(secret_key: "test secret key")
74
+ expect(pub_client.secret_key).to eq("test secret key")
75
+
76
+ pub_client = Pubnub::Publisher.new(cipher_key: "test cipher key")
77
+ expect(pub_client.cipher_key).to eq("test cipher key")
78
+
79
+ pub_client = Pubnub::Publisher.new(origin: "matt.pubnub.com")
80
+ expect(pub_client.origin).to eq("matt.pubnub.com")
81
+
82
+ pub_client = Pubnub::Publisher.new(session_uuid: "test-instance-runner")
83
+ expect(pub_client.session_uuid).to eq("test-instance-runner")
84
+
85
+ pub_client = Pubnub::Publisher.new(ssl: false)
86
+ expect(pub_client.ssl).to be_false
87
+ end
88
+
89
+ it "can be verified (check that required fields are set)" do
90
+ pub_client = Pubnub::Publisher.new
91
+ expect(pub_client.publish_key).to be_nil
92
+ expect{ pub_client.check_config }.to raise_error(Pubnub::Publisher::ConfigNotSet)
93
+
94
+ valid_config = {publish_key: "test", subscribe_key: "test", origin: "test.pubnub.com"}
95
+ expect{ Pubnub::Publisher.new(valid_config).check_config }.to_not raise_error(Pubnub::Publisher::ConfigNotSet)
96
+ without_pub_key = valid_config.dup
97
+ without_pub_key.delete(:publish_key)
98
+ expect{ Pubnub::Publisher.new(without_pub_key).check_config }.to raise_error(Pubnub::Publisher::ConfigNotSet)
99
+ without_sub_key = valid_config.dup
100
+ without_sub_key.delete(:subscribe_key)
101
+ expect{ Pubnub::Publisher.new(without_sub_key).check_config }.to raise_error(Pubnub::Publisher::ConfigNotSet)
102
+ without_origin = valid_config.dup
103
+ without_origin[:origin] = ""
104
+ expect{ Pubnub::Publisher.new(without_origin).check_config }.to raise_error(Pubnub::Publisher::ConfigNotSet)
105
+ end
106
+
107
+ it "has a publish url for a given channel" do
108
+ pub_client = Pubnub::Publisher.new(publish_key: "demo_pub_key", subscribe_key: "demo_sub_key", origin: "demo.pubnub.com")
109
+ expect(pub_client.publish_url("mychannel")).to eq("https://demo.pubnub.com/publish/demo_pub_key/demo_sub_key/0/mychannel/0")
110
+ end
111
+
112
+ it "can prepare a http request to publish a message" do
113
+ pub_client = Pubnub::Publisher.new(publish_key: "demo_pub_key", subscribe_key: "demo_sub_key", origin: "demo.pubnub.com")
114
+ http, request = pub_client.prepare_message_publishing("mychannel", {text: "hey"})
115
+ expect(http.address).to eq("demo.pubnub.com")
116
+ expect(http.use_ssl?).to be_true
117
+ expect(http.port).to eq(443)
118
+ expect(request.path).to eq("/publish/demo_pub_key/demo_sub_key/0/mychannel/0/%7B%22text%22:%22hey%22%7D")
119
+ expect(request).to be_instance_of(Net::HTTP::Get)
120
+ end
121
+
122
+ it "successfully publishes messages", integration: true do
123
+ pub_client = Pubnub::Publisher.new(publish_key: "demo", subscribe_key: "demo")
124
+ output = pub_client.publish("test", {text: "test from PubNub Publisher's Ruby gem"})
125
+ expect(output).to be_true
126
+ end
127
+
128
+ it "handles messages which failed to publish", integration: true do
129
+ pub_client = Pubnub::Publisher.new(publish_key: "bad-demo", subscribe_key: "demo")
130
+ output = pub_client.publish("test", {text: "test from PubNub Publisher's Ruby gem"})
131
+ expect(output).to be_false
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,2 @@
1
+ require_relative "../lib/pubnub/publisher"
2
+ require 'rspec/autorun'
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pubnub-publisher
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Aimonetti
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
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
+ description: The simplest PubNub gem possible to simply publish events. Nothing more.
56
+ email:
57
+ - mattaimonetti@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/pubnub/publisher.rb
68
+ - lib/pubnub/publisher/version.rb
69
+ - pubnub-publisher.gemspec
70
+ - spec/publisher_spec.rb
71
+ - spec/spec_helper.rb
72
+ homepage: ''
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.0.3
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Because when you only care to publish events, you don't want to load a bunch
96
+ of unneeded dependencies.
97
+ test_files:
98
+ - spec/publisher_spec.rb
99
+ - spec/spec_helper.rb