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


Reply via email to