witch 0.0.2 → 0.0.3

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: f4aec34f53b5eefdb9e1ef701556c0b9834f23ae
4
- data.tar.gz: 99bf4a228960cc0e830136b57e00562e4254b5fc
3
+ metadata.gz: a844251fad9136572ae168e4ccec604679651caf
4
+ data.tar.gz: 51f9b573a0bfcb8b59885ed2d88e5c518455d7b4
5
5
  SHA512:
6
- metadata.gz: 3b6c2d058d1fc8c524756b0662b65f7d7d4a601902e96c699b886b96348a47e9e2291f2514df161e95e13d4368d411b3ae3828c7ccad8726e5fcc6e3952bdcd2
7
- data.tar.gz: a55381d307d1c6cea404640a135da9d553730074b39807d5397e5f35c6b13cba06e3c87b8f0c80ef554bcb08878ab58654fcb3df1567d936f1f7ff5ecc810ad8
6
+ metadata.gz: 47e2ab33086fa1b4bc303dd5fddd3fdb3abca21d43dd263a4ba7db1990bf23bd2236d61eb37552febae197018277c674f8a8490391ffa11fa41e824e36ae4f5f
7
+ data.tar.gz: 015e88a9dbb40aaa85f321bb086a3d809c249811252429d0803f7a7a60d26101ed3147f6cc0ce98c173ebe155ef5d426ff3b3683041bd39c526f868e2ebd3638
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'puma'
4
+ gem 'witch', :path => '../..'
@@ -0,0 +1,21 @@
1
+ require 'bundler/setup'
2
+ require 'witch'
3
+
4
+ class HelloWorld
5
+ def initialize
6
+ @response_text = 'Hello World!'
7
+
8
+ Witch.init(:logger => Logger.new(STDOUT))
9
+
10
+ Witch.on('change_text') do |text|
11
+ puts 'Got new text: ' + text
12
+ @response_text = text
13
+ end
14
+ end
15
+
16
+ def call(env)
17
+ [200, {"Content-Type" => "text/html"}, [@response_text]]
18
+ end
19
+ end
20
+
21
+ run HelloWorld.new
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'witch'
3
+
4
+ text = ARGV[0] || "Random number: #{rand(100)}"
5
+ puts "Updating new text: #{text}"
6
+
7
+ Witch.init
8
+ Witch.publish 'change_text', text
@@ -1,3 +1,3 @@
1
1
  module Witch
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
@@ -1,5 +1,5 @@
1
1
  require 'redis'
2
- require 'json'
2
+ require 'logger'
3
3
 
4
4
  module Witch
5
5
 
@@ -10,12 +10,21 @@ module Witch
10
10
  def init(options = {})
11
11
  raise 'Already initialized!' if @queue
12
12
  @queue = options.delete(:queue) || 'eventstream'
13
+ @logger = options.delete(:logger)
13
14
  @options = options
14
15
  @callbacks = {:once => {}, :on => {}}
15
16
  @channels = []
17
+ @thread = nil
16
18
  @id = Socket.gethostname + '-' + $$.to_s
17
19
  end
18
20
 
21
+ def reset
22
+ return unless @queue
23
+ disconnect # clears @callbacks[:once]
24
+ @callbacks[:on] = {}
25
+ @queue = nil
26
+ end
27
+
19
28
  def once(*events, &block)
20
29
  raise 'Not initialized' unless @callbacks
21
30
  events.each do |event|
@@ -43,21 +52,23 @@ module Witch
43
52
  end
44
53
 
45
54
  def publish(event, data = nil)
55
+ raise 'Not initialized' unless @queue
56
+
46
57
  str = event + '___' + data.to_s
47
58
 
48
59
  lock.synchronize do
49
60
  # first, send to everyone on the main queue
50
- puts '[publisher] Publishing on queue ' + @queue
61
+ logger.debug '[publisher] Publishing on queue ' + @queue
51
62
  connection.publish(@queue, str)
52
63
 
53
64
  # if one or more clients are subscribed to the 'once' queue, choose one and notify.
54
65
  if consumer = connection.smembers('subscribers:' + event.to_s).shuffle.first
