Author: bdonlan
Date: 2005-07-18 18:48:30 -0400 (Mon, 18 Jul 2005)
New Revision: 878
Added:
trunk/clients/ravish/evnet.rb
Modified:
trunk/clients/ravish/eventmanager.rb
trunk/clients/ravish/haver/net.rb
trunk/clients/ravish/ravish2.rb
Log:
* Set timer update interval to one second.
* Use EventManager to monitor network sockets, via a new generic event-based
socket class.
Modified: trunk/clients/ravish/eventmanager.rb
===================================================================
--- trunk/clients/ravish/eventmanager.rb 2005-07-18 17:21:00 UTC (rev
877)
+++ trunk/clients/ravish/eventmanager.rb 2005-07-18 22:48:30 UTC (rev
878)
@@ -37,7 +37,9 @@
writehand = @fdwrite.keys
errorhand = @fderror.keys
+ #printf "now=%f nt=%f\n", Time.now.to_f, nexttimer
ret = select(readhand, writehand, errorhand, nexttimer)
+ #print "ret=" + ret.to_s + "\n"
if !ret then ret = [[],[],[]] end
if ret[0].delete @pipe[0]
Added: trunk/clients/ravish/evnet.rb
===================================================================
--- trunk/clients/ravish/evnet.rb 2005-07-18 17:21:00 UTC (rev 877)
+++ trunk/clients/ravish/evnet.rb 2005-07-18 22:48:30 UTC (rev 878)
@@ -0,0 +1,142 @@
+# vim: set ft=ruby ts=4 sw=4 et fileencoding=utf8 :
+# EventManager-based socket class
+# Copyright © 2005 Bryan James Donlan
+# This program is FREE SOFTWARE.
+# You may edit and redistribute it under the same terms as ruby.
+
+
+require 'socket'
+require 'io/nonblock'
+require 'observer'
+
+# Warning: API is NOT permanent. You have been warned.
+
+class EventSocket
+ include Observable
+
+ def initialize socket, observers=[] # todo: host, port (!)
+ if !socket.kind_of?(TCPSocket)
+ raise ArgumentError,
+ "#{self.class}.new takes a TCPSocket as an argument."
+ end
+ @outbuf = ""
+ @inbuf = ""
+ @socket = socket
+ @socket.nonblock = true
+ EventManager.instance.watchread(@socket, lambda { self._readable })
+ EventManager.instance.watcherror(@socket, lambda { self._error })
+ _add_observers(observers)
+ end
+
+ def _add_observers observer
+ if observer.kind_of?(Array)
+ observer.each { |ob| _add_observers(ob) }
+ else
+ add_observer observer
+ end
+ end
+
+ def _readable
+ oldlen = @inbuf.length
+ _check_read
+ newlen = @inbuf.length
+ if oldlen == newlen
+ _error_notify(0) # connection closed
+ else
+ changed
+ notify_observers(self, :input)
+ end
+ end
+
+ def _error
+ _error_notify(1) # TODO: get error code
+ end
+
+ def _error_notify code
+ @error = code
+ EventManager.instance.unwatch @socket
+ @socket.close
+ @outbuf = ""
+ @inbuf = ""
+ if [EMAIL PROTECTED]
+ changed
+ notify_observers(self, :error)
+ end
+ end
+
+ def _check_read
+ b = @socket.gets
+ if b.nil?
+ return
+ end
+ @inbuf += b
+ end
+
+ def read
+ if @closing
+ raise "Tried to read from a closed socket"
+ end
+ b = @inbuf
+ @inbuf = ""
+ return b
+ end
+
+ def write data
+ if @closing
+ raise "Tried to write to a closed socket"
+ end
+ if data == ""
+ return
+ end
+
+ @outbuf += data
+ if @outbuf == data
+ EventManager.instance.watchwrite @socket, lambda { self._write }
+ end
+ end
+
+ def _write
+ c = @socket.write @outbuf
+ @outbuf.slice!(0..c-1)
+ if @outbuf == ""
+ EventManager.instance.unwatchwrite @socket
+ changed
+ notify_observers self, :flushed
+ if @closing
+ EventManager.unwatch @socket
+ @socket.close
+ end
+ end
+ end
+
+ def flushed?
+ return @outbuf == ""
+ end
+
+ def readable?
+ return [EMAIL PROTECTED] && @inbuf != ""
+ end
+
+ def closed?
+ return @closing
+ end
+
+ def close
+ if @closing
+ return
+ end
+ @closing = 1
+ @inbuf = ""
+ EventManager.unwatchread @socket
+ if @outbuf == ""
+ EventManager.unwatch @socket
+ @socket.close
+ end
+ changed
+ notify_observers self, :closed
+ end
+
+ def to_io
+ return @socket # hope you know what you're doing...
+ end
+end
Modified: trunk/clients/ravish/haver/net.rb
===================================================================
--- trunk/clients/ravish/haver/net.rb 2005-07-18 17:21:00 UTC (rev 877)
+++ trunk/clients/ravish/haver/net.rb 2005-07-18 22:48:30 UTC (rev 878)
@@ -6,6 +6,7 @@
require 'socket'
require 'io/nonblock'
require 'observer'
+require 'evnet'
module Haver
class Net
@@ -28,71 +29,40 @@
end
}
end
- @socket = socket
- socket.nonblock = true
+ @socket = EventSocket.new socket, self
@buffer = ''
- @outbox = Queue.new
- @closed = false
-
- @rthread = Thread.new { rthread }
- @wthread = Thread.new { wthread }
end
def put string
- if @closed
- return
- end
- @outbox.push string
- self
+ if @socket.closed?
+ return
+ end
+ @socket.write string
end
alias_method :<<, :put
- def rthread
- loop {
- select([EMAIL PROTECTED])
+
+ def update what, why
+ if why == :input
doread
- }
+ elsif why == :error
+ event :error, "The socket exploded for some
reason."
+ end
end
-
- def wthread
- loop {
- m = @outbox.pop
- select(nil, [EMAIL PROTECTED])
- dowrite m
- }
- end
-
+
def doread
- if @socket.closed? || @closed
+ if @socket.closed?
raise "Tried to read from closed socket."
end
- if b = @socket.gets
- b.each("\r\n") { |l|
- if l =~ /\r\n$/
- if @buffer.empty?
- event :data, l.chomp
- else
- event :data, @buffer +
l.chomp
- @buffer = ''
- end
- else
- @buffer += l
- end
- }
+ @buffer += @socket.read
+ while !(idx = @buffer.index "\r\n").nil?
+ l = @buffer.slice!(0..(idx + 1))
+ event :data, l.chomp
end
end
+ private :doread
- def dowrite m
- if @socket.closed? or @closed
- return
- end
- b = 0
- begin
- b += @socket.write(m)
- end while b < m.length
- end
-
def event type, *args
changed
notify_observers type, *args
@@ -100,22 +70,12 @@
private :event
def close
- # TODO: defer until flush maybe?
- unless write_ready?
- EventManager.instance.unwatch self
- @socket.close
- end
- @closed = true
- end
+ @socket.close
+ end
def closed?; @socket.closed?; end
- def eof?; @socket.eof?; end
- def write_ready?
- [EMAIL PROTECTED]
- end
-
def to_io
- @socket
+ @socket.to_io
end
end
end
Modified: trunk/clients/ravish/ravish2.rb
===================================================================
--- trunk/clients/ravish/ravish2.rb 2005-07-18 17:21:00 UTC (rev 877)
+++ trunk/clients/ravish/ravish2.rb 2005-07-18 22:48:30 UTC (rev 878)
@@ -231,7 +231,7 @@
def statbar_wheel arg=nil
statbar_update
- EventManager.instance.in 0.5, self.method(:statbar_wheel)
+ EventManager.instance.in 1, self.method(:statbar_wheel)
end
def statbar_update