* riece-signal.el: Require 'riece-options for riece-debug.
[riece] / lisp / riece-async.el
index 8ac4e89..34b0b16 100644 (file)
 
 ;;; Commentary:
 
-;; This program allows to connect IRC server via asynchronous proxy
-;; which responds to PING request from server in background.
+;; This program allows to connect to an IRC server via local proxy
+;; which responds to PING requests from server.
 
 ;; To use, add the following line to your ~/.riece/init.el:
 ;; (add-to-list 'riece-addons 'riece-async)
 
-;; If you want to enable this feature to per server, write the server
+;; If you want to enable this feature per server, write the server
 ;; spec like this:
 ;; (add-to-list 'riece-server-alist
 ;;              '("async" :host "irc.tokyo.wide.ad.jp"
@@ -37,6 +37,8 @@
 
 ;;; Code:
 
+(require 'riece-options)
+
 (defgroup riece-async nil
   "Connect to IRC server via asynchronous proxy"
   :prefix "riece-"
 
 (defcustom riece-async-server-program
   '("\
+require 'io/nonblock'
 socket = TCPSocket.new(" host ", " service ")
-$stdout.write(\"NOTICE CONNECTED\r\n\")
+$stdout.write(\"NOTICE CONNECTED #{$$}\\r\\n\")
 $stdout.flush
+$stdout.nonblock = true
+trap('STOP', 'IGNORE')
+trap('TSTP', 'IGNORE')
+wfds_in = []
+buf = ''
 loop do
-  rfds, = select([socket, $stdin])
-  if rfds.delete(socket)
-    line = socket.gets(\"\r\n\")
+  rfds, wfds, = select([socket, $stdin], wfds_in)
+  unless wfds.empty?
+    until buf.length <= " max-buffer-size "
+      i = buf.index(\"\\r\\n\")
+      break unless i
+      buf.slice!(0 .. i + 1)
+    end
+    begin
+      until buf.empty?
+        len = $stdout.syswrite(buf)
+        buf.slice!(0 .. len)
+      end
+      wfds_in = []
+    rescue Errno::EAGAIN
+    end
+  end
+  if rfds.include?(socket)
+    line = socket.gets(\"\\r\\n\")
     break unless line
-    if line =~ /^(?::[^ ]+ +)?PING +(.+)\r\n/i
-      socket.write(\"PONG #{$1}\r\n\")
+    if line =~ /^(?::[^ ]+ +)?PING +(.+)\\r\\n/i
+      socket.write(\"PONG #{$1}\\r\\n\")
       socket.flush
     else
-      $stdout.write(line)
-      $stdout.flush
+      wfds_in = [$stdout]
+      buf << line
     end
   end
-  if rfds.delete($stdin)
-    line = $stdin.gets(\"\r\n\")
+  if rfds.include?($stdin)
+    line = $stdin.gets(\"\\r\\n\")
     break unless line
     socket.write(line)
     socket.flush
   end
 end
 socket.close
-exit
 ")
-  "Ruby program of asynchronous proxy"
+  "Ruby program of asynchronous proxy."
   :type 'list
   :group 'riece-async)
 
+(defcustom riece-async-max-buffer-size 65535
+  "Maximum size of the write buffer."
+  :type 'integer
+  :group 'riece-async)
+
 (defun riece-async-substitute-variables (program variable value)
   (setq program (copy-sequence program))
   (let ((pointer program))
@@ -97,13 +124,17 @@ exit
                         (apply #'concat
                                (riece-async-substitute-variables
                                 (riece-async-substitute-variables
-                                 riece-async-server-program
-                                 'host
-                                 (concat "'" host "'"))
-                                'service
-                                (if (numberp service)
-                                    (number-to-string service)
-                                  (concat "'" service "'")))))
+                                 (riece-async-substitute-variables
+                                  riece-async-server-program
+                                  'host
+                                  (concat "'" host "'"))
+                                 'service
+                                 (if (numberp service)
+                                     (number-to-string service)
+                                   (concat "'" service "'")))
+                                'max-buffer-size
+                                (number-to-string
+                                 riece-async-max-buffer-size))))
     (process-send-string process "\0\n") ;input to process is needed
     (if buffer
        (save-excursion
@@ -111,7 +142,8 @@ exit
          (while (and (eq (process-status process) 'run)
                      (progn
                        (goto-char (point-min))
-                       (not (looking-at "NOTICE CONNECTED"))))
+                       (not (looking-at (format "NOTICE CONNECTED %d"
+                                                (process-id process))))))
            (accept-process-output process))))
     process))