ruby-iarm 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.
data/CHANGELOG CHANGED
@@ -1,2 +1,5 @@
1
+ v0.0.3. Many bugfixes and enhancements. First production-ready version
2
+
1
3
  v0.0.2. Move unneeded files from bin to test
4
+
2
5
  v0.0.1. First version
data/Manifest CHANGED
@@ -7,7 +7,9 @@ example/IARMserver.rb
7
7
  example/chattest.rb
8
8
  example/chattest_sniffer.rb
9
9
  lib/iarm.rb
10
+ lib/iarm/channel.rb
10
11
  lib/iarm/client.rb
12
+ lib/iarm/handle.rb
11
13
  lib/iarm/msg.rb
12
14
  lib/iarm/msg/channel_member.rb
13
15
  lib/iarm/msg/join.rb
@@ -16,7 +18,6 @@ lib/iarm/msg/timeout.rb
16
18
  lib/iarm/msg/topic.rb
17
19
  lib/iarm/server.rb
18
20
  lib/iarm/timer.rb
19
- ruby-iarm.gemspec
20
21
  test/performance_test.rb
21
22
  test/test_iarm.rb
22
23
  Manifest
data/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
1
  require 'echoe'
2
- Echoe.new('ruby-iarm')
3
-
2
+ Echoe.new('ruby-iarm') do |g|
3
+ g.summary = 'IRC-like Messaging Server for Ruby'
4
+ g.author = 'Andrew Snow'
5
+ g.email = 'andrew@modulus.org'
6
+ end
@@ -1,5 +1,5 @@
1
1
 
2
- ['timer', 'msg', 'server', 'client'].each do |x|
2
+ ['timer', 'msg', 'server', 'client', 'handle', 'channel'].each do |x|
3
3
  require("#{File.dirname(__FILE__)}/iarm/" + x)
4
4
  end
5
5
 
@@ -0,0 +1,29 @@
1
+
2
+ module Iarm
3
+ class Channel
4
+
5
+
6
+ attr_reader :created_at, :name
7
+ attr_accessor :members, :topic, :key
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ @key = key
12
+ @members = {}
13
+ @created_at = Time.now.to_i
14
+ @topic = nil
15
+ end
16
+
17
+ def post(handle, msg)
18
+ handle.say(self, msg)
19
+ end
20
+
21
+ def empty?
22
+ @members.empty?
23
+ end
24
+
25
+ def members_by_name
26
+ @members.keys.inject({}) {|hash,handle| hash[handle.name] = @members[handle] ; hash }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,83 @@
1
+
2
+ module Iarm
3
+ class Handle
4
+
5
+ attr_reader :touched_at, :created_at, :name, :timer
6
+ attr_accessor :ttl, :channels
7
+
8
+ def initialize(name)
9
+ @msg_mutex = Mutex.new
10
+ @channels = {}
11
+ @name = name
12
+ @timer = Iarm::Timer.new
13
+ @created_at = Time.now.to_i
14
+ @ttl = 90
15
+ @msgs = []
16
+ self.touch
17
+ end
18
+
19
+ def timed_out?
20
+ (@touched_at + @ttl) < Time.now.to_i
21
+ end
22
+
23
+ def next_msg
24
+ @msg_mutex.synchronize { @msgs.shift }
25
+ end
26
+
27
+ def push_msg(msg)
28
+ @msg_mutex.synchronize { @msgs << msg }
29
+ end
30
+
31
+ def no_msgs?
32
+ @msgs.empty?
33
+ end
34
+
35
+ def touch
36
+ @touched_at = Time.now.to_i
37
+ end
38
+
39
+ def timeout # returns list of channels that this handle was a member of
40
+ @channels.keys.select do |channel|
41
+ channel.members.delete(self)
42
+ channel.post(self, Msg::Timeout.new(channel.name, self.name))
43
+ @channels.delete(channel)
44
+ true
45
+ end
46
+ end
47
+
48
+
49
+ def depart(channel) # returns a list of channels that we departed
50
+ @channels.keys.select do |ch|
51
+ if channel.nil? || ch == channel
52
+ ch.members.delete(self)
53
+ @channels.delete(ch)
54
+ ch.post(self, Msg::Part.new(ch.name, self.name))
55
+ true
56
+ end
57
+ end
58
+ end
59
+
60
+ def join(channel)
61
+ @channels[channel] = channel.members[self] = Time.now.to_i
62
+ send_msg(channel.topic) if channel.topic
63
+ channel.post(self, Msg::Join.new(channel.name, self.name, @channels[channel]))
64
+ end
65
+
66
+ def send_msg(msg)
67
+ if(msg.kind_of?(Msg::Topic) || @name != msg.from)
68
+ #puts "MSG[#{msg.class}] <##{msg.channel}:#{msg.from}> #{@name} : #{msg.data}"
69
+ self.push_msg(msg)
70
+ self.poke
71
+ end
72
+ end
73
+
74
+ def poke
75
+ @timer.poke
76
+ end
77
+
78
+ def say(channel, msg)
79
+ channel.members.each_key {|member| member.send_msg(msg) }
80
+ end
81
+
82
+ end
83
+ end
@@ -1,8 +1,7 @@
1
1
 