55
66
  # connection.publish(['events', event, subscriber].join(':'), data)
56
- puts "[publisher] Found consumer for #{event}: #{consumer}"
67
+ logger.info "[publisher] Found consumer for #{event}: #{consumer}"
57
68
  count = connection.publish(consumer, str)
58
69
 
59
70
  if count == 0
60
- puts "[publisher] Consumer #{consumer} disconnected! Removing and retrying..."
71
+ logger.warn "[publisher] Consumer #{consumer} disconnected! Removing and retrying..."
61
72
  connection.srem('subscribers:' + event.to_s, consumer)
62
73
  raise ConsumerDisconnected, "name: #{consumer}"
63
74
  end
@@ -69,11 +80,23 @@ module Witch
69
80
  retry
70
81
  end
71
82
 
83
+ def wait
84
+ @thread.join
85
+ end
86
+
72
87
  def disconnect
73
88
  return unless @id
89
+
74
90
  @callbacks[:once].keys.each do |event|
75
91
  unregister_from(event)
76
92
  end
93
+
94
+ return unless @thread
95
+
96
+ logger.warn '[consumer] Disconnecting!'
97
+ lock.synchronize do
98
+ @thread.kill
99
+ end
77
100
  end
78
101
 
79
102
  private
@@ -81,31 +104,37 @@ module Witch
81
104
  def register_for(event)
82
105
  lock.synchronize do
83
106
  count = connection.sadd('subscribers:' + event.to_s, @id)
84
- puts "[consumer] Registered. Queue contains #{count} listeners."
107
+ logger.debug "[consumer] Registered. Queue contains #{count} listeners."
85
108
  end
109
+ rescue => e
110
+ logger.error '[consumer] Register error: ' + e.inspect
86
111
  end
87
112
 
88
113
  def unregister_from(event)
89
114
  lock.synchronize do
90
- puts "[consumer] Unregistering from #{event} processing queue."
115
+ logger.debug "[consumer] Unregistering from #{event} processing queue."
91
116
  connection.srem('subscribers:' + event.to_s, @id)
92
117
  end
93
118
  rescue => e
94
- puts e.inspect
119
+ logger.error '[consumer] Unregister error: ' + e.inspect
95
120
  end
96
121
 
97
122
  def listen(type, queue)
98
123
  lock.synchronize do
99
- puts "[consumer] Subscribing to queue #{queue} on new thread..."
124
+ logger.debug "[consumer] Subscribing to queue #{queue} on new thread..."
100
125
  @channels.push(queue)
101
- Thread.new do
126
+ @thread = Thread.new do
102
127
  # connection.subscribe(['events' + event + id].join(':')) do |on|
103
128
  connection.subscribe(queue) do |on|
104
129
  on.subscribe do |channel, subscriptions|
105
-
106
- puts "[consumer] Subscribed to #{channel} (#{subscriptions} subscriptions)"
130
+ logger.info "[consumer] Subscribed to #{channel} (#{subscriptions} subscriptions)"
107
131
  raise "Existing subscribers!" if subscriptions > 1
108
132
  end
133
+
134
+ on.unsubscribe do |channel, subscriptions|
135
+ logger.info "Unsubscribed from ##{channel} (#{subscriptions} subscriptions)"
136
+ end
137
+
109
138
  on.message do |channel, msg|
110
139
  process(type, msg)
111
140
  end
@@ -114,26 +143,25 @@ module Witch
114
143
  end
115
144
  rescue => e
116
145
  @channels.delete(queue)
117
- puts e.message
146
+ logger.error '[consumer] ' + e.message
118
147
  end
119
148
 
120
149
  def process(type, msg)
121
150
  parts = msg.split('___')
122
- data = parts[1] ? JSON.parse(parts[1]) : nil
123
- fire_callbacks(type, parts[0], data)
151
+ fire_callbacks(type, parts[0], parts[1])
124
152
  rescue => e
125
- puts "[consumer] Error parsing message: #{e.message}"
153
+ logger.error "[consumer] Error parsing message: #{e.message}"
126
154
  end
