actors: Add new method of running REPL via REPL actor.
authorChristopher Allan Webber <cwebber@dustycloud.org>
Tue, 27 Dec 2016 02:13:23 +0000 (20:13 -0600)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Tue, 27 Dec 2016 02:20:47 +0000 (20:20 -0600)
Also adds new procedure to see if an actor is alive, and make use of it
in the new REPL actor.

* 8sync/actors.scm (actor-am-i-alive?): New procedure.
(ez-run-hive): Remove #:repl-server keyword.
* 8sync/repl.scm (<make-coop-server-handler, spawn-and-queue-repl-server!):
Remove.
(<repl-manager>, repl-manager-cleanup, repl-manager-init): New variables.
* demos/ircbot.scm (parse-args): Add --repl command line option.
(run-bot): Add and queue <repl-manager> actor if appropriate.

8sync/actors.scm
8sync/repl.scm
demos/ircbot.scm
doc/8sync-new-manual.org

index 886e11405fb8586e3edd92fa6329ae79011083b0..1927465a804007d1d64fbead3e84d6bf8141a7e1 100644 (file)
@@ -25,7 +25,6 @@
   #:use-module (ice-9 match)
   #:use-module (ice-9 pretty-print)
   #:use-module (8sync agenda)
-  #:use-module (8sync repl)
   #:export (;; utilities... ought to go in their own module
             big-random-number
             big-random-number-string
@@ -48,6 +47,8 @@
             actor-id-hive
             actor-id-string
 
+            actor-am-i-alive?
+
             build-actions
 
             define-simple-actor