2
-
3
2
  Iarm::Msg = Struct.new(:channel, :from, :data)
4
3
 
5
4
  ['join', 'part', 'channel_member', 'timeout', 'topic'].each do |x|
6
- require("#{File.dirname(__FILE__)}/msg/" + x)
5
+ require("#{File.dirname(__FILE__)}/msg/#{x}")
7
6
  end
8
7
 
@@ -3,63 +3,51 @@ require 'thread'
3
3
  require 'drb'
4
4
 
5
5
 
6
-
7
6
  module Iarm
8
7
  class Server
9
8
 
10
- def ping
9
+ def ping(nickname=nil)
10
+ touch_nickname(nickname) if nickname
11
11
  'pong'
12
12
  end
13
- def ttl(ttl_secs)
14
- @ttl_secs = ttl_secs
13
+
14
+ def ttl(nickname, ttl_secs)
15
+ handle = touch_nickname(nickname)
16
+ handle.ttl = ttl_secs
15
17
  end
16
18
 
17
19
  def list(pattern=nil)
18
20
  pattern ? @channels.keys.grep(pattern) : @channels.keys
19
21
  end
20
22
 
21
- def who(channel)
22
- if(@channels.has_key?(channel))
23
- @channel_members[channel] #.each {|w,time| post_msg(who, Msg::ChannelMember.new(channel, w, time)) }
24
- else
25
- {}
26
- end
23
+ def who(channelname)
24
+ (ch = find_channel(channelname)) && ch.members_by_name || {}
27
25
  end
28
26
 
29
- def join(who, channel, key=nil) # returns true if joined, false if denied, and nil if new channel formed
27
+ def join(who, channelname, key=nil) # returns true if joined, false if denied, and nil if new channel formed
30
28
  retval = nil
31
- touch_nickname(who)
32
- @mutex.synchronize do
33
- if(@channels.has_key?(channel))
34
- retval = (@channels[channel] == key)
29
+ handle = touch_nickname(who)
30
+ @channel_mutex.synchronize do
31
+ if(channel = find_channel(channelname))
32
+ retval = channel.key == key # verify password
35
33
  else
36
- @channels[channel] = key
34
+ @channels[channelname].key = key # create the channel
37
35
  end
38
36
 
39
37
  if(retval != false) # if retval is true (joined existing) or nil (new channel formed)
40
- if(!@channel_members[channel].has_key?(who)) # don't re-join them if they've already joined before
41
- @channel_members[channel][who] = clockval
42
- @channels_joined[who] << channel
43
- send_msg(Msg::Join.new(channel, who, @channel_members[channel][who]))
44
- post_msg(who, @topics[channel]) if @topics.has_key?(channel)
38
+ if(!(channel = @channels[channelname]).members.has_key?(handle)) # don't re-join them if they've already joined before
39
+ handle.join(channel)
45
40
  end
46
41
  end
47
42
  end
48
43
  retval
49
44
  end
50
45
 
51
- def depart(who, channel=nil) # nil=depart ALL channels and log out client
52
- @mutex.synchronize do
53
- (channel.nil? ? @channels_joined[who] : [ channel ]).each do |ch|
54
- @channels_joined[who].delete(ch)
55
- if @channel_members[ch].delete(who)
56
- send_msg(Msg::Part.new(ch, who))
57
- end
58
- check_channel_empty(ch)
59
- end
60
- kill_client(who) if(channel.nil?)
61
- end
62
-
46
+ def depart(nickname, channelname=nil) # nil=depart ALL channels and log out client
47
+ handle = touch_nickname(nickname)
48
+ channel = (find_channel(channelname) if channelname)
49
+ handle.depart(channel).each {|ch| check_channel_empty(ch) }
50
+ @handles.delete(nickname) if channelname.nil?
63
51
  end
64
52
 
65
53
  # getmsg(): NOTES
@@ -68,28 +56,15 @@ module Iarm
68
56
  # if who=nil then it listens on all channels, but only one client can do this at once
69
57
  # if another client is already listening with the same who-id, it has the effect of making them return immediately (before their timeout is up)
70
58
  def getmsg(who, timeout=0)
71
- if(@msgs[who].empty? && timeout != 0)
72
- wait_existing = false
73
- msg = @mutex.synchronize do
74
- wait_existing = Iarm::Timer.poke(@listeners[who])
75
- next_msg(who)
76
- end
77
- return msg if(msg)
78
-
79
- if(wait_existing)
80
- Thread.pass while(@mutex.synchronize { @listeners.has_key?(who) })
81
- end
59
+ handle = touch_nickname(who)
60
+ if(timeout != 0 && handle.no_msgs?)
61
+ handle.poke
82
62
 
83
- #puts "Timer.wait: timeout=#{timeout}"
84
- Iarm::Timer.wait(timeout) do |mode|
85
- @mutex.synchronize do
86
- mode ? @listeners[who] = Thread.current : @listeners.delete(who)
87
- end
88
- #puts "IARM getmsg: #{who} #{mode ? 'entering' : 'exiting'} wait with msgcount=#{@msgs[who].length}"
89
- Iarm::Timer.poke(Thread.current) if mode && @msgs[who].length>0 # don't bother sleeping if we already have a new message waiting
63
+ handle.timer.wait(timeout) do |mode|
64
+ mode && handle.no_msgs?
90
65
  end
91
66
  end
92
- @mutex.synchronize { next_msg(who) }
67
+ handle.next_msg
93
68
  end
94
69
 
95
70
  def getmsgs(who, timeout=0)
@@ -100,30 +75,31 @@ module Iarm
100
75
  res
101
76
  end
102
77
 
103
- def say(who, channel, data)
104
- post(Iarm::Msg.new(channel, who, data))
78
+ def say(nickname, channelname, data)
79
+ handle = touch_nickname(nickname)
80
+ if(channel = find_channel(channelname))
81
+ channel.post(handle, Iarm::Msg.new(channelname, nickname, data))
82
+ end
105
83
  end
106
84
 
107
- def set_topic(who, channel, data)
108
- touch_nickname(who)
109
- if @channels.has_key?(channel)
110
- data = Msg::Topic.new(channel, who, data) unless data.kind_of?(Msg::Topic)
111
- if(@topics[channel] != data)
112
- @mutex.synchronize { @topics[channel] = data }
113
- post(data)
114
- data
85
+ def set_topic(nickname, channelname, topic_data)
86
+ handle = touch_nickname(nickname)
87
+ if(channel = find_channel(channelname))
88
+ topic_data = Msg::Topic.new(channelname, nickname, topic_data) unless topic_data.kind_of?(Msg::Topic)
89
+ if(channel.topic != topic_data)
90
+ channel.topic = topic_data
91
+ channel.post(handle, topic_data)
92
+ topic_data
115
93
  end
116
94
  end
117
95
  end
118
96
 
119
- def get_topic(channel)
120
- @topics[channel]
97
+ def get_topic(channelname)
98
+ if(channel = find_channel(channelname))
99
+ channel.topic
100
+ end
121
101
  end
122
102
 
123
- def post(msg)
124
- @mutex.synchronize { send_msg(msg) } if(msg.kind_of?(Msg))
125
- end
126
-
127
103
  def self.start(uri=nil)
128
104
  DRb.start_service(uri, self.new)
129
105
  DRb.thread
@@ -133,43 +109,30 @@ module Iarm
133
109
  REAPER_GRANULARITY = 5 #seconds
134
110
 
135
111
  def initialize
136
- @mutex = Mutex.new()
137
- @reaper_mutex = Mutex.new()
138
- @ttl_secs = 60
139
- @listeners = Hash.new() # { who => Thread }
140
- @msgs = Hash.new() {|hsh,key| hsh[key] = [ ] } # { who => [ msg1, msg2, ...] }
141
- @clients = Hash.new() # { who => time_of_last_activity }
142
- @channel_members = Hash.new() {|hsh,key| hsh[key] = { } } # { channelname => { who1 => join_time }, who2 => ...] }
143
- @channels_joined = Hash.new() {|hsh,key| hsh[key] = [ ] } # { who => [ channel1, channel2 ] }
144
- @channels = Hash.new() # { channelname => password }
145
- @topics = Hash.new() # { channelname => topic }
112
+ @channel_mutex = Mutex.new()
113
+ @handle_mutex = Mutex.new()
114
+ @handles = Hash.new() # { nickname => Handle object }
115
+ @channels = Hash.new() {|hsh,key| hsh[key] = Iarm::Channel.new(key) }
146
116
  @timeout_queue = []
147
117
  reaper_thread
148
118
  end
149
119
 
150
- def touch_nickname(nickname) #TODO: call this
151
- # UPTO THERE
152
- timeout_box = @ttl_secs / REAPER_GRANULARITY #/
153
- @reaper_mutex.synchronize do
154
- @timeout_queue[timeout_box] ||= []
155
- @timeout_queue[timeout_box] << nickname
156
- @clients[nickname] = clockval
120
+ def touch_nickname(nickname, refresh=true) # returns Handle object
121
+ if !@handles.has_key?(nickname)
122
+ @handle_mutex.synchronize { @handles[nickname] ||= Iarm::Handle.new(nickname) }
123
+ end
124
+ handle = @handles[nickname]
125
+ handle.touch
126
+ if(refresh)
127
+ timeout_box = (handle.ttl.to_f / REAPER_GRANULARITY).ceil.to_i #/
128
+ @timeout_queue[timeout_box] ||= {}
129
+ @timeout_queue[timeout_box][handle] = true
157
130
  end
131
+ handle
158
132
  end
159
133
 
160
-
161
- =begin
162
- reaper ideas
163
- ------------
164
-
165
- have a linked list which is in order of things to timeout
166
- when taking something off the list, check its actual timeout value and put it back to sleep if needed
167
- this could be a binary search down the track, for performance
168
-
169
- =end
170
-
171
- def timed_out?(nickname)
172
- (tla = @clients[nickname]) && (tla + @ttl_secs) < clockval
134
+ def find_channel(channelname)
135
+ @channels[channelname] if @channels.has_key?(channelname)
173
136
  end
174
137
 
175
138
  def reaper_thread
@@ -177,25 +140,12 @@ module Iarm
177
140
  loop do
178
141
  kill_list = []
179
142
  sleep REAPER_GRANULARITY
180
- @reaper_mutex.synchronize do
181
- timeoutlist = @timeout_queue.shift
182
- if timeoutlist
183
- timeoutlist.each do |who|
184
- kill_list << who if timed_out?(who)
185
- end
186
- end
143
+ if(timeoutlist = @timeout_queue.shift)
144
+ kill_list = timeoutlist.keys.select {|who| who.timed_out? }
187
145
  end
188
- @mutex.synchronize do
189
- kill_list.each do |who|
190
- if(@channels_joined.has_key?(who))
191
- @channels_joined[who].each do |ch|
192
- @channel_members[ch].delete(who)
193
- send_msg(Msg::Timeout.new(ch, who))
194
- check_channel_empty(ch)
195
- end
196
- end
197
- kill_client(who)
198
- end
146
+ kill_list.each do |who|
147
+ who.timeout.each {|ch| check_channel_empty(ch) }
148
+ @handles.delete(who.name)
199
149
  end
200
150
  end
201
151
  end
@@ -204,37 +154,11 @@ module Iarm
204
154
  def clockval
205
155
  Time.new.to_i
206
156
  end
207
-
208
- def send_msg(msg)
209
- @channel_members[msg.channel].each_key {|w| post_msg(w, msg) }
210
- post_msg(nil, msg) if(@clients.has_key?(nil))
211
- end
212
- def post_msg(who, msg)
213
- if(msg.kind_of?(Msg::Topic) || who != msg.from)
214
- @msgs[who] << msg
215
- Iarm::Timer.poke(@listeners[who]) if(@listeners.has_key?(who))
216
- end
217
- end
218
- def next_msg(who) # returns msg or nil
219
- touch_nickname(who)
220
- @msgs[who].shift
221
- end
157
+
222
158
  def check_channel_empty(channel)
223
- if(@channel_members[channel].empty?)
224
- @channels.delete(channel)
225
- @channel_members.delete(channel)
226
- @topics.delete(channel)
227
- end
228
- end
229
- def kill_client(who)
230
- @channels_joined[who].each do |ch|
231
- @channel_members[ch].delete(who)
232
- check_channel_empty(ch)
159
+ @channel_mutex.synchronize do
160
+ @channels.delete(channel.name) if channel.empty?
233
161
  end
234
- @channels_joined.delete(who)
235
- @clients.delete(who)
236
- @msgs.delete(who)
237
- @listeners.delete(who)
238
162
  end
239
163
 
240
164
  end
@@ -6,44 +6,83 @@ module Iarm
6
6
  class Timeout < Exception; end
7
7
  class Poke < Exception; end
8
8
 
9
- def self.poke(thr)
10
- crit do
11
- if(thr)# && thr.stop?)
12
- thr.raise(Poke.new)
13
- true
14
- else
15
- false
16
- end
9
+ def initialize
10
+ @poked = false
11
+ @mutex = Mutex.new
12
+ @resource = ConditionVariable.new
13
+ end
14
+
15
+ def poke(timeout=false)
16
+ @mutex.synchronize do
17
+ @poked = true if timeout
18
+ @resource.signal
17
19
  end
18
20
  end
19
21
 
20
- def self.wait(timeout)
22
+ def wait(timeout)
21
23
  timer = create_timer(timeout)
22
- yield(true) if block_given?
23
- Thread.stop
24
+ should_wait = true
25
+ should_wait = yield(true) if block_given?
26
+ if should_wait
27
+ @mutex.synchronize do
28
+ @resource.wait(@mutex)
29
+ end
30
+ end
31
+ @poked
24
32
  rescue Timeout
25
- return false
26
- rescue Poke
27
- return true
28
33
  ensure
29
34
  Thread.kill(timer) if(timer && timer.alive?)
30
- yield(false) if block_given?
35
+ yield(false) if block_given?
31
36
  end
32
37
 
33
- def self.crit
34
- yield
35
- end
36
-
37
38
  private
38
- def self.create_timer(timeout)
39
+ def create_timer(timeout)
39
40
  return nil if(timeout.nil?)
40
-
41
41
  waiter = Thread.current
42
42
  Thread.start do
43
- Thread.pass
44
43
  sleep(timeout)
45
- # Thread.critical = true
46
- waiter.raise(Timeout.new)
44
+ poke(true)
45
+ end
46
+ end
47
+
48
+ class << self
49
+ def poke(thr)
50
+ if(thr)# && thr.stop?)
51
+ thr.raise(Poke.new)
52
+ true
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+ def wait(timeout)
59
+ timer = create_timer(timeout)
60
+ yield(true) if block_given?
61
+ Thread.stop
62
+ rescue Timeout
63
+ return false
64
+ rescue Poke
65
+ return true
66
+ ensure
67
+ Thread.kill(timer) if(timer && timer.alive?)
68
+ yield(false) if block_given?
69
+ end
70
+
71
+ def crit
72
+ (@mutex ||= Mutex.new).synchronize { yield }
73
+ end
74
+
75
+ private
76
+ def create_timer(timeout)
77
+ return nil if(timeout.nil?)
78
+
79
+ waiter = Thread.current
80
+ Thread.start do
81
+ Thread.pass
82
+ sleep(timeout)
83
+ # Thread.critical = true
84
+ waiter.raise(Timeout.new)
85
+ end
47
86
  end
48
87
  end
49
88
  end
@@ -2,21 +2,21 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{ruby-iarm}
5
- s.version = "0.0.2"
5
+ s.version = "0.0.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
- s.authors = [""]
9
- s.date = %q{2010-06-07}
10
- s.description = %q{}
11
- s.email = %q{}
12
- s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "README.textile", "lib/iarm.rb", "lib/iarm/client.rb", "lib/iarm/msg.rb", "lib/iarm/msg/channel_member.rb", "lib/iarm/msg/join.rb", "lib/iarm/msg/part.rb", "lib/iarm/msg/timeout.rb", "lib/iarm/msg/topic.rb", "lib/iarm/server.rb", "lib/iarm/timer.rb"]
13
- s.files = ["CHANGELOG", "LICENSE", "README", "README.textile", "Rakefile", "example/IARMserver.rb", "example/chattest.rb", "example/chattest_sniffer.rb", "lib/iarm.rb", "lib/iarm/client.rb", "lib/iarm/msg.rb", "lib/iarm/msg/channel_member.rb", "lib/iarm/msg/join.rb", "lib/iarm/msg/part.rb", "lib/iarm/msg/timeout.rb", "lib/iarm/msg/topic.rb", "lib/iarm/server.rb", "lib/iarm/timer.rb", "ruby-iarm.gemspec", "test/performance_test.rb", "test/test_iarm.rb", "Manifest"]
8
+ s.authors = ["Andrew Snow"]
9
+ s.date = %q{2010-08-25}
10
+ s.description = %q{IRC-like Messaging Server for Ruby}
11
+ s.email = %q{andrew@modulus.org}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "README.textile", "lib/iarm.rb", "lib/iarm/channel.rb", "lib/iarm/client.rb", "lib/iarm/handle.rb", "lib/iarm/msg.rb", "lib/iarm/msg/channel_member.rb", "lib/iarm/msg/join.rb", "lib/iarm/msg/part.rb", "lib/iarm/msg/timeout.rb", "lib/iarm/msg/topic.rb", "lib/iarm/server.rb", "lib/iarm/timer.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "README", "README.textile", "Rakefile", "example/IARMserver.rb", "example/chattest.rb", "example/chattest_sniffer.rb", "lib/iarm.rb", "lib/iarm/channel.rb", "lib/iarm/client.rb", "lib/iarm/handle.rb", "lib/iarm/msg.rb", "lib/iarm/msg/channel_member.rb", "lib/iarm/msg/join.rb", "lib/iarm/msg/part.rb", "lib/iarm/msg/timeout.rb", "lib/iarm/msg/topic.rb", "lib/iarm/server.rb", "lib/iarm/timer.rb", "test/performance_test.rb", "test/test_iarm.rb", "Manifest", "ruby-iarm.gemspec"]
14
14
  s.homepage = %q{}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ruby-iarm", "--main", "README"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{ruby-iarm}
18
18
  s.rubygems_version = %q{1.3.7}
19
- s.summary = %q{}
19
+ s.summary = %q{IRC-like Messaging Server for Ruby}
20
20
  s.test_files = ["test/test_iarm.rb", "test/performance_test.rb"]
21
21
 
22
22
  if s.respond_to? :specification_version then
@@ -1 +1,27 @@
1
1
 
2
+ require "#{File.dirname(__FILE__)}/../lib/iarm"
3
+ Thread.abort_on_exception = true
4
+
5
+ socket_path = 'drbunix:/tmp/.s.perftestiarm'
6
+ num_clients = 4
7
+
8
+ server_pid = fork do
9
+ puts "#{$$} Starting server"
10
+ Iarm::Server.start(socket_path)
11
+ loop { sleep 10 }
12
+ end
13
+
14
+ client_pids = []
15
+
16
+
17
+ # handle sigpipe, check exit values, shutdown on any failures
18
+
19
+
20
+ num_clients.times do
21
+ Iarm::Client.connect(socket_path) or raise 'Cannot connect'
22
+
23
+ end
24
+
25
+
26
+ puts "Finished"
27
+ Process.kill(9, server_pid)
@@ -36,7 +36,37 @@ end
36
36
  class TestIarm < Test::Unit::TestCase
37
37
  include TestIarmServer
38
38
 
39
- def test_join_and_speak
39
+ def test_getmsg_with_timeout
40
+ @client1.join('client1', 'test_channel')
41
+ @client2.join('client2', 'test_channel')
42
+
43
+ # first test timeout with no messages
44
+ starttime = Time.now.to_f
45
+ msg = @client2.getmsg('client2', 2)
46
+ assert_nil msg
47
+ assert_in_delta(2, (Time.now.to_f - starttime), 0.5) # should have waited 2 seconds
48
+
49
+ testerthread = Thread.start do
50
+ sleep 1
51
+ new_connection = new_client
52
+ new_connection.say('client1', 'test_channel', 'TEST message!')
53
+ end
54
+
55
+ begin
56
+ starttime = Time.now.to_f
57
+ msg = @client2.getmsg('client2', 4)
58
+
59
+ assert_in_delta(1, (Time.now.to_f - starttime), 1) # make sure we didn't wait 4 seconds
60
+ assert_instance_of Iarm::Msg, msg
61
+ assert_equal 'client1', msg.from
62
+ assert_equal 'test_channel', msg.channel
63
+ assert_equal 'TEST message!', msg.data
64
+ ensure
65
+ testerthread.join
66
+ end
67
+ end
68
+
69
+ def test_join
40
70
  @client1.join('client1', 'test_channel')
41
71
  @client2.join('client2', 'test_channel')
42
72
 
@@ -125,10 +155,12 @@ class TestIarm < Test::Unit::TestCase
125
155
  end
126
156
 
127
157
  def test_timeout
128
- @client1.ttl(2)
129
158
  @client1.join('client1', 'test_channel')
159
+ @client1.ttl('client1', 2)
130
160
  assert_equal ['client1'], @client2.who('test_channel').keys
131
- sleep(Iarm::Server::REAPER_GRANULARITY + 1)
161
+ assert_equal 'pong', @client1.ping('client1')
162
+ countdown = Iarm::Server::REAPER_GRANULARITY * 2 + 1
163
+ sleep 1 while((countdown -= 1) >= 0 && !@client2.who('test_channel').empty?)
132
164
  assert_equal [], @client2.who('test_channel').keys
133
165
  end
134
166
  end
metadata CHANGED
@@ -1,26 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-iarm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
- - ""
13
+ - Andrew Snow
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-07 00:00:00 +10:00
18
+ date: 2010-08-25 00:00:00 +10:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
22
- description: ""
23
- email: ""
22
+ description: IRC-like Messaging Server for Ruby
23
+ email: andrew@modulus.org
24
24
  executables: []
25
25
 
26
26
  extensions: []
@@ -31,7 +31,9 @@ extra_rdoc_files:
31
31
  - README
32
32
  - README.textile
33
33
  - lib/iarm.rb
34
+ - lib/iarm/channel.rb
34
35
  - lib/iarm/client.rb
36
+ - lib/iarm/handle.rb
35
37
  - lib/iarm/msg.rb
36
38
  - lib/iarm/msg/channel_member.rb
37
39
  - lib/iarm/msg/join.rb
@@ -50,7 +52,9 @@ files:
50
52
  - example/chattest.rb
51
53
  - example/chattest_sniffer.rb
52
54
  - lib/iarm.rb
55
+ - lib/iarm/channel.rb
53
56
  - lib/iarm/client.rb
57
+ - lib/iarm/handle.rb
54
58
  - lib/iarm/msg.rb
55
59
  - lib/iarm/msg/channel_member.rb
56
60
  - lib/iarm/msg/join.rb
@@ -59,10 +63,10 @@ files:
59
63
  - lib/iarm/msg/topic.rb
60
64
  - lib/iarm/server.rb
61
65
  - lib/iarm/timer.rb
62
- - ruby-iarm.gemspec
63
66
  - test/performance_test.rb
64
67
  - test/test_iarm.rb
65
68
  - Manifest
69
+ - ruby-iarm.gemspec
66
70
  has_rdoc: true
67
71
  homepage: ""
68
72
  licenses: []
@@ -102,7 +106,7 @@ rubyforge_project: ruby-iarm
102
106
  rubygems_version: 1.3.7
103
107
  signing_key:
104
108
  specification_version: 3
105
- summary: ""
109
+ summary: IRC-like Messaging Server for Ruby
106
110
  test_files:
107
111
  - test/test_iarm.rb
108
112
  - test/performance_test.rb