(define-module (bugafriend ui) #:use-module (bugafriend utils registry) #:use-module (goblins) #:use-module (goblins vat) #:use-module (goblins ocapn ids) #:use-module (fibers) #:use-module (fibers channels) #:use-module (fibers conditions) #:use-module (srfi srfi-9) #:use-module (srfi srfi-1) #:use-module (ice-9 rdelim) #:use-module (ice-9 match) #:use-module (ice-9 exceptions) #:use-module (ice-9 readline) #:use-module (ice-9 suspendable-ports) #:export (say)) ;; ;; https://www.gnu.org/software/guile/manual/guile.html#Non_002dBlocking-I_002fO ;; (let* ((input (current-input-port)) ;; (flags (fcntl input F_GETFL))) ;; (fcntl input F_SETFL (logior O_NONBLOCK flags))) ;; (install-suspendable-ports!) (define ocapn-registry #f) (define listener-actor #f) (define (is-command? str) (and (> (string-length str) 0) (eq? (string-ref str 0) #\/))) (define-record-type (make-console-command name help thunk) console-command? (name console-command-name) (help console-command-help) (thunk console-command-thunk)) (define commands (list (make-console-command "/quit" "- Exits the chat" (λ (args) (loop! #f))) (make-console-command "/help" "- Prints this help" (λ (args) (print-help) (loop! #t))) (make-console-command "/join" " - Switch chats to another listener" (λ (args) (unless (eq? 2 (length args)) (error "Need one argument, the listener sturdyref!")) (let* ((listener-id (list-ref args 1)) (listener-sref (string->ocapn-id listener-id))) (unless listener-sref (error "Badly formatted sturdyref!")) (unless ocapn-registry (error "Relay not yet connected.")) (format #t "Connecting...\n") (on (<- ocapn-registry 'enliven listener-sref) (λ (l) (set! listener-actor l) (format #t "Joined chat.\n") (loop! #t)) #:catch (λ (e) (format #t "Failed: ~a\n" e) (loop! #t)))))))) (define (print-help) (format #t "Command reference:\n") (map (λ (x) (format #t " ~a ~a\n" (console-command-name x) (console-command-help x))) commands)) (define command-names (map console-command-name commands)) (define (%eval-command cmd) (define args (string-split cmd char-set:whitespace)) (define matching-command (find (λ (x) (equal? (console-command-name x) (car args))) commands)) (if matching-command ((console-command-thunk matching-command) args) (begin (format #t "Don't know how to handle ~a.\n\n" cmd) (print-help) (loop! #t)))) (define loop-channel (make-channel)) (define (loop! val) (put-message loop-channel val) val) (define (%loop vat) (with-exception-handler (λ (e) (format #t "Command failed: ~s\n" e) (loop! #t)) (λ () (let ((line (readline))) (with-vat vat (cond ((eq? 0 (string-length line)) (loop! #t)) ((is-command? line) (%eval-command line)) (else (if listener-actor (on (<- listener-actor line) (λ (val) (loop! val))) (begin (format #t "Not connected to anyone yet. Use /join !\n") (loop! #t)))))))) #:unwind? #t)) (define (say setup-sref) (define vat (spawn-vat #:name "Speaker Vat")) (set-readline-prompt! " 🐞 > ") (with-vat vat (format #t "Connecting to relay...\n") (on (prelay-sref->mycapn-registry setup-sref) (λ (r) (set! ocapn-registry r) (format #t "Connected.\n") (loop! #t)) #:catch (λ (e) (format #t "Failed: ~a\n" e) (loop! #t)))) (while (get-message loop-channel) (with-vat vat (syscaller-free-fiber (λ () (%loop vat))))))