Author: nornagon
Date: 2005-04-11 22:36:42 -0400 (Mon, 11 Apr 2005)
New Revision: 669

Added:
   trunk/clients/ravish/
   trunk/clients/ravish/ravish.rb
Log:
Ravish -- initial import

Added: trunk/clients/ravish/ravish.rb
===================================================================
--- trunk/clients/ravish/ravish.rb      2005-04-10 19:19:33 UTC (rev 668)
+++ trunk/clients/ravish/ravish.rb      2005-04-12 02:36:42 UTC (rev 669)
@@ -0,0 +1,485 @@
+# ravish -- Haver client written in ruby
+
+$:.unshift "/home/nornagon/dev/termvisual/lib"
+
+require 'term/visual'
+require 'socket'
+require 'io/nonblock'
+require 'observer'
+require 'thread'
+require 'delegate'
+
+class RavishVT < Term::Visual
+       def message msg
+               $windows[0][1].addline msg, 
'%(bblue)-%(bwhite)!%(bblue)-%(default) '
+       end
+end
+
+$vt = RavishVT.new
+
+$vt.global_prefix = lambda { Time.now.strftime("%H:%M:%S ") }
+
+palette = {
+       'bblue'         => 'bold blue on default',
+       'bwhite'        => 'bold white on default',
+       'nick'          => 'default on default',
+       'nickdecs'      => 'bold black on default',
+       'action'        => 'bold white on default',
+       'statdecs'      => 'cyan on blue',
+}
+
+$vt.palette.setcolors(palette)
+
+$windows = []
+
+$windows[0] = ['(server)', $vt.create_window]
+$windows[0][1].title = "Ravish: Haver client"
+
+switch_window = lambda { |ch|
+       win = nil
+          if ch == ?1 then win = 1
+       elsif ch == ?2 then win = 2
+       elsif ch == ?3 then win = 3
+       elsif ch == ?4 then win = 4
+       elsif ch == ?5 then win = 5
+       elsif ch == ?6 then win = 6
+       elsif ch == ?7 then win = 7
+       elsif ch == ?8 then win = 8
+       elsif ch == ?9 then win = 9
+       elsif ch == ?0 then win = 10
+       elsif ch == ?q then win = 11
+       elsif ch == ?w then win = 12
+       elsif ch == ?e then win = 13
+       elsif ch == ?r then win = 14
+       elsif ch == ?t then win = 15
+       elsif ch == ?y then win = 16
+       elsif ch == ?u then win = 17
+       elsif ch == ?i then win = 18
+       elsif ch == ?o then win = 19
+       else
+               return
+       end
+       if $windows[win-1] and to = $windows[win-1][1]
+               $vt.switch_window(to)
+       end
+}
+$vt.bind('A-1', switch_window)
+$vt.bind('A-2', switch_window)
+$vt.bind('A-3', switch_window)
+$vt.bind('A-4', switch_window)
+$vt.bind('A-5', switch_window)
+$vt.bind('A-6', switch_window)
+$vt.bind('A-7', switch_window)
+$vt.bind('A-8', switch_window)
+$vt.bind('A-9', switch_window)
+$vt.bind('A-0', switch_window)
+$vt.bind('A-Q', switch_window)
+$vt.bind('A-W', switch_window)
+$vt.bind('A-E', switch_window)
+$vt.bind('A-R', switch_window)
+$vt.bind('A-T', switch_window)
+$vt.bind('A-Y', switch_window)
+$vt.bind('A-U', switch_window)
+$vt.bind('A-I', switch_window)
+$vt.bind('A-O', switch_window)
+
+module Haver
+       module Event
+               CONNECTING = 0
+               CONNECTED = 1
+               MESG_RECV = 2
+               DISCONNECTING = 3
+               DISCONNECTED = 4
+       end
+
+       class Connector
+               include Observable
+
+               BufSize = 128
+
+               attr_reader :server, :port
+               attr_accessor :nick
+
+               def initialize server, port=7070, hash={}
+                       @server = server || hash['server'] || 'hardison.net'
+                       @port = port || hash['port'] || 7070
+                       @nick = hash['nick'] || 'nornagon'
+
+                       @socket = nil
+                       @alive = false
+                       @sendqueue = Queue.new
+                       @recvqueue = Queue.new
+
+                       @recvthread = nil
+                       @sendthread = nil
+               end
+
+               def open
+                       if self.alive?
+                               return false
+                       end
+
+                       notify Event::CONNECTING
+                       begin
+                               @socket = TCPSocket.new(@server, @port)
+                       rescue StandardError, SocketError
+                               notify Event::LINK_FAILED, $!
+                               return false
+                       end
+                       @socket.nonblock = true
+
+                       @recvthread = Thread.new do
+                               self.readfromsocket
+                       end
+
+                       @sendthread = Thread.new do
+                               self.writetosocket
+                       end
+
+                       notify Event::CONNECTED
+                       return true
+               end
+
+               def close
+                       notify Event::DISCONNECTING
+
+                       if [EMAIL PROTECTED] and @recvthread.alive?
+                               @recvthread.exit
+                       end
+
+                       if [EMAIL PROTECTED] and @sendthread.alive?
+                               @sendthread.exit
+                       end
+
+                       @socket.close unless @socket.closed?
+
+                       notify Event::DISCONNECTED
+               end
+
+               def alive?
+                       if [EMAIL PROTECTED](Thread) || [EMAIL 
PROTECTED](Thread)
+                               return false
+                       end
+                       if [EMAIL PROTECTED] || [EMAIL PROTECTED] || 
@socket.closed?
+                               return false
+                       end
+                       
+                       return true
+               end
+
+               def write msg
+                       if msg.kind_of?(Array)
+                               @sendqueue.push msg.join("\t") + "\r\n"
+                       else
+                               @sendqueue.push msg
+                       end
+               end
+
+               def read
+                       @recvqueue.pop
+               end
+
+               protected
+
+               def notify event
+                       changed
+                       notify_observers event, Time.now
+               end
+
+               def readfromsocket
+                       buf = ''
+                       loop do
+                               if @socket.eof?
+                                       break
+                               end
+                               begin
+                                       res = select([EMAIL PROTECTED])
+                                       if res
+                                               until buf =~ /\r\n/ do
+                                                       read_str = 
@socket.read(1)
+                                                       buf += read_str
+                                                       Thread.pass
+                                               end
+                                               
@recvqueue.push(buf.slice!(/^(.+?)\r\n/).chomp)
+                                               notify Event::MESG_RECV
+                                       end
+                               rescue StandardError, SocketError, IOError
+                                       break
+                               end
+                       end
+
+                       @recvthread = nil
+                       self.close
+                       Thread.current.exit
+               end
+
+               def writetosocket
+                       loop do
+                               msg = @sendqueue.pop
+                               sent = 0
+                               begin
+                                       begin
+                                               res = select(nil, [EMAIL 
PROTECTED])
+                                               if res then sent += 
@socket.write msg end
+                                               Thread.pass
+                                       end until sent == msg.length
+                               rescue StandardError, SocketError, IOError
+                                       break
+                               end
+                       end
+
+                       @sendthread = nil
+                       self.close
+                       Thread.current.exit
+               end
+       end
+       
+       class Client < SimpleDelegator
+               def initialize server, port=7070, hash={}
+                       hash['nick'] ||= 'nornagon'
+                       @conn = Connector.new(server, port, hash)
+                       @conn.add_observer(self)
+                       @conn.open
+               end
+               
+               def nick
+                       @conn.nick
+               end
+
+               def update event, time
+                       case event
+                       when Event::CONNECTING
+                               if self.respond_to?(:on_connecting)
+                                       self.on_connecting
+                               end
+                       when Event::CONNECTED
+                               if self.respond_to?(:on_connected)
+                                       self.on_connected
+                               end
+                       when Event::DISCONNECTING
+                               if self.respond_to?(:on_disconnecting)
+                                       self.on_disconnecting
+                               end
+                       when Event::DISCONNECTED
+                               if self.respond_to?(:on_disconnected)
+                                       self.on_disconnected
+                               end
+                       when Event::MESG_RECV
+                               mesg = @conn.read
+                               args = mesg.split("\t")
+                               cmd = args.shift
+                               fun = ("on_cmd_" + cmd.downcase).to_sym
+                               if self.respond_to?(fun)
+                                       self.send fun, *args
+                               elsif self.respond_to?(:on_unhandled_cmd)
+                                       self.send :on_unhandled_cmd, cmd, args
+                               end
+                               if self.respond_to?(:on_mesg_recv)
+                                       self.send :on_mesg_recv, cmd, args
+                               end
+                       end
+               end
+
+               def on_connected
+                       @conn.write ['HAVER', 'ravish/0.0.1']
+               end
+
+               def on_cmd_want cmd
+                       case cmd
+                       when 'IDENT'
+                               @conn.write ['IDENT', @conn.nick]
+                       end
+               end
+               
+               def on_cmd_fail cmd, reason, *args
+                       case cmd
+                       when 'IDENT'
+                               if reason == 'used.id'
+                                       @conn.nick += '_'
+                               end
+                       end
+               end
+
+               def cmd_join cid
+                       @conn.write ['JOIN', cid]
+               end
+
+               def cmd_part cid
+                       @conn.write ['PART', cid]
+               end
+
+               def cmd_list_users cid
+                       @conn.write ['LIST', cid, 'user']
+               end
+
+               def cmd_msg cid, msg
+                       @conn.write ['MSG', cid, '"', msg]
+               end
+
+               def cmd_action cid, act
+                       @conn.write ['MSG', cid, ':', act]
+               end
+       end
+end
+
+# client class
+
+class HaverConnection < Haver::Client
+       def initialize server, port=7070, hash={}
+               super
+       end
+
+       def on_connecting
+               $vt.message "Connecting to [EMAIL PROTECTED]:[EMAIL PROTECTED]"
+       end
+
+       def on_connected
+               $vt.message "Connected."
+               super
+       end
+
+       def on_mesg_recv cmd, args
+               $vt.message "S: #{cmd} #{args.join(' ')}"
+       end
+
+       def on_cmd_haver version
+               $vt.message "Server version: #{version}"
+       end
+
+       def on_cmd_want cmd
+               $vt.message "Server wants #{cmd}"
+               super
+       end
+
+       def on_cmd_accept uid
+               $vt.message "Accepted UID #{uid}"
+       end
+
+       def on_cmd_join cid, uid
+               if uid == @conn.nick
+                       $windows.push [cid, $vt.create_window]
+                       self.cmd_list_users(cid)
+               end
+       end
+
+       def on_cmd_part cid, uid
+               if uid == @conn.nick
+                       win = $windows.find { |w| w[0] == cid }
+                       $vt.delete_window win[1]
+                       $windows.delete_at $windows.index(win)
+                       $vt.message "Left channel #{cid}"
+               end
+       end
+
+       def on_cmd_msg cid, uid, type, msg
+               win = $windows.find { |w| w[0] == cid }
+               msgpre = "%(nickdecs)<%(nick)#{uid}%(nickdecs)>%(default) "
+               mepre = "%(action)* #{uid}%(default) "
+               chpre = "%(channel)#{cid}%(chsep):%(default)"
+               case type
+               when '"'
+                       if win
+                               win[1].addline msg, msgpre
+                       else
+                               $windows[0][1].addline msg, chpre + msgpre
+                       end
+               when ':'
+                       if win
+                               win[1].addline msg, mepre
+                       else
+                               $windows[0][1].addline msg, chpre + msgpre
+                       end
+               end
+       end
+
+       def on_cmd_list cid, type, *args
+               case type
+               when 'user'
+                       win = $windows.find { |w| w[0] == cid }
+                       win ||= $windows[0]
+                       win[1].print "Users in #{cid}: #{args.join ', '}"
+               else
+                       $vt.message "Unknown LIST received: #{type}"
+               end
+       end
+
+       def cmd_raw *args
+               @conn.write args
+       end
+end
+
+$haver = nil
+
+# user commands
+
+ucmds = {
+       'blah' => lambda { |*args|
+               $vt.current_window.print "args: #{args.join ', '}"
+       },
+       'join' => lambda { |*args|
+               if $haver
+                       $haver.cmd_join(args[0])
+               else
+                       $vt.message "You are not connected to a server!"
+               end
+       },
+       'raw' => lambda { |*args|
+               if $haver
+                       $haver.cmd_raw(args)
+               else
+                       $vt.message "You are not connected to a server!"
+               end
+       },
+       'me' => lambda { |args|
+               if $haver
+                       win = $windows.find { |w| w[1] == $vt.current_window }
+                       if win
+                               $haver.cmd_action(win[0], args.join(' '))
+                       end
+               else
+                       $vt.message "You are not connected to a server!"
+               end
+       },
+       'part' => lambda { |args|
+               if $haver
+                       if args.length < 1
+                               win = $windows.find { |w| w[1] == 
$vt.current_window }
+                       else
+                               win = $windows.find { |w| w[0] == args[0] }
+                       end
+                       if win
+                               $haver.cmd_part(win[0])
+                       end
+               else
+                       $vt.message "You are not connected to a server!"
+               end
+       }
+}
+
+# event loop!
+
+$haver = HaverConnection.new('hardison.net')
+
+loop do
+       cwin = $windows.find { |w| w[1] == $vt.current_window }
+       if line = $vt.getline
+               if line =~ %r|^[/.]+(.+)|
+                       # we have a command!
+                       args = $1.split
+                       cmd = args.shift
+                       if ucmds[cmd]
+                               ucmds[cmd].call args
+                       else
+                               $vt.message "Unknown command: #{cmd}"
+                       end
+               else
+                       $haver.cmd_msg(cwin[0], line)
+               end
+       end
+       
+       cwin[1].status = 
"%(statdecs)[%(status)#{Time.now.strftime("%H:%M:%S")}" +
+               "%(statdecs)] [%(status)#{$haver.nick}%(statdecs)] [%(status)" +
+               "#{$windows.index(cwin) + 1}:#{cwin[0]}%(statdecs)]%(status)"
+
+       sleep 0.0001
+end


Reply via email to