slanger 0.4.4 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cd65a213b5685b79b1fd958a1ee446cd9dac9986
4
- data.tar.gz: 428f76b4006c574491bcb308a2547b2bcb983d7f
2
+ SHA256:
3
+ metadata.gz: fce992bf7da1961b629f9c2acad242d07871f7d1f6c9b7ab405f247d53887e9f
4
+ data.tar.gz: 33cf202ea4f9d4e7ee245eaa4d7b613dc589ce8bfa5975a2427485a0463d726b
5
5
  SHA512:
6
- metadata.gz: b90d2d727f37da70e2e88a05f0cba997c43ddbd4a62472b6aba89d73914e8d0ef5b6aeb22bf12c152329a8e28d4cc15b3438521cde04434a3854a7a71fa78297
7
- data.tar.gz: dbcd5c1d8070327d26adda0881766151024e0148d4a7f69afb9a16aa27c2a64933bc11dcf3a56101c65e55a43603409226e64866d5441244e79165e0459f9ce7
6
+ metadata.gz: a74747925333bba78821f0105464e63f692869e46065ac1c043311acf9375f677b9de75a6dc27d1482cd1a7bdc4dd4fa82f04efd66ad1a65753345ff99790bbd
7
+ data.tar.gz: baa4433570751fd6eb0e726230fe7040bceb357c79fcf3dba27fa6ec16b80748a2fd5ffcfa88c0534c1dd670ffaa9a33cfb6058283ba7a20ff10f22666a4e030
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Slanger
2
2
 
