websockethook 0.1.0 → 0.1.01

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
2
  SHA1:
3
- metadata.gz: a598958034d0bc23bffba798c4e79791c6101441
4
- data.tar.gz: de4ba13cfc67d63f6fe9de5e07bfa995273b7d1c
3
+ metadata.gz: dd91e0fc65cf4e459ff0657766ea34ac7a9f1d8e
4
+ data.tar.gz: 77ddfff2e872950d7621d7c58ac99ce9792f4e88
5
5
  SHA512:
6
- metadata.gz: 6b6726ea1ce6af24499f6fc3fa09798de312c3a368e789e3b447df55f62c31c5ade4546f5240c2a8dcec81df54c30bb5dc35339aab183a4edc901831ab430d3e
7
- data.tar.gz: 1ec3c17f5344aacdcb34d1a056e6b40b5084152d8a82053beed896ae3087cffc1001aa0b4eda7d06f1c74db638ce5f57aec1fb8ea666cea81ba279f214a3bd8d
6
+ metadata.gz: 93056aaea58aac3939e1fe79d083d2f6eaf2fd465a234dcd50b748eb421a12484837c8b828ecd27d407b3ae3b68c16d0a28378ae91f0933adbae6990dd371105
7
+ data.tar.gz: 6de885962949b5db7165709a3dfcfe7aae3d89de67ddd869a3a8a058ca117f4abb0af15753db30559c0083a4ecafae6d29543837ea17cc3ace456367aa52caf4
data/lib/websockethook.rb CHANGED
@@ -6,27 +6,18 @@ class WebSocketHook
6
6
  DEFAULT_HOST = 'ws://web.sockethook.io'
7
7
 
8
8
  def initialize(options = {})
9
- @host = options[:host] || DEFAULT_HOST
10
- @pause = options[:sleep] || 0.1
11
- @stay_alive = options[:stay_alive] || true
12
- @ping = options[:ping] || 20
13
- hooks = options[:hooks] || []
14
- @stopping = false
15
- @hooks = []
16
-
17
- raise 'Host (:host) must be a URL' unless @host.is_a?(String)
18
- raise 'Pause (:pause) must be a float or integer' unless @pause.is_a?(Float) || @pause.is_a?(Integer)
19
- raise 'Stay Alive (:stay_alive) must be a boolean (true/false)' unless @stay_alive == true || @stay_alive == false
20
- raise 'Ping (:ping) must be an integer' unless @ping.is_a?(Integer)
21
- raise 'Stopping (:stopping) must be boolean (true/false)' unless @stopping == true || @stopping == false
22
- raise 'Hooks (:hooks) must be an array' unless hooks.is_a?(Array)
23
-
24
- hooks.each {|hook| register(hook) }
9
+ @stopping = false
10
+ @hooks = []
11
+ initialize_host options
12
+ initialize_pause options
13
+ initialize_keep_alive options
14
+ initialize_ping options
15
+ initialize_hooks options
25
16
  end
26
17
 
27
18
  def register(id)
28
- raise "Hook id '#{id}' must be a String" unless id.is_a?(String)
29
- raise "Hook id must only be alphanumeric, '_', '.', or '_'" unless /^[a-zA-Z0-9\-_\.]*$/ === id
19
+ fail "Hook id '#{id}' must be a String" unless id.is_a?(String)
20
+ fail "Hook id must only be alphanumeric, '_', '.', or '_'" unless /^[a-zA-Z0-9\-_\.]*$/ === id
30
21
  @hooks << id unless @hooks.include?(id)
31
22
  end
32
23
 
@@ -35,13 +26,13 @@ class WebSocketHook
35
26
  end
36
27
 
37
28
  def listen(&block)
38
- raise 'Block must be provided' unless block && block.is_a?(Proc)
29
+ fail 'Block must be provided' unless block && block.is_a?(Proc)
39
30
  begin
40
31
  @stopping = false
41
32
  listener(&block)
42
- restart = @stay_alive && !@stopping
33
+ restart = @keep_alive && !@stopping
43
34
  if restart
44
- block.call type:'restart', message:'restarting connection since it was lost'
35
+ block.call type: 'restart', message: 'restarting connection since it was lost'
45
36
  sleep 5
46
37
  end
47
38
  end while restart
@@ -54,51 +45,79 @@ class WebSocketHook
54
45
 
55
46
  private
56
47
 
48
+ def initialize_host(options = {})
49
+ @host = options[:host] || DEFAULT_HOST
50
+ fail 'Host (:host) must be a URL' unless @host.is_a?(String)
51
+ end
52
+
53
+ def initialize_pause(options = {})
54
+ @pause = options[:sleep] || 0.1
55
+ fail 'Pause (:pause) must be a float or integer' unless @pause.is_a?(Float) || @pause.is_a?(Integer)
56
+ end
57
+
58
+ def initialize_keep_alive(options = {})
59
+ @keep_alive = options[:keep_alive] || true
60
+ fail 'Keep Alive (:keep_alive) must be a boolean (true/false)' unless @keep_alive == true || @keep_alive == false
61
+ end
62
+
63
+ def initialize_ping(options = {})
64
+ @ping = options[:ping] || 20
65
+ fail 'Ping (:ping) must be an integer' unless @ping.is_a?(Integer)
66
+ end
67
+
68
+ def initialize_hooks(options = {})
69
+ hooks = options[:hooks] || []
70
+ fail 'Hooks (:hooks) must be an array' unless hooks.is_a?(Array)
71
+ hooks.each { |hook| register(hook) }
72
+ end
73
+
57
74
  def stop_em
58
- begin
59
- EM.stop
60
- rescue
61
- end
75
+ EM.stop
76
+ rescue
62
77
  end
63
78
 
64
79
  def listener(&block)
