shove 1.0.7 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -2
- data/README.markdown +57 -91
- data/Rakefile +0 -23
- data/lib/shove.rb +3 -70
- data/lib/shove/app.rb +40 -33
- data/lib/shove/client/channel.rb +4 -0
- data/lib/shove/client/connection.rb +32 -14
- data/lib/shove/http/request.rb +2 -2
- data/lib/shove/protocol.rb +3 -1
- data/shove.gemspec +1 -3
- data/spec/cassettes/should_be_able_to_authorize_with_the_server.yml +10 -6
- data/spec/cassettes/should_deny_a_connection.yml +10 -6
- data/spec/cassettes/should_deny_a_control_to_a_client.yml +10 -6
- data/spec/cassettes/should_deny_a_publishing_to_a_client.yml +10 -6
- data/spec/cassettes/should_deny_a_subscriptions_to_a_client.yml +10 -6
- data/spec/cassettes/should_deny_publishing_on_a_channel_context.yml +10 -6
- data/spec/cassettes/should_deny_subscriptions_on_a_channel_context.yml +10 -6
- data/spec/cassettes/should_get_a_set_of_nodes_for_the_network.yml +11 -7
- data/spec/cassettes/should_grant_a_connection.yml +10 -6
- data/spec/cassettes/should_grant_a_control_to_a_client.yml +11 -7
- data/spec/cassettes/should_grant_a_publishing_to_a_client.yml +10 -6
- data/spec/cassettes/should_grant_a_subscriptions_to_a_client.yml +10 -6
- data/spec/cassettes/should_grant_publishing_on_a_channel_context.yml +10 -6
- data/spec/cassettes/should_grant_subscriptions_on_a_channel_context.yml +10 -6
- data/spec/cassettes/should_publish_on_a_channel_context.yml +10 -6
- data/spec/cassettes/should_publish_to_a_client.yml +10 -6
- data/spec/helper.rb +0 -2
- data/spec/shove_client_spec.rb +39 -30
- data/spec/shove_http_spec.rb +27 -31
- metadata +20 -40
- data/bin/shove +0 -169
- data/lib/shove/app_directory.rb +0 -103
- data/spec/app_directory_spec.rb +0 -66
- data/spec/cassettes/should_authorize_on_a_channel.yml +0 -26
- data/spec/cassettes/should_authorize_oneself.yml +0 -24
- data/spec/cassettes/should_cancel_a_binding.yml +0 -24
- data/spec/cassettes/should_configure_the_default.yml +0 -24
- data/spec/cassettes/should_configure_the_from_the_previous_test.yml +0 -24
- data/spec/cassettes/should_create_a_channel_context.yml +0 -24
- data/spec/cassettes/should_get_a_subscribe_granted_event.yml +0 -24
- data/spec/cassettes/should_publish.yml +0 -24
- data/spec/cassettes/should_receive_an_unsubscribe_event.yml +0 -24
- data/spec/cassettes/should_receive_messages_on_a_channel.yml +0 -24
- data/spec/cassettes/should_send_a_connect_op.yml +0 -24
- data/spec/cassettes/should_send_a_connect_op_with_an_id.yml +0 -24
- data/spec/cassettes/should_spawn_a_client.yml +0 -24
- data/spec/cassettes/should_subscribe_to_a_channel.yml +0 -24
- data/spec/cassettes/should_trigger_a_connect_denied_event.yml +0 -24
- data/spec/cassettes/should_trigger_a_connect_event.yml +0 -24
- data/spec/cassettes/should_trigger_a_disconnect_event.yml +0 -24
- data/spec/cassettes/should_trigger_an_error_event.yml +0 -24
- data/spec/cassettes/should_unsubscribe_from_a_channel.yml +0 -24
- data/spec/cassettes/should_update_the_default_app.yml +0 -24
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
shove
|
2
|
-
|
3
|
-
|
1
|
+
shove
|
2
|
+
=====
|
3
|
+
HTTP and WebSocket clients for shove.io
|
4
4
|
|
5
5
|
<a name="installation"></a>
|
6
6
|
Installation
|
@@ -11,53 +11,42 @@ gem install shove
|
|
11
11
|
```
|
12
12
|
|
13
13
|
<a name="configuration"></a>
|
14
|
-
|
15
|
-
|
14
|
+
Using Shove
|
15
|
+
-----------
|
16
16
|
|
17
|
-
|
18
|
-
shove though the Shove module:
|
17
|
+
To use shove, you must first create a Shove::App object.
|
19
18
|
|
20
19
|
```ruby
|
21
|
-
Shove.
|
22
|
-
app_id "myappid"
|
23
|
-
app_key "myappkey"
|
24
|
-
|
25
|
-
```
|
26
|
-
|
27
|
-
If you want to work with different shove apps in one project, you can
|
28
|
-
create App objects
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
app = Shove::App.new do
|
32
|
-
app_id "myappid"
|
33
|
-
app_key "myappkey"
|
34
|
-
end
|
20
|
+
app = Shove::App.new(
|
21
|
+
app_id: "myappid",
|
22
|
+
app_key: "myappkey"
|
23
|
+
)
|
35
24
|
```
|
36
25
|
|
37
|
-
|
26
|
+
Get your app_id, and app_key at [shove.io][0]
|
38
27
|
|
39
28
|
<a name="http_client"></a>
|
40
29
|
Using the HTTP Client
|
41
30
|
---------------------
|
42
31
|
The HTTP client gives publishing and access control capabilities without
|
43
|
-
a persistent WebSocket connection. The HTTP client
|
32
|
+
a persistent WebSocket connection. The HTTP client cannot act as a subscriber.
|
44
33
|
|
45
|
-
|
34
|
+
Publish to a channel
|
46
35
|
|
47
36
|
```ruby
|
48
|
-
|
37
|
+
app.channel("notifications").publish("Hello World!")
|
49
38
|
```
|
50
39
|
|
51
40
|
Publish Direct
|
52
41
|
|
53
42
|
```ruby
|
54
|
-
|
43
|
+
app.channel("direct:buddy").publish("Hey buddy")
|
55
44
|
```
|
56
45
|
|
57
46
|
Publish and handle the HTTP response
|
58
47
|
|
59
48
|
```ruby
|
60
|
-
|
49
|
+
app.channel("notifications").publish("...") do |response|
|
61
50
|
if reponse.error?
|
62
51
|
puts "#{response.status} - #{response.error}"
|
63
52
|
end
|
@@ -70,25 +59,25 @@ granular security.
|
|
70
59
|
Grant subscription on the notifications channel
|
71
60
|
|
72
61
|
```ruby
|
73
|
-
|
62
|
+
app.channel("notifications").grant_subscribe("dan@shove.io")
|
74
63
|
```
|
75
64
|
|
76
65
|
Grant subscription on all channels to client dan
|
77
66
|
|
78
67
|
```ruby
|
79
|
-
|
68
|
+
app.channel("*").grant_subscribe("dan@shove.io")
|
80
69
|
```
|
81
70
|
|
82
71
|
Grant publishing on chat:client_22733 channel to client dan
|
83
72
|
|
84
73
|
```ruby
|
85
|
-
|
74
|
+
app.channel("chat:client_22733").grant_publish("dan")
|
86
75
|
```
|
87
76
|
|
88
77
|
Deny publishing on chat:client_22733 channel to dan
|
89
78
|
|
90
79
|
```ruby
|
91
|
-
|
80
|
+
app.channel("chat:client_22733").deny_publish("dan")
|
92
81
|
```
|
93
82
|
|
94
83
|
Sometimes it's easier to give out an access key to a specific
|
@@ -98,37 +87,37 @@ channel, which is also an option.
|
|
98
87
|
Channel Keys
|
99
88
|
------------
|
100
89
|
You can generate channel keys which allow clients of
|
101
|
-
your shove network to
|
90
|
+
your shove network to subscribe or publish to specific
|
102
91
|
channels.
|
103
92
|
|
104
93
|
Example: Create a key for the channel groups:788
|
105
94
|
|
106
95
|
```ruby
|
107
|
-
key =
|
96
|
+
key = app.channel_key "group:788"
|
108
97
|
```
|
109
98
|
|
110
|
-
|
99
|
+
Subscribe only
|
111
100
|
|
112
101
|
```ruby
|
113
|
-
key = app.
|
102
|
+
key = app.subscribe_key "group:788"
|
114
103
|
```
|
115
104
|
|
116
105
|
This functionality becomes useful when you want to give
|
117
|
-
you site users access.
|
106
|
+
you site users access. In your view:
|
118
107
|
|
119
|
-
```
|
120
|
-
|
121
|
-
|
122
|
-
var key = "#{@shove.channel_key(@channel)}";
|
108
|
+
```erb
|
109
|
+
var channel = "<%= @channel %>";
|
110
|
+
var key = "<%= @app.channel_key(@channel) %>";
|
123
111
|
```
|
124
112
|
|
125
|
-
Note: Channel keys are based off the app key. So, in order for
|
126
|
-
them to work, you must specify the app key
|
113
|
+
Note: Channel keys are based off the app key (master key). So, in order for
|
114
|
+
them to work, you must specify the app key in your app.
|
127
115
|
|
128
116
|
```ruby
|
129
|
-
|
130
|
-
|
131
|
-
|
117
|
+
app = Shove::App.new(
|
118
|
+
app_id: "myappid",
|
119
|
+
app_key: "myappkey"
|
120
|
+
)
|
132
121
|
```
|
133
122
|
|
134
123
|
<a name="websocket_client"></a>
|
@@ -139,28 +128,15 @@ requires that you are running an EventMachine reactor.
|
|
139
128
|
|
140
129
|
```ruby
|
141
130
|
EM.run do
|
142
|
-
app = Shove::App.new
|
143
|
-
app_id "myapp"
|
144
|
-
|
145
|
-
|
146
|
-
app.connect
|
131
|
+
app = Shove::App.new(
|
132
|
+
app_id "myapp",
|
133
|
+
app_key: "myappkey"
|
134
|
+
)
|
147
135
|
|
148
|
-
|
149
|
-
client = app.connect "unique_id"
|
136
|
+
client = app.connect
|
150
137
|
end
|
151
138
|
```
|
152
139
|
|
153
|
-
### Authorization
|
154
|
-
The client is treated like any other websocket
|
155
|
-
client and must be authorized to publish and subscribe.
|
156
|
-
|
157
|
-
```ruby
|
158
|
-
client.authorize "app_key"
|
159
|
-
|
160
|
-
# self authorize a particular channel
|
161
|
-
client.channel("channel").authorize "channel_key"
|
162
|
-
```
|
163
|
-
|
164
140
|
### Client events
|
165
141
|
|
166
142
|
Connect event:
|
@@ -195,7 +171,7 @@ client.on("connect_denied") do |id|
|
|
195
171
|
end
|
196
172
|
```
|
197
173
|
|
198
|
-
### Publish and Subscribe
|
174
|
+
### Channels & Publish and Subscribe
|
199
175
|
|
200
176
|
Subscribe to a channel or get a subscribed channel
|
201
177
|
|
@@ -265,37 +241,27 @@ channel.publish("hi!")
|
|
265
241
|
channel.publish(obj.to_json)
|
266
242
|
```
|
267
243
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
```bash
|
274
|
-
shove help
|
275
|
-
```
|
276
|
-
|
277
|
-
Publish a message
|
278
|
-
|
279
|
-
```bash
|
280
|
-
shove publish -c channel1 -m "Hello world!"
|
281
|
-
```
|
282
|
-
|
283
|
-
Publish to a specific app
|
284
|
-
|
285
|
-
```bash
|
286
|
-
shove publish -a app_id -c chan1 -m "hi"
|
287
|
-
```
|
244
|
+
<a name="websocket_client"></a>
|
245
|
+
WebSocket Client without App Key
|
246
|
+
--------------------------------
|
247
|
+
If you are connecting to someone elses app
|
248
|
+
and have limited scope and access, you can get by.
|
288
249
|
|
289
|
-
|
250
|
+
```ruby
|
251
|
+
EM.run do
|
252
|
+
app = Shove::App.new(
|
253
|
+
app_id "myapp"
|
254
|
+
)
|
290
255
|
|
291
|
-
|
292
|
-
shove apps:default -a app_id
|
293
|
-
```
|
256
|
+
client = app.connect "connect-key"
|
294
257
|
|
295
|
-
|
258
|
+
channel = client.channel("channel")
|
259
|
+
channel.auth "channelkey"
|
296
260
|
|
297
|
-
|
298
|
-
|
261
|
+
channel.on("message") do |message|
|
262
|
+
puts message
|
263
|
+
end
|
264
|
+
end
|
299
265
|
```
|
300
266
|
|
301
267
|
[0]: https://shove.io
|
data/Rakefile
CHANGED
@@ -28,26 +28,3 @@ task :autospec => :spec do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
end
|
31
|
-
|
32
|
-
desc "Generate the README HTML"
|
33
|
-
task :readme do
|
34
|
-
|
35
|
-
require "redcarpet"
|
36
|
-
require "albino"
|
37
|
-
|
38
|
-
# Create a custom renderer that uses albino to
|
39
|
-
# make pretty code
|
40
|
-
class Colorizer < Redcarpet::Render::HTML
|
41
|
-
def block_code(code, language)
|
42
|
-
Albino.colorize(code, language)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
content = Redcarpet::Markdown.new(Colorizer, :fenced_code_blocks => true)
|
47
|
-
.render(File.read("README.markdown"))
|
48
|
-
|
49
|
-
File.open("README.html", "w") do |f|
|
50
|
-
f << content
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
data/lib/shove.rb
CHANGED
@@ -7,7 +7,6 @@ require "em-http-request"
|
|
7
7
|
require "em-ws-client"
|
8
8
|
require "yajl"
|
9
9
|
require "yaml"
|
10
|
-
require "confstruct"
|
11
10
|
require "digest/sha1"
|
12
11
|
|
13
12
|
##
|
@@ -18,80 +17,14 @@ require "digest/sha1"
|
|
18
17
|
# See https://github.com/shove/shove for js client documentation
|
19
18
|
module Shove
|
20
19
|
|
21
|
-
Version = "1.0.
|
22
|
-
|
23
|
-
class ShoveException < Exception; end
|
24
|
-
|
25
|
-
class << self
|
26
|
-
|
27
|
-
attr_accessor :config, :app
|
28
|
-
|
29
|
-
# configure shover
|
30
|
-
# +settings+ the settings for the created client as
|
31
|
-
# a string for a yaml file, or as a hash
|
32
|
-
def configure params=nil, &block
|
33
|
-
|
34
|
-
unless defined? @config
|
35
|
-
@config = Confstruct::Configuration.new do
|
36
|
-
api_url "https://api.shove.io"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
if params
|
41
|
-
@config.configure params
|
42
|
-
end
|
20
|
+
Version = "1.0.8"
|
43
21
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
unless defined? @app
|
49
|
-
@app = App.new(@config)
|
50
|
-
else
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# fetch a channel by name
|
56
|
-
# +name+ the name of the channel
|
57
|
-
def channel name
|
58
|
-
@app.channel(name)
|
59
|
-
end
|
60
|
-
|
61
|
-
# fetch a client by id
|
62
|
-
def client id
|
63
|
-
@app.client(id)
|
64
|
-
end
|
65
|
-
|
66
|
-
# validate network settings
|
67
|
-
# used for the CLI
|
68
|
-
def valid?
|
69
|
-
@app.valid?
|
70
|
-
end
|
71
|
-
|
72
|
-
# fetch the available stream nodes
|
73
|
-
# for this network.
|
74
|
-
def hosts
|
75
|
-
@app.hosts
|
76
|
-
end
|
77
|
-
|
78
|
-
# Connect to the default app with a
|
79
|
-
# WebSocket connection
|
80
|
-
def connect
|
81
|
-
@app.connect
|
82
|
-
end
|
83
|
-
|
84
|
-
# Create a channel key
|
85
|
-
# +channel+ the name of the channel
|
86
|
-
def channel_key channel
|
87
|
-
@app.channel_key channel
|
88
|
-
end
|
22
|
+
# Exception class for all shove exception
|
23
|
+
class ShoveException < Exception; end
|
89
24
|
|
90
|
-
end
|
91
25
|
end
|
92
26
|
|
93
27
|
require "shove/app"
|
94
|
-
require "shove/app_directory"
|
95
28
|
require "shove/protocol"
|
96
29
|
require "shove/client/connection"
|
97
30
|
require "shove/client/channel"
|
data/lib/shove/app.rb
CHANGED
@@ -1,38 +1,24 @@
|
|
1
1
|
module Shove
|
2
2
|
class App
|
3
3
|
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :app_key, :app_id, :api_url, :ws_url
|
5
5
|
|
6
6
|
# create an API client
|
7
7
|
# +config+ optional Confstruct
|
8
8
|
# +&block+ config block
|
9
9
|
# Example:
|
10
|
-
# Shove::App.new
|
11
|
-
# app_id "myappid"
|
12
|
-
# app_key "myappkey"
|
13
|
-
#
|
14
|
-
def initialize config=
|
15
|
-
@config
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@config.configure do
|
22
|
-
api_url Shove.config.api_url || "https://api.shove.io"
|
23
|
-
end
|
10
|
+
# Shove::App.new(
|
11
|
+
# app_id: "myappid"
|
12
|
+
# app_key: "myappkey"
|
13
|
+
# )
|
14
|
+
def initialize config={}
|
15
|
+
@config = config
|
16
|
+
@app_id = config[:app_id]
|
17
|
+
@app_key = config[:app_key]
|
18
|
+
@api_url = config[:api_url] || "https://api.shove.io"
|
19
|
+
@ws_url = config[:ws_url]
|
24
20
|
|
25
|
-
|
26
|
-
@config.configure params
|
27
|
-
end
|
28
|
-
|
29
|
-
if block
|
30
|
-
@config.configure(&block)
|
31
|
-
end
|
32
|
-
|
33
|
-
unless @config.app_id
|
34
|
-
raise ShoveException.new("App ID required")
|
35
|
-
end
|
21
|
+
raise ShoveException.new("App ID required") unless @app_id
|
36
22
|
end
|
37
23
|
|
38
24
|
# is the app valid?
|
@@ -43,7 +29,7 @@ module Shove
|
|
43
29
|
|
44
30
|
# get a list of websocket hosts
|
45
31
|
def hosts
|
46
|
-
request("hosts").exec_sync(:get).parse
|
32
|
+
@hosts ||= request("hosts").exec_sync(:get).parse
|
47
33
|
end
|
48
34
|
|
49
35
|
# create a channel context for acting on a channel
|
@@ -60,29 +46,50 @@ module Shove
|
|
60
46
|
|
61
47
|
# the base URL based on the settings
|
62
48
|
def url
|
63
|
-
"#{@
|
49
|
+
"#{@api_url}/apps/#{@app_id}"
|
64
50
|
end
|
65
51
|
|
66
52
|
# Create a default request object with the base URL
|
67
53
|
# +path+ extra path info
|
68
54
|
def request path
|
69
|
-
Http::Request.new("#{url}/#{path}",
|
55
|
+
Http::Request.new("#{url}/#{path}", self)
|
70
56
|
end
|
71
57
|
|
72
58
|
# Generate a channel key for a client to self authorize
|
73
59
|
# publish and subscribe actions.
|
74
60
|
# +channel+ the name of the channel
|
75
61
|
def channel_key channel
|
76
|
-
Digest::SHA1.hexdigest "#{@
|
62
|
+
Digest::SHA1.hexdigest "#{@app_key}-#{channel}!"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Generate a channel key for a client to self authorize
|
66
|
+
# publish and subscribe actions.
|
67
|
+
# +channel+ the name of the channel
|
68
|
+
def publish_key channel
|
69
|
+
channel_key channel
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generate a channel key for a client to self authorize
|
73
|
+
# subscribe actions.
|
74
|
+
# +channel+ the name of the channel
|
75
|
+
def subscribe_key channel
|
76
|
+
Digest::SHA1.hexdigest "#{@app_key}-#{channel}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Generate a connect key for a client to self authorize
|
80
|
+
# publish and subscribe actions.
|
81
|
+
# +channel+ the name of the channel
|
82
|
+
def connect_key
|
83
|
+
Digest::SHA1.hexdigest "#{@app_key}-connect"
|
77
84
|
end
|
78
85
|
|
79
86
|
####
|
80
87
|
|
81
88
|
# Connect to shove as a client in the current process
|
82
89
|
# +id+ optional shove id to supply
|
83
|
-
def connect
|
84
|
-
client = Client::Connection.new(self
|
85
|
-
client.connect
|
90
|
+
def connect connect_key=nil
|
91
|
+
client = Client::Connection.new(self)
|
92
|
+
client.connect connect_key
|
86
93
|
client
|
87
94
|
end
|
88
95
|
|