irc: Update IRC code to use simpler suspendable ports system.
[8sync.git] / 8sync / systems / irc.scm
index 1333c3c5868424a19f12ee1812c06063dfd3554a..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 (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-run (handle-line
-                          socket
-                          ready-line
-                          username))))
-          (_ #f))))
-    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))