shove 0.4 → 0.6.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/.gitignore +3 -0
- data/README.md +23 -7
- data/bin/shove +8 -2
- data/lib/shove/client.rb +19 -13
- data/lib/shove/request.rb +60 -15
- data/lib/shove/response.rb +11 -0
- data/lib/shove.rb +34 -17
- data/shove.gemspec +9 -17
- data/spec/shove_spec.rb +35 -2
- metadata +22 -27
data/.gitignore
ADDED
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
gem install shove
|
8
8
|
|
9
9
|
##Install Step 2
|
10
|
-
Grab your network id and API key from shove at [http://shove.io/customer/network/api_access]
|
10
|
+
Grab your network id and API key from shove at [http://shove.io/customer/network/api_access#ruby][0]
|
11
11
|
|
12
12
|
##Install Step 3
|
13
13
|
Configure shover with your credentials
|
@@ -20,7 +20,7 @@
|
|
20
20
|
:cluster => "cluster"
|
21
21
|
)
|
22
22
|
|
23
|
-
##
|
23
|
+
##Broadcasting
|
24
24
|
|
25
25
|
# broadcast the "hello" event on the "default" channel with
|
26
26
|
# Hello World! as the data
|
@@ -30,18 +30,32 @@
|
|
30
30
|
puts response.message
|
31
31
|
end
|
32
32
|
|
33
|
-
##
|
33
|
+
##Send direct messages
|
34
34
|
|
35
35
|
Shove.direct(userid, "hello", "Hello World!") do |response|
|
36
36
|
# handle response
|
37
37
|
end
|
38
38
|
|
39
|
-
##
|
39
|
+
##Subscription Authorization
|
40
40
|
|
41
41
|
# authorize user with id userid on channel "default"
|
42
42
|
Shove.authorize(userid, "default") do |response|
|
43
43
|
# handle response
|
44
44
|
end
|
45
|
+
|
46
|
+
##Channel Streaming
|
47
|
+
|
48
|
+
# stream all data on channel "default"
|
49
|
+
Shove.stream("default") do |msg|
|
50
|
+
|
51
|
+
# msg has several properties
|
52
|
+
puts msg[:channel]
|
53
|
+
puts msg[:event]
|
54
|
+
puts msg[:to] # this will either be empty or self
|
55
|
+
puts msg[:from] # message sender
|
56
|
+
puts msg[:data] # the payload
|
57
|
+
|
58
|
+
end
|
45
59
|
|
46
60
|
##Block and Non-blocking
|
47
61
|
shover does both. If the shover code happens to run inside of an EM.run block, the HTTP calls
|
@@ -50,6 +64,8 @@
|
|
50
64
|
|
51
65
|
##CLI (Command line interface)
|
52
66
|
The shove gem comes with a command line tool for controlling the network.
|
53
|
-
View documentation @ [http://shove.io/documentation/cli]
|
54
|
-
|
55
|
-
|
67
|
+
View documentation @ [http://shove.io/documentation/cli][1]
|
68
|
+
|
69
|
+
|
70
|
+
[0]: http://shove.io/customer/network/api_access
|
71
|
+
[1]: http://shove.io/documentation/cli
|
data/bin/shove
CHANGED
@@ -16,7 +16,6 @@ unless FileTest.exist?(ymlpath)
|
|
16
16
|
say "Please enter your network information."
|
17
17
|
say "Visit http://shove.io/customer/network/api_access for more info."
|
18
18
|
|
19
|
-
access[:cluster] = ask "Enter Cluster Group: "
|
20
19
|
access[:network] = ask "Enter Network Id: "
|
21
20
|
access[:key] = ask "Enter Network Key: "
|
22
21
|
|
@@ -56,7 +55,14 @@ command :stream do |c|
|
|
56
55
|
say_invalid c
|
57
56
|
else
|
58
57
|
EM.run do
|
59
|
-
Shove.stream(args.first) { |m|
|
58
|
+
Shove.stream(args.first) { |m|
|
59
|
+
puts m[:channel]
|
60
|
+
puts m[:event]
|
61
|
+
puts m[:to] # this will either be empty or self
|
62
|
+
puts m[:from] # message sender
|
63
|
+
puts m[:data] # the payload
|
64
|
+
puts "============"
|
65
|
+
}
|
60
66
|
end
|
61
67
|
end
|
62
68
|
end
|
data/lib/shove/client.rb
CHANGED
@@ -6,14 +6,12 @@ module Shove
|
|
6
6
|
# +key+ the api access key
|
7
7
|
# +opts+ hash with a few options, such as:
|
8
8
|
# :secure true or false
|
9
|
-
# :host leave as default unless you
|
10
|
-
def initialize
|
11
|
-
@network = network
|
12
|
-
@cluster = opts[:cluster] || "a04"
|
13
|
-
@key = key
|
14
|
-
@auth_header = { "api-key" => key }
|
9
|
+
# :host leave as default unless you have a dedicated cluster
|
10
|
+
def initialize opts={}
|
11
|
+
@network = opts[:network]
|
15
12
|
@secure = opts[:secure] || false
|
16
|
-
@host = opts[:host] || "api
|
13
|
+
@host = opts[:host] || "api.shove.io"
|
14
|
+
@port = opts[:port] || (@secure ? 443 : 80)
|
17
15
|
end
|
18
16
|
|
19
17
|
# broadcast a message
|
@@ -21,7 +19,7 @@ module Shove
|
|
21
19
|
# +event+ the event to trigger
|
22
20
|
# +message+ the message to send, UTF-8 encoded kthx
|
23
21
|
def broadcast channel, event, message, &block
|
24
|
-
Request.new("#{uri}
|
22
|
+
Request.new("#{uri}/broadcast/#{channel}/#{event}").post(message, &block)
|
25
23
|
end
|
26
24
|
|
27
25
|
# direct a message to a specific user
|
@@ -29,27 +27,35 @@ module Shove
|
|
29
27
|
# +event+ the event to trigger
|
30
28
|
# +message+ the message to send, UTF-8 encoded kthx
|
31
29
|
def direct uid, event, message, &block
|
32
|
-
Request.new("#{uri}
|
30
|
+
Request.new("#{uri}/direct/#{event}/#{uid}").post(message, &block)
|
33
31
|
end
|
34
32
|
|
35
33
|
# authorize a user on a private channel
|
36
34
|
# +uid+ the users id
|
37
35
|
# +channel+ the channel to authorize them on
|
38
36
|
def authorize uid, channel="*", &block
|
39
|
-
Request.new("#{uri}
|
37
|
+
Request.new("#{uri}/authorize/#{channel}/#{uid}").post(&block)
|
40
38
|
end
|
41
39
|
|
40
|
+
# validate current API settings
|
42
41
|
def validate
|
43
|
-
Request.new("#{uri}
|
42
|
+
Request.new("#{uri}/validate").post do |response|
|
44
43
|
return response
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
47
|
+
# fetch a list of hosts for streaming websockets and comet
|
48
|
+
def hosts
|
49
|
+
Request.new("#{uri}/hosts").get do |response|
|
50
|
+
return response
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
48
54
|
protected
|
49
55
|
|
50
56
|
def uri
|
51
|
-
(@secure ? "https" : "http") + "://#{@host}"
|
57
|
+
(@secure ? "https" : "http") + "://#{@host}:#{@port}/#{@network}"
|
52
58
|
end
|
53
59
|
|
54
60
|
end
|
55
|
-
end
|
61
|
+
end
|
data/lib/shove/request.rb
CHANGED
@@ -1,33 +1,78 @@
|
|
1
1
|
module Shove
|
2
2
|
class Request
|
3
3
|
|
4
|
+
include EventMachine::HttpEncoding
|
5
|
+
|
4
6
|
attr_accessor :url, :headers
|
5
7
|
|
6
8
|
def initialize url, headers={}
|
7
9
|
self.url = url
|
8
|
-
self.headers = headers
|
10
|
+
self.headers = headers.merge({
|
11
|
+
"api-key" => Shove.config[:key]
|
12
|
+
})
|
13
|
+
end
|
14
|
+
|
15
|
+
# HTTP Delete request
|
16
|
+
def delete &block
|
17
|
+
exec :delete, &block
|
18
|
+
end
|
19
|
+
|
20
|
+
# HTTP Post request for new content
|
21
|
+
def post params={}, &block
|
22
|
+
exec :post, params, &block
|
23
|
+
end
|
24
|
+
|
25
|
+
# HTTP Put request for updates
|
26
|
+
def put params={}, &block
|
27
|
+
exec :put, params, &block
|
28
|
+
end
|
29
|
+
|
30
|
+
# HTTP Get request
|
31
|
+
def get &block
|
32
|
+
exec :get, &block
|
9
33
|
end
|
10
34
|
|
11
|
-
|
35
|
+
private
|
36
|
+
|
37
|
+
# exec a HTTP request, and callback with
|
38
|
+
# a response via block
|
39
|
+
def exec method, params={}, &block
|
40
|
+
|
41
|
+
# run async so we don't block if EM is running
|
12
42
|
if EM.reactor_running?
|
13
|
-
http = EventMachine::HttpRequest.new(url).
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
43
|
+
http = EventMachine::HttpRequest.new(url).send(method, {
|
44
|
+
:body => params,
|
45
|
+
:head => headers
|
46
|
+
})
|
47
|
+
|
48
|
+
# handle error
|
49
|
+
http.errback {
|
50
|
+
block.call(Response.new(http.response_header.status, http.response, true)) if block_given?
|
51
|
+
}
|
52
|
+
|
53
|
+
# handle success
|
54
|
+
http.callback {
|
55
|
+
status = http.response_header.status
|
56
|
+
block.call(Response.new(status, http.response, status >= 400)) if block_given?
|
57
|
+
}
|
58
|
+
|
59
|
+
# fallback to standard lib for http
|
22
60
|
else
|
23
61
|
uri = URI.parse(url)
|
24
|
-
|
25
|
-
|
26
|
-
|
62
|
+
case method
|
63
|
+
when :post, :put
|
64
|
+
res = Net::HTTP.new(uri.host, uri.port).send(method, uri.path, normalize_body(params), headers)
|
65
|
+
when :get, :delete
|
66
|
+
res = Net::HTTP.new(uri.host, uri.port).send(method, uri.path, headers)
|
27
67
|
end
|
68
|
+
block.call(Response.new(res.code, res.body, res.code.to_i >= 400)) if block_given?
|
28
69
|
end
|
29
70
|
end
|
30
|
-
|
71
|
+
|
72
|
+
def normalize_body(body)
|
73
|
+
body.is_a?(Hash) ? form_encode_body(body) : body
|
74
|
+
end
|
75
|
+
|
31
76
|
end
|
32
77
|
end
|
33
78
|
|
data/lib/shove/response.rb
CHANGED
@@ -9,9 +9,20 @@ module Shove
|
|
9
9
|
self.error = error
|
10
10
|
end
|
11
11
|
|
12
|
+
# was there an error with the request?
|
12
13
|
def error?
|
13
14
|
error
|
14
15
|
end
|
16
|
+
|
17
|
+
# parse a json response
|
18
|
+
def parse
|
19
|
+
@parsed ||= Yajl::Parser.new(:symbolize_keys => true).parse(message)
|
20
|
+
end
|
21
|
+
|
22
|
+
# alias parse
|
23
|
+
def to_hash
|
24
|
+
parse
|
25
|
+
end
|
15
26
|
|
16
27
|
end
|
17
28
|
end
|
data/lib/shove.rb
CHANGED
@@ -3,15 +3,18 @@ $:.unshift File.dirname(__FILE__)
|
|
3
3
|
require "rubygems"
|
4
4
|
require "net/http"
|
5
5
|
require "em-http-request"
|
6
|
+
require "yajl"
|
6
7
|
require "yaml"
|
7
8
|
|
8
9
|
##
|
9
10
|
# Shove
|
10
11
|
#
|
11
|
-
# See http://shove.io for an account
|
12
|
+
# See http://shove.io for an account and client documentation
|
13
|
+
# See https://github.com/shove/shover for gem documentation
|
14
|
+
# See https://github.com/shove/shove for client documentation
|
12
15
|
module Shove
|
13
16
|
|
14
|
-
Version = 0.
|
17
|
+
Version = 0.60
|
15
18
|
|
16
19
|
class << self
|
17
20
|
|
@@ -21,22 +24,16 @@ module Shove
|
|
21
24
|
# +settings+ the settings for the created client as
|
22
25
|
# a string for a yaml file, or as a hash
|
23
26
|
def configure settings
|
24
|
-
|
25
27
|
if settings.kind_of? String
|
26
28
|
self.config = YAML.load_file(settings)
|
29
|
+
self.config
|
27
30
|
elsif settings.kind_of? Hash
|
28
31
|
self.config = settings
|
29
32
|
else
|
30
33
|
raise "Unsupported configuration type"
|
31
34
|
end
|
32
|
-
|
33
|
-
|
34
|
-
# self.config = {}
|
35
|
-
# tmp.each_pair do |k,v|
|
36
|
-
# self.config[k.to_sym] = v
|
37
|
-
# end
|
38
|
-
|
39
|
-
self.client = Client.new config[:network], config[:key], config
|
35
|
+
|
36
|
+
self.client = Client.new(config)
|
40
37
|
end
|
41
38
|
|
42
39
|
# broadcast a message
|
@@ -67,18 +64,32 @@ module Shove
|
|
67
64
|
def validate
|
68
65
|
client.validate
|
69
66
|
end
|
70
|
-
|
67
|
+
|
68
|
+
# fetch the available stream hosts
|
69
|
+
# for this network.
|
70
|
+
def hosts
|
71
|
+
client.hosts
|
72
|
+
end
|
73
|
+
|
71
74
|
# act as a stream client. requires EM
|
72
75
|
# +channel+ the channel to stream
|
73
76
|
def stream channel, &block
|
74
77
|
|
75
78
|
unless EM.reactor_running?
|
76
|
-
|
79
|
+
puts "You can stream when running in an Eventmachine event loop. EM.run { #code here }"
|
80
|
+
exit
|
77
81
|
end
|
78
82
|
|
79
|
-
|
83
|
+
## Fetch hosts
|
84
|
+
hostnames = hosts
|
85
|
+
|
86
|
+
if hostnames.empty?
|
87
|
+
puts "Error fetching hosts for network #{config[:network]}"
|
88
|
+
exit
|
89
|
+
end
|
80
90
|
|
81
|
-
|
91
|
+
uid = ""
|
92
|
+
http = EventMachine::HttpRequest.new("ws://ws-#{hostnames.first}.shove.io/#{config[:network]}").get :timeout => 0
|
82
93
|
|
83
94
|
http.errback {
|
84
95
|
block.call("Connection Error")
|
@@ -90,7 +101,7 @@ module Shove
|
|
90
101
|
}
|
91
102
|
|
92
103
|
http.stream { |msg|
|
93
|
-
|
104
|
+
|
94
105
|
parts = msg.split "!"
|
95
106
|
|
96
107
|
case parts[1]
|
@@ -100,7 +111,13 @@ module Shove
|
|
100
111
|
Shove.authorize uid, channel
|
101
112
|
end
|
102
113
|
|
103
|
-
block.call(
|
114
|
+
block.call({
|
115
|
+
:channel => parts[0],
|
116
|
+
:event => parts[1],
|
117
|
+
:to => parts[2],
|
118
|
+
:from => parts[3],
|
119
|
+
:data => parts[4]
|
120
|
+
})
|
104
121
|
}
|
105
122
|
|
106
123
|
end
|
data/shove.gemspec
CHANGED
@@ -1,31 +1,23 @@
|
|
1
1
|
spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "shove"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "
|
3
|
+
s.version = "0.6.0"
|
4
|
+
s.date = "2011-07-23"
|
5
5
|
s.summary = "Ruby gem for leveraging shove.io, the web push platform"
|
6
6
|
s.email = "dan@shove.io"
|
7
7
|
s.homepage = "https://github.com/shove/shover"
|
8
8
|
s.description = "Client side implementation for the shove.io API. See http://shove.io/documentation"
|
9
9
|
s.has_rdoc = true
|
10
10
|
|
11
|
-
s.add_dependency("em-http-request", "
|
11
|
+
s.add_dependency("em-http-request", "= 0.3.0")
|
12
12
|
s.add_dependency("commander", ">= 4.0.3")
|
13
|
+
s.add_dependency("yajl-ruby", ">= 0.8.1")
|
13
14
|
|
14
15
|
s.bindir = "bin"
|
15
|
-
|
16
|
-
|
16
|
+
|
17
17
|
s.authors = ["Dan Simpson"]
|
18
18
|
|
19
|
-
s.files =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"spec/helper.rb",
|
24
|
-
"spec/shove_spec.rb",
|
25
|
-
"lib/shove.rb",
|
26
|
-
"lib/shove/request.rb",
|
27
|
-
"lib/shove/response.rb",
|
28
|
-
"lib/shove/client.rb",
|
29
|
-
"bin/shove"
|
30
|
-
]
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
|
31
23
|
end
|
data/spec/shove_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + "/helper"
|
|
3
3
|
describe Shove do
|
4
4
|
|
5
5
|
before do
|
6
|
-
Shove.configure "
|
6
|
+
Shove.configure "shove.yml"
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should have a version" do
|
@@ -11,7 +11,40 @@ describe Shove do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should have config" do
|
14
|
-
Shove.config[
|
14
|
+
Shove.config[:network].should == "test"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to authorize with the server" do
|
18
|
+
response = Shove.validate
|
19
|
+
response.error?.should == false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should get a set of hosts for the network" do
|
23
|
+
response = Shove.hosts
|
24
|
+
response.status.should == 200
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to broadcast a message" do
|
28
|
+
Shove.broadcast("default", "event", "test") do |response|
|
29
|
+
response.error?.should == false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be able to broadcast a message with EM" do
|
34
|
+
EM.run do
|
35
|
+
|
36
|
+
##
|
37
|
+
# Setup stream and capture for validation
|
38
|
+
##
|
39
|
+
|
40
|
+
Shove.broadcast("default", "event", "test2") do |response|
|
41
|
+
response.error?.should == false
|
42
|
+
end
|
43
|
+
|
44
|
+
EM.add_timer(0.2) do
|
45
|
+
EM.stop
|
46
|
+
end
|
47
|
+
end
|
15
48
|
end
|
16
49
|
|
17
50
|
end
|
metadata
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shove
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 4
|
8
|
-
version: "0.4"
|
4
|
+
prerelease:
|
5
|
+
version: 0.6.0
|
9
6
|
platform: ruby
|
10
7
|
authors:
|
11
8
|
- Dan Simpson
|
@@ -13,8 +10,7 @@ autorequire:
|
|
13
10
|
bindir: bin
|
14
11
|
cert_chain: []
|
15
12
|
|
16
|
-
date:
|
17
|
-
default_executable:
|
13
|
+
date: 2011-07-23 00:00:00 Z
|
18
14
|
dependencies:
|
19
15
|
- !ruby/object:Gem::Dependency
|
20
16
|
name: em-http-request
|
@@ -22,12 +18,8 @@ dependencies:
|
|
22
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
19
|
none: false
|
24
20
|
requirements:
|
25
|
-
- - "
|
21
|
+
- - "="
|
26
22
|
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 0
|
29
|
-
- 3
|
30
|
-
- 0
|
31
23
|
version: 0.3.0
|
32
24
|
type: :runtime
|
33
25
|
version_requirements: *id001
|
@@ -39,13 +31,20 @@ dependencies:
|
|
39
31
|
requirements:
|
40
32
|
- - ">="
|
41
33
|
- !ruby/object:Gem::Version
|
42
|
-
segments:
|
43
|
-
- 4
|
44
|
-
- 0
|
45
|
-
- 3
|
46
34
|
version: 4.0.3
|
47
35
|
type: :runtime
|
48
36
|
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: yajl-ruby
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.8.1
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
49
48
|
description: Client side implementation for the shove.io API. See http://shove.io/documentation
|
50
49
|
email: dan@shove.io
|
51
50
|
executables:
|
@@ -55,17 +54,17 @@ extensions: []
|
|
55
54
|
extra_rdoc_files: []
|
56
55
|
|
57
56
|
files:
|
57
|
+
- .gitignore
|
58
58
|
- README.md
|
59
|
-
- shove.gemspec
|
60
59
|
- Rakefile
|
61
|
-
-
|
62
|
-
- spec/shove_spec.rb
|
60
|
+
- bin/shove
|
63
61
|
- lib/shove.rb
|
62
|
+
- lib/shove/client.rb
|
64
63
|
- lib/shove/request.rb
|
65
64
|
- lib/shove/response.rb
|
66
|
-
-
|
67
|
-
-
|
68
|
-
|
65
|
+
- shove.gemspec
|
66
|
+
- spec/helper.rb
|
67
|
+
- spec/shove_spec.rb
|
69
68
|
homepage: https://github.com/shove/shover
|
70
69
|
licenses: []
|
71
70
|
|
@@ -79,21 +78,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
78
|
requirements:
|
80
79
|
- - ">="
|
81
80
|
- !ruby/object:Gem::Version
|
82
|
-
segments:
|
83
|
-
- 0
|
84
81
|
version: "0"
|
85
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
83
|
none: false
|
87
84
|
requirements:
|
88
85
|
- - ">="
|
89
86
|
- !ruby/object:Gem::Version
|
90
|
-
segments:
|
91
|
-
- 0
|
92
87
|
version: "0"
|
93
88
|
requirements: []
|
94
89
|
|
95
90
|
rubyforge_project:
|
96
|
-
rubygems_version: 1.3
|
91
|
+
rubygems_version: 1.8.3
|
97
92
|
signing_key:
|
98
93
|
specification_version: 3
|
99
94
|
summary: Ruby gem for leveraging shove.io, the web push platform
|