witch 0.0.2 → 0.0.3

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.
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