¶News
Check out the System Crafters Forum!
- A bunch of cool announcements in a couple of weeks!
¶An IRC Bot with Guile Scheme?
¶Goals
- Leaving a message for another user who is offline
- Making it possible to call back chat history (reply to old messages)
- Attempt to make a simple Matrix bridge
Provide a way for community members to connect their IRC account
Community member puts their IRC nick in a web page, the IRC bot contacts them via private message and asks them to paste a token they got from the web page.
- Add some fun commands of some sort
- Make it possible to gather funny quotes from IRC and relay them to the forum somehow
¶The Final Code
(use-modules (json)
(irc irc)
(irc handlers)
((irc message) #:renamer (symbol-prefix-proc 'msg:))
(ice-9 regex)
(ice-9 match)
(ice-9 threads)
(ice-9 textual-ports)
(web uri)
(web client)
(web server)
(web request)
(web response)
(sxml simple)
(system repl server)
(system repl coop-server))
(define libera-irc #f)
(define libera-nick "crafter-bot")
(define libera-channel "#systemcrafters-live")
(define (libera-irc-connect)
(set! libera-irc (make-irc #:nick libera-nick
#:realname "Crafter Bot"
#:server "irc.libera.chat"
#:port 6697
#:ssl #t))
(install-ping-handler! libera-irc)
(install-printer! libera-irc)
(do-connect libera-irc)
(do-register libera-irc)
;; (do-privmsg libera-irc "NickServ"
;; (format #f "identify ~a ~a"
;; libera-nick
;; (get-libera-pass)))
(do-wait libera-irc)
(add-message-hook! libera-irc (lambda (msg)
(libera-message-hook msg)))
(do-join libera-irc libera-channel))
(define (send-msg! recipient msg-text)
(do-privmsg libera-irc
recipient
msg-text))
(define counter 0)
(define (handle-message msg sender)
(let* ((message-text (msg:trailing msg))
(command-parts (string-split message-text #\ ))
(command (and (pair? command-parts)
(car command-parts))))
(case (and command (string->symbol command))
((!hello)
(send-msg! libera-channel (format #f "Hello, ~a!" sender)))
((!slap)
(let ((target (and (pair? (cdr command-parts))
(cadr command-parts))))
(if target
(send-msg! libera-channel (format #f "~a slaps ~a around with a bit of trout"
sender target))
(send-msg! libera-channel (format #f "~a slaps themself around with a bit of trout"
sender)))))
((!leftpad)
(send-msg! libera-channel "Thank you leftpad 🙏"))
;; ((!roll)
;; (let* ((sides (and (pair? (cdr command-parts))
;; ;; TODO: Make this handle negative numbers!
;; (with-exception-handler
;; (lambda (exn) 6)
;; (lambda ()
;; (string->number (cadr command-parts)))
;; #:unwind? #t))))
;; (send-msg! libera-channel (format #f
;; "You rolled a ~a!"
;; (+ (random (or (and sides (> 0 sides))
;; 6)) 1)))))
((!profile)
(send-msg! libera-channel "✅ emacs mention in the profile"))
((!forum)
(send-msg! libera-channel "You can join the forum at https://forum.systemcrafters.net"))
((!count)
(set! counter (+ counter 1))
(send-msg! libera-channel (format #f "You bothered me ~a times!" counter))))))
(define (handle-private-message msg sender)
(let ((message-text (msg:trailing msg)))
(format #t "*** Excuse me, ~a told me this: ~a\n" sender message-text)
(send-msg! sender (format #f "Hello! You told me: '~a'" message-text))))
(define (libera-message-hook msg)
(let ((sender (and (eqv? (msg:prefix-type msg) 'USER)
(car (msg:prefix msg)))))
(when (and sender
(equal? (msg:command msg) 'PRIVMSG))
;; Handle message
(cond
((string=? (msg:middle msg) libera-channel)
(handle-message msg sender))
((string=? (msg:middle msg) libera-nick)
(handle-private-message msg sender))))))
;; (push-message! `((name . ,nick)
;; (text . ,(msg:trailing msg))))
;;; Message Queue
(define message-queue '())
(define queue-mutex (make-mutex))
(define (push-message! msg)
(with-mutex queue-mutex
(set! message-queue (cons msg message-queue))))
(define (pop-messages!)
(with-mutex queue-mutex
(let ((msgs message-queue))
(set! message-queue '())
msgs)))
;;; Main Threads
(define repl-server-socket
(make-tcp-server-socket #:port 37147))
(define irc-thread
(call-with-new-thread
(lambda ()
(define repl-server (spawn-coop-repl-server repl-server-socket))
(format #t "Connecting to IRC...\n")
(libera-irc-connect)
(format #t "IRC connected, polling...\n")
(while #t
(poll-coop-repl-server repl-server)
(let ((msg (do-listen libera-irc)))
(when msg
(run-message-hook libera-irc msg)))
(usleep 500)))))
(join-thread irc-thread)