@@ -347,6 +348,9 @@ raise an exception if an error."
 (define %current-actor
   (make-parameter #f))
 
+(define (actor-am-i-alive? actor)
+  (hive-resolve-local-actor (actor-hive actor) (actor-id actor)))
+
 
 \f
 ;;; Actor utilities
@@ -694,21 +698,11 @@ Like create-actor, but permits supplying an id-cookie."
 ;;; 8sync bootstrap utilities
 ;;; =========================
 
-(define* (ez-run-hive hive initial-tasks #:key repl-server)
-  "Start up an agenda and run HIVE in it with INITIAL-TASKS.
-
-Should we start up a cooperative REPL for live hacking?  REPL-SERVER
-wants to know!  You can pass it #t or #f, or if you want to specify a port,
-an integer."
+(define* (ez-run-hive hive initial-tasks)
+  "Start up an agenda and run HIVE in it with INITIAL-TASKS."
   (let* ((queue (list->q initial-tasks))
          (agenda (make-agenda #:pre-unwind-handler print-error-and-continue
                               #:queue queue)))
-    (cond
-     ;; If repl-server is an integer, we'll use that as the port
-     ((integer? repl-server)
-      (spawn-and-queue-repl-server! agenda repl-server))
-     (repl-server
-      (spawn-and-queue-repl-server! agenda)))
     (start-agenda agenda)))
 
 (define (bootstrap-message hive to-id action . message-body-args)
index bc68138eb3b5c353d9fe0e9d8e50dc130c27d93a..16e246699fe1af49573ddb221ba7bbce839cdda3 100644 (file)
 ;;; License along with 8sync.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (8sync repl)
-  #:use-module (ice-9 q)
-  #:use-module (8sync agenda)
+  #:use-module (oop goops)
+  #:use-module (8sync)
+  #:use-module (system repl server)
   #:use-module (system repl coop-server)
-  #:export (make-coop-server-handler
-            spawn-and-queue-repl-server!))
+  #:export (<repl-manager>))
 
-(define (make-coop-server-handler coop-server)
-  (define (run-self)
-    (poll-coop-repl-server coop-server)
-    ;; queue ourselves again
-    (run-delay (run-self) (/ 1 30)))
-  run-self)
+(define-class <repl-manager> (<actor>)
+  (path #:init-keyword #:path
+        #:init-value "/tmp/8sync-socket"
+        #:getter repl-manager-path)
+  (socket #:init-value #f
+          #:accessor repl-manager-socket)
+  (poll-every #:init-keyword #:poll-every
+              #:init-value (/ 1 30)
+              #:getter repl-manager-poll-every)
+  (actions #:allocation #:each-subclass
+           ;; @@: Should we add a stop action?
+           #:init-value (build-actions
+                         (*cleanup* repl-manager-cleanup)
+                         (init repl-manager-init))))
+
+(define (repl-manager-cleanup repl-manager message)
+  ;; Close the socket, if open
+  (and=> (repl-manager-socket repl-manager)
+         close)
+  ;; Delete the file, if it exists
+  (when (file-exists? (repl-manager-path repl-manager))
+    (delete-file (repl-manager-path repl-manager))))
+
+(define (repl-manager-init repl-manager message)
+  (define socket
+    (make-unix-domain-server-socket #:path (repl-manager-path repl-manager)))
+  (define server
+    (spawn-coop-repl-server socket))
+  (set! (repl-manager-socket repl-manager) socket)
+  (while (actor-am-i-alive? repl-manager)
+    (poll-coop-repl-server server)
+    (8sleep (repl-manager-poll-every repl-manager))))
 
-(define* (spawn-and-queue-repl-server! agenda #:optional port)
-  (let ((coop-server
-         (if port
-             (spawn-coop-repl-server port)
-             (spawn-coop-repl-server))))
-    (enq! (agenda-queue agenda)
-          (make-coop-server-handler coop-server))))
index b97b572bf738143d37c739c138f5d5f9286b6749..eaae113f80bf07d34b391652eec024d9ca728fc7 100755 (executable)
@@ -22,6 +22,7 @@
 
 (use-modules (8sync)
              (8sync systems irc)
+             (8sync repl)
              (oop goops)
              (srfi srfi-37)
              (ice-9 format)
                    (option '("channels") #t #f
                            (lambda (opt name arg result)
                              `(#:channels ,(string-split arg #\,)
-                               ,@result))))
+                               ,@result)))
+                   (option '("repl") #f #t
+                           (lambda (opt name arg result)
+                             `(#:repl ,(or arg #t) ,@result))))
              (lambda (opt name arg result)
                (format #t "Unrecognized option `~a'\n" name)
                (exit 1))
                         #:username username
                         #:server server
                         #:channels channels))
+  (define repl-manager
+    (cond
+     ((string? repl)
+      (hive-create-actor* hive <repl-manager> "repl"
+                          #:path repl))
+     (repl
+      (hive-create-actor* hive <repl-manager> "repl"))))
+
+  (define initial-messages
+    (if repl
+        (list (bootstrap-message hive irc-bot 'init)
+              (bootstrap-message hive repl-manager 'init))
+        (list (bootstrap-message hive irc-bot 'init))))
+
   ;; TODO: load REPL
-  (ez-run-hive hive (list (bootstrap-message hive irc-bot 'init))))
+  (ez-run-hive hive initial-messages))
 
 (define (main args)
   (define parsed-args (parse-args "ircbot.scm" args))
index e2bb333c22e8153493c597f72b243f16221d3ad1..51c670ed4764cf5262cfb6bf337463f51bbde37c 100644 (file)
@@ -405,6 +405,39 @@ What cool commands can you add?
 
 ** An intermission: about live hacking
 
+This section is optional, but highly recommended.
+It requires that you're a user of GNU Emacs.
+If you aren't, don't worry... you can forge ahead and come back in case
+you ever do become an Emacs user.
+(If you're more familiar with Vi/Vim style editing, I hear good things
+about Spacemacs...)
+
+So you may have noticed while updating the last section that the
+start/stop cycle of hacking isn't really ideal.
+You might either edit a file in your editor, then run it, or
+type the whole program into the REPL, but then you'll have to spend
+extra time copying it to a file.
+Wouldn't it be nice if it were possible to both write code in a
+file and try it as you go?
+And wouldn't it be even better if you could live edit a program
+while it's running?
+
+Luckily, there's a great Emacs mode called Geiser which makes
+editing and hacking and experimenting all happen in harmony.
+And even better, 8sync is optimized for this experience.
+8sync provides easy drop-in "cooperative REPL" support, and
+most code can be simply redefined on the fly in 8sync through Geiser
+and actors will immediately update their behavior, so you can test
+and tweak things as you go.
+
+
+
+
+
+# Finally, show off pk
+
+
+
 ** Battle bot!
 
 ** Adding a "rankings" web page