65
- EM.run do
66
- ws_settings = {ping: @ping}
67
- ws = Faye::WebSocket::Client.new(@host, nil, ws_settings)
68
-
80
+ websocket(block) do |ws|
81
+ ws.on :open do
82
+ @hooks.each do |hook|
83
+ ws.send({type:'register',id:hook}.to_json)
84
+ end
85
+ end
69
86
  ws.on :message do |message|
70
87
  data = nil
71
88
  begin
72
- data = JSON.parse(message.data, symbolize_names:true)
89
+ data = JSON.parse(message.data, symbolize_names: true)
73
90
  rescue => ex
74
- block.call type:'error', message: "Message received, but couldn't parse: #{ex.message}"
91
+ block.call type: 'error', message: "Message received, but couldn't parse: #{ex.message}"
75
92
  end
76
- content = data.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo }
93
+ content = data.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
94
+ data[:data][:url] = "#{@host.sub('ws://','http://')}#{data[:data][:path]}" if data[:type]=='registered' && data[:data] && data[:data][:path]
77
95
  block.call(content) if data && block
78
96
  end
79
97
 
80
- ws.on :open do
81
- block.call(type:'open') if block
82
- @hooks.each do |hook|
83
- ws.send({type:'register', id:hook}.to_json)
84
- end
85
- end
86
-
87
- ws.on :close do
88
- block.call(type:'close') if block
89
- stop_em
90
- end
98
+ handle_ws(ws, :error, block) { @hooks.each { |hook| ws.send({ type: 'register', id: hook }.to_json) } }
99
+ handle_ws(ws, :close, block) { stop_em }
100
+ handle_ws(ws, :error, block) { stop_em }
101
+ end
102
+ end
91
103
 
92
- ws.on :error do
93
- block.call(type:'error') if block
94
- stop_em
95
- end
104
+ def websocket(callback_block, &socket_block)
105
+ EM.run do
106
+ ws_settings = { ping: @ping }
107
+ ws = Faye::WebSocket::Client.new(@host, nil, ws_settings)
108
+ socket_block.call(ws)
96
109
  end
97
- block.call(type:'stopped')
110
+ callback_block.call(type: 'stopped')
98
111
  rescue => ex
99
- block.call type:'error', message:ex.message
112
+ callback_block.call type: 'error', message: ex.message
100
113
  rescue Interrupt
101
114
  stop
102
- block.call(type:'stopped')
115
+ callback_block.call(type: 'stopped')
116
+ end
117
+
118
+ def handle_ws(ws, action, callback_block, &_block)
119
+ ws.on action do
120
+ callback_block.call(type: action.to_s)
121
+ end
103
122
  end
104
- end
123
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
- require "codeclimate-test-reporter"
1
+ require 'codeclimate-test-reporter'
2
2
  require 'rspec'
3
+ require 'wrong'
3
4
 
4
5
  CodeClimate::TestReporter.start if ENV['CODECLIMATE_REPO_TOKEN']
5
6
 
6
- RSpec.configure do |c|
7
-
8
- end
7
+ RSpec.configure do |_c|
8
+ end
@@ -1,12 +1,78 @@
1
1
  require 'spec_helper'
2
-
3
2
  require 'websockethook'
3
+ require 'securerandom'
4
+ require 'rest-client'
4
5
 
5
6
  describe WebSocketHook do
7
+ include Wrong
6
8
 
7
9
  it 'can initialize' do
8
- expect {
10
+ expect do
9
11
  ws = WebSocketHook.new
10
- }.to_not raise_error
12
+ end.to_not raise_error
13
+ end
14
+
15
+ it 'can register a hook' do
16
+ ws = WebSocketHook.new
17
+ data = []
18
+ t = Thread.new { ws.listen { |msg| data << msg } }
19
+
20
+ eventually do
21
+ data.any? do |line|
22
+ line[:type] == 'registered'
23
+ end
24
+ end
25
+
26
+ ws.stop
27
+ t.kill
28
+ end
29
+
30
+ it 'can register a hook with an id' do
31
+ id = "test_#{SecureRandom.hex(4)}"
32
+ ws = WebSocketHook.new
33
+ ws.register id
34
+ data = []
35
+ t = Thread.new { ws.listen { |msg| data << msg } }
36
+
37
+ eventually do
38
+ data.any? do |line|
39
+ line[:type] == 'registered' && line[:data][:id] == id
40
+ end
41
+ end
42
+
43
+ ws.stop
44
+ t.kill
45
+ end
46
+
47
+ it 'can trigger a hook with data' do
48
+ id = "test_#{SecureRandom.hex(4)}"
49
+ ws = WebSocketHook.new
50
+ ws.register id
51
+ data = []
52
+ t = Thread.new { ws.listen { |msg| data << msg } }
53
+ hook_url = ''
54
+
55
+ check_eventually data do |line|
56
+ found = line[:type] == 'registered' && line[:data][:id] == id
57
+ hook_url = line[:data][:url] if found
58
+ found
59
+ end
60
+
61
+ RestClient.post(hook_url,this_is_a:'test')
62
+
63
+ check_eventually data do |line|
64
+ line[:type] == 'hook' && line[:data] == {this_is_a:'test'}
65
+ end
66
+
67
+ ws.stop
68
+ t.kill
69
+ end
70
+
71
+ def check_eventually(data, &block)
72
+ eventually do
73
+ data.any? do |line|
74
+ block.yield(line)
75
+ end
76
+ end
11
77
  end
12
- end
78
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websockethook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.01
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Skierkowski
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 10.4.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: wrong
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.7.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.7.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: rest-client
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.0
69
97
  description: Listen for web hooks in your app without creating a web service.
70
98
  email:
71
99
  - maciej@factor.io