127
155
 
128
156
  def fire_callbacks(type, event, data)
129
157
  return if @callbacks.nil?
130
- lock.synchronize do
158
+ # lock.synchronize do
131
159
  (@callbacks[type][event.to_sym] || []).each do |callback|
132
160
  callback.call(data)
133
161
  end
134
- end
162
+ # end
135
163
  rescue => e
136
- puts "[consumer] Error firing callback: #{e.message}"
164
+ logger.error "[consumer] Error firing callback: #{e.message}"
137
165
  end
138
166
 
139
167
  def lock
@@ -149,6 +177,10 @@ module Witch
149
177
  @channels.include?(queue)
150
178
  end
151
179
 
180
+ def logger
181
+ @logger || Logger.new(nil)
182
+ end
183
+
152
184
  end
153
185
 
154
186
  end
@@ -2,43 +2,89 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe 'witch' do
4
4
 
5
- before do
6
- @called = {}
5
+ before(:each) do
6
+ Witch.reset
7
7
  end
8
8
 
9
9
  after(:all) do
10
10
  # Witch.disconnect
11
11
  end
12
12
 
13
- def register(type)
14
- Witch.init
15
- Witch.send(type, 'some_event') do
16
- # puts 'calledxxxxxxxxx'
17
- @called[$$] = true
13
+ def register(type, event_name)
14
+ Witch.send(type, event_name) do
15
+ @called[event_name] = {} unless @called[event_name]
16
+ @called[event_name][$$] = true
17
+ sleep 0.1
18
+ puts Witch.disconnect
18
19
  end
19
- sleep 0.1
20
+ end
21
+
22
+ describe 'init' do
23
+
24
+ it 'works if called once' do
25
+ expect do
26
+ Witch.init
27
+ end.not_to raise_error
28
+ end
29
+
30
+ it 'fires error if called twice' do
31
+ expect do
32
+ Witch.init
33
+ Witch.init
34
+ end.to raise_error('Already initialized!')
35
+ end
36
+
20
37
  end
21
38
 
22
39
  describe 'once' do
23
40
 
41
+ before do
42
+ Witch.init(:logger => Logger.new(STDOUT))
43
+ @called = {}
44
+ end
45
+
24
46
  describe 'single process' do
25
47
 
26
- before do
27
- register :once
48
+ describe 'single listener' do
49
+
50
+ before do
51
+ register(:once, 'some_event')
52
+ end
53
+
54
+ it 'fires event once' do
55
+ Witch.publish 'some_event'
56
+ Witch.wait
57
+ expect(@called['some_event'].keys.count).to be(1)
58
+ expect(@called['some_event'].keys.first).to be($$)
59
+ end
60
+
28
61
  end
29
62
 
30
- it 'fires event once' do
31
- puts 'publishing'
32
- Witch.publish 'some_event'
33
- puts @called.inspect
34
- # @called.keys.should == $$
63
+ describe 'multiple listeners' do
64
+
65
+ before do
66
+ register(:once, 'some_other_event')
67
+ register(:once, 'some_other_event')
68
+ end
69
+
70
+ it 'fires event once' do
71
+ Witch.publish 'some_other_event'
72
+ Witch.wait
73
+ expect(@called['some_other_event'].keys.count).to be(1)
74
+ expect(@called['some_other_event'].keys.first).to be($$)
75
+ end
76
+
35
77
  end
36
78
 
37
79
  end
38
80
 
39
81
  describe 'multi process' do
40
82
 
41
- it 'fires event once' do
83
+ describe 'single listener per process' do
84
+
85
+ end
86
+
87
+ describe 'multiple listeners per process' do
42
88
 
43
89
  end
44
90
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: witch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomás Pollak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-30 00:00:00.000000000 Z
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -68,6 +68,9 @@ files:
68
68
  - Gemfile
69
69
  - README.md
70
70
  - Rakefile
71
+ - examples/puma/Gemfile
72
+ - examples/puma/config.ru
73
+ - examples/puma/update.rb
71
74
  - lib/version.rb
72
75
  - lib/witch.rb
73
76
  - sandbox/api.rb