3
+ ## UNMAINTAINED - Slanger is deprecated and unmaintained by its authors. Use at your own risk.
4
+
3
5
  [![Gem Version](https://badge.fury.io/rb/slanger.svg)](http://badge.fury.io/rb/slanger) [![Build Status](https://travis-ci.org/stevegraham/slanger.svg?branch=master)](https://travis-ci.org/stevegraham/slanger)
4
6
 
5
7
  **Important! Slanger is not supposed to be included in your Gemfile. RubyGems is used as a distribution mechanism. If you include it in your app, you will likely get dependency conflicts. PRs updating dependencies for compatibility with your app will be closed. Thank you for reading and enjoy Slanger!**
6
8
 
7
- ##Typical usage
9
+ ## Typical usage
8
10
 
9
11
  ```
10
12
  gem install slanger
@@ -19,7 +21,8 @@ installed as a gem.
19
21
 
20
22
  Bundler has multiple purposes, one of which is useful for installation.
21
23
 
22
- ##About
24
+ ## About
25
+
23
26
  Slanger is an open source server implementation of the Pusher protocol written
24
27
  in Ruby. It is designed to scale horizontally across N nodes and to be agnostic
25
28
  as to which Slanger node a subscriber is connected to, i.e subscribers to the
@@ -2,7 +2,6 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  require 'optparse'
5
- require 'bundler/setup'
6
5
  require 'eventmachine'
7
6
  require 'yaml'
8
7
  require 'active_support/core_ext/hash'
@@ -92,15 +91,17 @@ end
92
91
 
93
92
  if options[:tls_options]
94
93
  [:cert_chain_file, :private_key_file].each do |param|
95
- raise RuntimeError.new "--#{param} does not exist at `#{options[:tls_options][param]}`" unless File.exists? options[:tls_options][param]
96
94
  raise RuntimeError.new "Both --cert_file and --private_key_file need to be specified" unless options[:tls_options][param]
95
+ raise RuntimeError.new "--#{param} does not exist at `#{options[:tls_options][param]}`" unless File.exists? options[:tls_options][param]
97
96
  end
98
97
  end
99
98
 
100
99
  STDOUT.sync = true
101
100
 
102
- EM.epoll
103
- EM.kqueue
101
+ case
102
+ when EM.epoll? then EM.epoll
103
+ when EM.kqueue? then EM.kqueue
104
+ end
104
105
 
105
106
  EM.run do
106
107
  File.tap { |f| require f.expand_path(f.join(f.dirname(__FILE__),'..', 'slanger.rb')) }
@@ -12,7 +12,7 @@ module Slanger
12
12
  end
13
13
 
14
14
  def data
15
- @data ||= Oj.load(body["data"] || params["data"])
15
+ @data ||= Oj.strict_load(body["data"] || params["data"])
16
16
  end
17
17
 
18
18
  def body
@@ -87,7 +87,7 @@ module Slanger
87
87
  end
88
88
 
89
89
  def assert_valid_json!(string)
90
- Oj.load(string)
90
+ Oj.strict_load(string)
91
91
  rescue Oj::ParserError
92
92
  raise Slanger::InvalidRequest.new("Invalid request body: #{raw_body}")
93
93
  end
@@ -83,10 +83,24 @@ module Slanger
83
83
  # which will send it to subscribed clients.
84
84
  def dispatch(message, channel)
85
85
  push(Oj.dump(message, mode: :compat)) unless channel =~ /\Aslanger:/
86
+
87
+ perform_client_webhook!(message)
86
88
  end
87
89
 
88
90
  def authenticated?
89
91
  channel_id =~ /\Aprivate-/ || channel_id =~ /\Apresence-/
90
92
  end
93
+
94
+ private
95
+
96
+ def perform_client_webhook!(message)
97
+ if (message['event'].start_with?('client-')) then
98
+
99
+ event = message.merge({'name' => 'client_event'})
100
+ event['data'] = Oj.dump(event['data'])
101
+
102
+ Slanger::Webhook.post(event)
103
+ end
104
+ end
91
105
  end
92
106
  end
@@ -9,7 +9,7 @@ module Slanger
9
9
  end
10
10
 
11
11
  def send_message m
12
- msg = Oj.load m
12
+ msg = Oj.strict_load m
13
13
  s = msg.delete 'socket_id'
14
14
  socket.send Oj.dump(msg, mode: :compat) unless s == socket_id
15
15
  end
@@ -25,9 +25,9 @@ module Slanger
25
25
  # Dispatches message handling to method with same name as
26
26
  # the event name
27
27
  def onmessage(msg)
28
- msg = Oj.load(msg)
28
+ msg = Oj.strict_load(msg)
29
29
 
30
- msg['data'] = Oj.load(msg['data']) if msg['data'].is_a? String
30
+ msg['data'] = Oj.strict_load(msg['data']) if msg['data'].is_a? String
31
31
 
32
32
  event = msg['event'].gsub(/\Apusher:/, 'pusher_')
33
33
 
@@ -32,7 +32,7 @@ module Slanger
32
32
  end
33
33
 
34
34
  def subscribe(msg, callback, &blk)
35
- channel_data = Oj.load msg['data']['channel_data']
35
+ channel_data = Oj.strict_load msg['data']['channel_data']
36
36
  public_subscription_id = SecureRandom.uuid
37
37
 
38
38
  # Send event about the new subscription to the Redis slanger:connection_notification Channel.
@@ -25,7 +25,7 @@ module Slanger
25
25
  def subscriber
26
26
  @subscriber ||= new_connection.pubsub.tap do |c|
27
27
  c.on(:message) do |channel, message|
28
- message = Oj.load(message)
28
+ message = Oj.strict_load(message)
29
29
  c = Channel.from message['channel']
30
30
  c.dispatch message, channel
31
31
  end
@@ -1,3 +1,3 @@
1
1
  module Slanger
2
- VERSION = '0.4.4'
2
+ VERSION = '0.6.1'
3
3
  end
@@ -4,8 +4,10 @@ require 'em-websocket'
4
4
  module Slanger
5
5
  module WebSocketServer
6
6
  def run
7
- EM.epoll
8
- EM.kqueue
7
+ case
8
+ when EM.epoll? then EM.epoll
9
+ when EM.kqueue? then EM.kqueue
10
+ end
9
11
 
10
12
  EM.run do
11
13
  options = {
data/slanger.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  # encoding: utf-8
2
- require 'bundler/setup'
3
-
4
2
  require 'eventmachine'
5
3
  require 'em-hiredis'
6
4
  require 'rack'
@@ -9,8 +7,10 @@ require File.join(File.dirname(__FILE__), 'lib', 'slanger', 'version')
9
7
 
10
8
  module Slanger; end
11
9
 
12
- EM.epoll
13
- EM.kqueue
10
+ case
11
+ when EM.epoll? then EM.epoll
12
+ when EM.kqueue? then EM.kqueue
13
+ end
14
14
 
15
15
  File.tap do |f|
16
16
  Dir[f.expand_path(f.join(f.dirname(__FILE__),'lib', 'slanger', '*.rb'))].each do |file|
@@ -18,7 +18,7 @@ describe 'Integration:' do
18
18
  end
19
19
  end
20
20
 
21
- messages.should have_attributes connection_established: true, id_present: true,
21
+ expect(messages).to have_attributes connection_established: true, id_present: true,
22
22
  last_event: 'an_event', last_data: { some: "Mit Raben Und Wölfen" }.to_json
23
23
  end
24
24
 
@@ -36,7 +36,7 @@ describe 'Integration:' do
36
36
  end
37
37
  end
38
38
 
39
- messages.should have_attributes connection_established: true, id_present: true,
39
+ expect(messages).to have_attributes connection_established: true, id_present: true,
40
40
  last_event: 'not_excluded_socket_event', last_data: { some: "Mit Raben Und Wölfen" }.to_json
41
41
  end
42
42
 
@@ -52,7 +52,7 @@ describe 'Integration:' do
52
52
  end
53
53
  end
54
54
 
55
- messages.last.should == {"event"=>"pusher:error", "data"=>"{\"code\":null,\"message\":\"Existing subscription to MY_CHANNEL\"}"}
55
+ expect(messages.last).to eq({"event"=>"pusher:error", "data"=>"{\"code\":null,\"message\":\"Existing subscription to MY_CHANNEL\"}"})
56
56
  end
57
57
 
58
58
  it 'supports unsubscribing to channels without closing the socket' do
@@ -77,7 +77,7 @@ describe 'Integration:' do
77
77
  end
78
78
  end
79
79
 
80
- messages.should have_attributes connection_established: true, id_present: true,
80
+ expect(messages).to have_attributes connection_established: true, id_present: true,
81
81
  last_event: 'pusher_internal:subscription_succeeded', count: 2
82
82
  end
83
83
 
@@ -105,10 +105,10 @@ describe 'Integration:' do
105
105
  end
106
106
  end
107
107
 
108
- client1_messages.should have_attributes count: 2
108
+ expect(client1_messages).to have_attributes count: 2
109
109
 
110
- client2_messages.should have_attributes last_event: 'an_event',
111
- last_data: { some: 'data' }.to_json
110
+ expect(client2_messages).to have_attributes last_event: 'an_event',
111
+ last_data: { some: 'data' }.to_json
112
112
  end
113
113
  end
114
114
  end
@@ -10,7 +10,7 @@ describe 'Integration' do
10
10
  messages = em_stream(key: 'bogus_key') do |websocket, messages|
11
11
  websocket.callback { EM.stop }
12
12
  end
13
- messages.should have_attributes count: 1, last_event: 'pusher:error',
13
+ expect(messages).to have_attributes count: 1, last_event: 'pusher:error',
14
14
  connection_established: false, id_present: false
15
15
  messages.first['data'] == 'Could not find app by key bogus_key'
16
16
  end
@@ -21,7 +21,7 @@ describe 'Integration' do
21
21
  messages = em_stream do |websocket, messages|
22
22
  websocket.callback { EM.stop }
23
23
  end
24
- messages.should have_attributes activity_timeout: Slanger::Config.activity_timeout,
24
+ expect(messages).to have_attributes activity_timeout: Slanger::Config.activity_timeout,
25
25
  connection_established: true, id_present: true
26
26
  end
27
27
  end
@@ -31,7 +31,7 @@ describe 'Integration' do
31
31
  messages = em_stream do |websocket, messages|
32
32
  websocket.callback { EM.stop }
33
33
  end
34
- messages.should have_attributes connection_established: true, id_present: true
34
+ expect(messages).to have_attributes connection_established: true, id_present: true
35
35
  end
36
36
  end
37
37
 
@@ -40,7 +40,7 @@ describe 'Integration' do
40
40
  messages = em_stream(protocol: "20") do |websocket, messages|
41
41
  websocket.callback { EM.stop }
42
42
  end
43
- messages.should have_attributes connection_established: false, id_present: false,
43
+ expect(messages).to have_attributes connection_established: false, id_present: false,
44
44
  last_event: 'pusher:error'
45
45
  end
46
46
 
@@ -48,7 +48,7 @@ describe 'Integration' do
48
48
  messages = em_stream(protocol: nil) do |websocket, messages|
49
49
  websocket.callback { EM.stop }
50
50
  end
51
- messages.should have_attributes connection_established: false, id_present: false,
51
+ expect(messages).to have_attributes connection_established: false, id_present: false,
52
52
  last_event: 'pusher:error'
53
53
  end
54
54
  end
@@ -19,7 +19,7 @@ describe 'Integration' do
19
19
  end
20
20
  end
21
21
 
22
- messages.should have_attributes connection_established: true, id_present: true,
22
+ expect(messages).to have_attributes connection_established: true, id_present: true,
23
23
  count: 2,
24
24
  last_event: 'pusher:error'
25
25
 
@@ -46,11 +46,11 @@ describe 'Integration' do
46
46
  end
47
47
  end
48
48
 
49
- messages.should have_attributes first_event: 'pusher:connection_established', count: 2,
49
+ expect(messages).to have_attributes first_event: 'pusher:connection_established', count: 2,
50
50
  id_present: true
51
51
 
52
52
  # Channel id should be in the payload
53
- messages.last['event'].should == 'pusher:error'
53
+ expect(messages.last['event']).to eq('pusher:error')
54
54
  expect(JSON.parse(messages.last['data'])['message']).to match /^Invalid signature: Expected HMAC SHA256 hex digest of/
55
55
  end
56
56
  end
@@ -69,11 +69,11 @@ describe 'Integration' do
69
69
  end
70
70
  end
71
71
 
72
- messages.should have_attributes connection_established: true, count: 2
72
+ expect(messages).to have_attributes connection_established: true, count: 2
73
73
 
74
- messages.last.should == {"channel"=>"presence-channel",
74
+ expect(messages.last).to eq({"channel"=>"presence-channel",
75
75
  "event" =>"pusher_internal:subscription_succeeded",
76
- "data" => "{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"}
76
+ "data" => "{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"})
77
77
  end
78
78
 
79
79
 
@@ -87,8 +87,7 @@ describe 'Integration' do
87
87
  send_subscribe(user: user1,
88
88
  user_id: '0f177369a3b71275d25ab1b44db9f95f',
89
89
  name: 'SG',
90
- message: messages.first
91
- )
90
+ message: messages.first)
92
91
 
93
92
  when 2
94
93
  new_websocket.tap do |u|
@@ -107,13 +106,13 @@ describe 'Integration' do
107
106
 
108
107
  end
109
108
 
110
- messages.should have_attributes connection_established: true, count: 3
109
+ expect(messages).to have_attributes connection_established: true, count: 3
111
110
  # Channel id should be in the payload
112
- messages[1].should == {"channel"=>"presence-channel", "event"=>"pusher_internal:subscription_succeeded",
113
- "data"=>"{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"}
111
+ expect(messages[1]).to eq({"channel"=>"presence-channel", "event"=>"pusher_internal:subscription_succeeded",
112
+ "data"=>"{\"presence\":{\"count\":1,\"ids\":[\"0f177369a3b71275d25ab1b44db9f95f\"],\"hash\":{\"0f177369a3b71275d25ab1b44db9f95f\":{\"name\":\"SG\"}}}}"})
114
113
 
115
- messages.last.should == {"channel"=>"presence-channel", "event"=>"pusher_internal:member_added",
116
- "data"=>{"user_id"=>"37960509766262569d504f02a0ee986d", "user_info"=>{"name"=>"CHROME"}}}
114
+ expect(messages.last).to eq({"channel"=>"presence-channel", "event"=>"pusher_internal:member_added",
115
+ "data"=>{"user_id"=>"37960509766262569d504f02a0ee986d", "user_info"=>{"name"=>"CHROME"}}})
117
116
  end
118
117
 
119
118
  it 'does not send multiple member added and member removed messages if one subscriber opens multiple connections, i.e. multiple browser tabs.' do
@@ -147,8 +146,8 @@ describe 'Integration' do
147
146
  end
148
147
 
149
148
  # There should only be one set of presence messages sent to the refernce user for the second user.
150
- messages.one? { |message| message['event'] == 'pusher_internal:member_added' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }.should be_true
151
- messages.one? { |message| message['event'] == 'pusher_internal:member_removed' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }.should be_true
149
+ expect(messages.one? { |message| message['event'] == 'pusher_internal:member_added' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }).to eq(true)
150
+ expect(messages.one? { |message| message['event'] == 'pusher_internal:member_removed' && message['data']['user_id'] == '37960509766262569d504f02a0ee986d' }).to eq(true)
152
151
 
153
152
  end
154
153
  end
@@ -17,7 +17,7 @@ describe 'Integration' do
17
17
  end
18
18
  end
19
19
 
20
- messages.should have_attributes connection_established: true,
20
+ expect(messages).to have_attributes connection_established: true,
21
21
  count: 2,
22
22
  id_present: true,
23
23
  last_event: 'pusher_internal:subscription_succeeded'
@@ -37,7 +37,7 @@ describe 'Integration' do
37
37
  end
38
38
  end
39
39
 
40
- messages.should have_attributes connection_established: true, count: 2, id_present: true, last_event:
40
+ expect(messages).to have_attributes connection_established: true, count: 2, id_present: true, last_event:
41
41
  'pusher:error'
42
42
 
43
43
  expect(JSON.parse(messages.last['data'])['message']).to match /^Invalid signature: Expected HMAC SHA256 hex digest of/
@@ -71,8 +71,8 @@ describe 'Integration' do
71
71
  end
72
72
  end
73
73
 
74
- client1_messages.one? { |m| m['event'] == 'client-something' }.should be_true
75
- client2_messages.none? { |m| m['event'] == 'client-something' }.should be_true
74
+ expect(client1_messages.one? { |m| m['event'] == 'client-something' }).to eq(true)
75
+ expect(client2_messages.none? { |m| m['event'] == 'client-something' }).to eq(true)
76
76
  end
77
77
  end
78
78
  end
@@ -18,6 +18,6 @@ describe 'Replacable handler' do
18
18
  end
19
19
  end
20
20
 
21
- msgs.last.should == { "event" => "pusher:info", "data" =>"{\"message\":\"Welcome!\"}" }
21
+ expect(msgs.last).to eq({ "event" => "pusher:info", "data" =>"{\"message\":\"Welcome!\"}" })
22
22
  end
23
23
  end
@@ -12,7 +12,7 @@ describe 'Integration' do
12
12
  expected_cert = OpenSSL::X509::Certificate.new(File.open('spec/server.crt'))
13
13
  ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
14
14
  ssl_socket.connect
15
- ssl_socket.peer_cert.to_s.should == expected_cert.to_s
15
+ expect(ssl_socket.peer_cert.to_s).to eq(expected_cert.to_s)
16
16
  end
17
17
  end
18
18
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'slanger'
3
+ require 'oj'
3
4
 
4
5
  def clear_redis_connections
5
6
  Slanger::Redis.instance_variables.each do |ivar|
@@ -66,4 +67,39 @@ describe 'Slanger::Channel' do
66
67
  3.times { channel.subscribe { |m| nil } }
67
68
  end
68
69
  end
70
+
71
+ describe '#dispatch' do
72
+ it 'activates a webhook when client events are received' do
73
+ message = {
74
+ 'event' => 'client-test_event',
75
+ 'channel' => 'private-test_channel',
76
+ 'socket_id' => '8.422225',
77
+ 'data' => { 'key' => 'value' }
78
+ }
79
+
80
+ expected_params = message.merge({
81
+ 'name' => 'client_event',
82
+ 'data' => Oj.dump(message['data'])
83
+ })
84
+
85
+ Slanger::Webhook.expects(:post).
86
+ with(expected_params).
87
+ once
88
+
89
+ channel.dispatch(message, 'private-test_channel')
90
+ end
91
+
92
+ it 'does not activate a webhook when non-client event messages are received' do
93
+ message = {
94
+ 'event' => 'non_client_event',
95
+ 'channel' => 'private-test_channel',
96
+ 'socket_id' => '8.422225',
97
+ 'data' => { 'key' => 'value' }
98
+ }
99
+
100
+ Slanger::Webhook.expects(:post).never
101
+
102
+ channel.dispatch(message, 'private-test_channel')
103
+ end
104
+ end
69
105
  end
@@ -6,8 +6,8 @@ describe Slanger::Api::RequestValidation do
6
6
  it 'validation' do
7
7
  socket_id = "POST\n/apps/99759/events\nauth_key=840543d97de9803651b1&auth_timestamp=123&auth_version=1.0&body_md5=some_md5&dummy="
8
8
 
9
- expect {validate(nil) }.not_to raise_error Slanger::Api::InvalidRequest
10
- expect {validate("1234.123455") }.not_to raise_error Slanger::Api::InvalidRequest
9
+ expect {validate(nil) }.not_to raise_error
10
+ expect {validate("1234.123455") }.not_to raise_error
11
11
 
12
12
  expect {validate(socket_id) }.to raise_error Slanger::Api::InvalidRequest
13
13
  expect {validate("something 123")}.to raise_error Slanger::Api::InvalidRequest
@@ -32,7 +32,7 @@ describe 'Slanger::Webhook' do
32
32
 
33
33
  Slanger::Webhook.post name: 'channel_occupied', channel: 'test channel'
34
34
 
35
- WebMock.should have_requested(:post, Slanger::Config.webhook_url).
35
+ expect(WebMock).to have_requested(:post, Slanger::Config.webhook_url).
36
36
  with(body: payload, headers: {
37
37
  "X-Pusher-Key" => Slanger::Config.app_key,
38
38
  "X-Pusher-Signature" => hmac,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slanger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stevie Graham
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-07-23 00:00:00.000000000 Z
12
+ date: 2019-02-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -171,14 +171,14 @@ dependencies:
171
171
  requirements:
172
172
  - - "~>"
173
173
  - !ruby/object:Gem::Version
174
- version: 2.12.0
174
+ version: 3.6.0
175
175
  type: :development
176
176
  prerelease: false
177
177
  version_requirements: !ruby/object:Gem::Requirement
178
178
  requirements:
179
179
  - - "~>"
180
180
  - !ruby/object:Gem::Version
181
- version: 2.12.0
181
+ version: 3.6.0
182
182
  - !ruby/object:Gem::Dependency
183
183
  name: pusher
184
184
  requirement: !ruby/object:Gem::Requirement
@@ -369,8 +369,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
369
369
  - !ruby/object:Gem::Version
370
370
  version: '0'
371
371
  requirements: []
372
- rubyforge_project:
373
- rubygems_version: 2.2.0
372
+ rubygems_version: 3.0.2
374
373
  signing_key:
375
374
  specification_version: 4
376
375
  summary: A websocket service compatible with Pusher libraries
@@ -389,4 +388,3 @@ test_files:
389
388
  - spec/unit/channel_spec.rb
390
389
  - spec/unit/request_validation_spec.rb
391
390
  - spec/unit/webhook_spec.rb
392
- has_rdoc: