ruby-iarm 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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