irc: Update IRC code to use simpler suspendable ports system.
authorChristopher Allan Webber <cwebber@dustycloud.org>
Thu, 8 Dec 2016 21:43:15 +0000 (15:43 -0600)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Thu, 8 Dec 2016 21:43:15 +0000 (15:43 -0600)
* 8sync/systems/irc.scm (irc-socket-setup): Set port to be non-blocking.
  (install-socket, make-basic-irc-handler): Remove.
  (irc-loop): New procedure; uses the Guile read-line code to switch
  from the former manual-buffering of make-basic-irc-handler to simply
  using Guile's read-line utility.
  (queue-and-start-irc-agenda!): Use irc-loop.

8sync/systems/irc.scm

index c2fe8e34f74403d48ca11b26d4655f1dd13db449..6262f43a249969326a0782857f228087ab048232 100755 (executable)
@@ -27,6 +27,7 @@
   #:use-module (ice-9 getopt-long)
   #:use-module (ice-9 format)
   #:use-module (ice-9 receive)
+  #:use-module (ice-9 rdelim)
   #:use-module (ice-9 q)
   #:use-module (ice-9 match)
   #:export (;; The only things you definitely need if writing a bot
 (define default-irc-port 6665)
 
 (define* (irc-socket-setup hostname #:optional (inet-port default-irc-port))
-  (let ((s (socket PF_INET SOCK_STREAM 0))
-        (ip-address (inet-ntoa (car (hostent:addr-list (gethost hostname))))))
+  (let* ((s (socket PF_INET SOCK_STREAM 0))
+         (flags (fcntl s F_GETFL))
+         (ip-address (inet-ntop AF_INET (car (hostent:addr-list (gethost hostname))))))
+    (fcntl s F_SETFL (logior O_NONBLOCK flags))
     (connect s AF_INET
              (inet-pton AF_INET ip-address)
              inet-port)
     s))
 
-(define (install-socket socket handler)
-  (display "Installing socket...\n")   ; debugging :)
-  (make-port-request socket #:read handler))
-
 (define irc-eol "\r\n")
 
 (define (irc-line line)
          (newline)))))
   handle-line)
 
-(define (make-basic-irc-handler handle-line username)
-  (let ((buffer '()))
-    (define (reset-buffer)
-      (set! buffer '()))
-    (define (should-read-char socket)
-      (and (not (port-closed? socket))
-           (char-ready? socket)
-           (not (eof-object? (peek-char socket)))))
-    (define (irc-handler socket)
-      (while (should-read-char socket)
-        (set! buffer (cons (read-char socket) buffer))
-        (match buffer
-          ((#\newline #\return (? char? line-chars) ...)
-           (let ((ready-line (list->string (reverse line-chars))))
-             ;; reset buffer
-             (set! buffer '())
-             ;; run it
-             (8sync (handle-line
-                      socket
-                      ready-line
-                      username))))
-          (_ #f)))
-      ;; I need to shut things down on EOF object
-      (cond
-       ((port-closed? socket)
-        (display "port closed time\n")
-        (port-remove-request socket))
-       ((and (char-ready? socket)
-             (eof-object? (peek-char socket)))
-        (display "port eof time\n")
-        (close socket)
-        (port-remove-request socket))))
-    irc-handler))
+(define (irc-loop socket handle-line username)
+  (define (loop)
+    (define line (string-trim-right (read-line socket) #\return))
+    (handle-line socket line username)
+    (cond
+     ;; The port's been closed for some reason, so stop looping
+     ((port-closed? socket)
+      'done)
+     ;; We've reached the EOF object, which means we should close
+     ;; the port ourselves and stop looping
+     ((eof-object? (peek-char socket))
+      (close socket)
+      'done)
+     ;; Otherwise, let's read till the next line!
+     (else (loop))))
+  (loop))
 
 (define default-line-handler (make-handle-line))
 
     (lambda () #f)
     (lambda ()
       (enq! (agenda-queue agenda)
-            (wrap (install-socket
-                   socket
-                   (make-basic-irc-handler
-                    line-handler
-                    username))))
+            (wrap (irc-loop socket line-handler username)))
       (enq! (agenda-queue agenda) (wrap (handle-login socket username
                                                       #:channels channels)))
       (start-agenda agenda))