You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.5 KiB
138 lines
3.5 KiB
#! /usr/bin/env racket
|
|
#lang racket
|
|
|
|
(require racket/unix-socket)
|
|
(require json)
|
|
|
|
;; Resource management functions
|
|
|
|
(define (bail . args)
|
|
(displayln "/tmp/shelltalk.sock could not be created (may already exist)"
|
|
(current-error-port))
|
|
(exit 1))
|
|
|
|
; All messages come through this socket
|
|
; It is cleaned up after execution finishes
|
|
(define
|
|
control-socket
|
|
(with-handlers ([exn:fail? bail])
|
|
(unix-socket-listen "/tmp/shelltalk.sock")))
|
|
|
|
(define (close-socket in out)
|
|
(close-output-port out)
|
|
(close-input-port in))
|
|
|
|
(define (rm-socket . args)
|
|
; Removes the socket
|
|
(parameterize ([current-error-port
|
|
(open-output-string)])
|
|
|
|
(system "rm /tmp/shelltalk.sock")))
|
|
|
|
|
|
;; Message handling functions
|
|
|
|
(define (write-to entries out)
|
|
(displayln entries)
|
|
(with-handlers ([exn:fail? (const '())])
|
|
(write-json entries out)
|
|
(display "\n" out)))
|
|
|
|
(define (log pid entries)
|
|
(match (thread-receive)
|
|
[(cons 'read out)
|
|
(write-to entries out)
|
|
(log pid entries)]
|
|
|
|
[entry
|
|
(log pid (cons entry entries))]))
|
|
|
|
(define (logger-send loggers pid message)
|
|
(cond
|
|
[(hash-has-key? loggers pid)
|
|
(thread-send (hash-ref loggers pid) message)]
|
|
[else '()]))
|
|
|
|
(define (handle-messages loggers)
|
|
(match (thread-receive)
|
|
[(list 'log pid entry)
|
|
(logger-send loggers pid entry)
|
|
(handle-messages loggers)]
|
|
|
|
[(cons 'spawn pid)
|
|
;; XXX this should check if it exists already
|
|
(handle-messages (hash-set loggers
|
|
pid
|
|
(thread (lambda () (log pid '[])))))]
|
|
|
|
[(cons 'kill pid)
|
|
(kill-thread (hash-ref loggers pid))
|
|
(handle-messages
|
|
(hash-remove loggers pid))]
|
|
|
|
[(list 'read pid out)
|
|
(displayln "got read message")
|
|
; Reads all the logs for a given pid
|
|
(logger-send loggers pid (cons 'read out))
|
|
(handle-messages loggers)]))
|
|
|
|
(define message-handler
|
|
(thread (lambda ()
|
|
(handle-messages
|
|
(make-immutable-hash '[])))))
|
|
|
|
(define (handle-connection in out)
|
|
(define input-string (read-line in 'linefeed))
|
|
(cond
|
|
[(eof-object? input-string)
|
|
(close-socket in out)]
|
|
[else
|
|
(match (string-split input-string)
|
|
[(list "spawn" pid)
|
|
(displayln "got spawn")
|
|
(displayln pid)
|
|
(thread-send message-handler (cons 'spawn pid))
|
|
(handle-connection in out)]
|
|
|
|
[(list "read" pid)
|
|
(displayln "got read")
|
|
(thread-send message-handler (list 'read pid out))
|
|
(handle-connection in out)]
|
|
|
|
[(list "write" pid message)
|
|
(displayln "got write")
|
|
(displayln pid)
|
|
(displayln message)
|
|
(thread-send message-handler (list 'log pid message))
|
|
(handle-connection in out)]
|
|
|
|
[(list "close" pid)
|
|
(displayln (format "~a closed" pid))
|
|
(thread-send message-handler (cons 'kill pid))
|
|
(close-socket in out)]
|
|
|
|
[other
|
|
(displayln other)
|
|
(handle-connection in out)])]))
|
|
|
|
;; Socket handling
|
|
|
|
(define (accept-logs)
|
|
(let-values
|
|
([(in out) (unix-socket-accept control-socket)])
|
|
(thread
|
|
; hands the read capability over for this shell instance
|
|
(lambda ()
|
|
(file-stream-buffer-mode out 'none)
|
|
(handle-connection in out))))
|
|
(accept-logs))
|
|
|
|
; Start execution
|
|
; Use dynamic-wind to ensure socket is always cleaned up
|
|
(dynamic-wind
|
|
(const '())
|
|
(lambda ()
|
|
(with-handlers ([exn:break? rm-socket]
|
|
[exn:fail? rm-socket])
|
|
(accept-logs)))
|
|
rm-socket)
|
|
|