X-Git-Url: https://jxself.org/git/?p=8sync.git;a=blobdiff_plain;f=doc%2F8sync-new-manual.org;h=844653fa0b6a3da7eedd30ad376775d65fcc5759;hp=6658c93928d9d820b37e4eb959779b1544666077;hb=61dba76070f6b468dd918e6f8d8791231cf2ba6f;hpb=9833ecabb267e740134f5bd49663d4c0a872796d diff --git a/doc/8sync-new-manual.org b/doc/8sync-new-manual.org index 6658c93..844653f 100644 --- a/doc/8sync-new-manual.org +++ b/doc/8sync-new-manual.org @@ -103,8 +103,8 @@ Now we need to add our bot. Initially, it won't do much. #+BEGIN_SRC scheme (define-class ()) - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) (if emote? (format #t "~a emoted ~s in channel ~a\n" speaker line channel) @@ -117,6 +117,11 @@ This is an 8sync actor. (8sync uses GOOPS to define actors.) We extended the handle-line generic method, so this is the code that will be called whenever the IRC bot "hears" anything. +This method is itself an action handler, hence the second argument +for =message=, which we can ignore for now. +Pleasantly, the message's argument body is passed in as the rest of +the arguments. + For now the code is pretty basic: it just outputs whatever it "hears" from a user in a channel to the current output port. Pretty boring! @@ -174,8 +179,8 @@ Let's get it to echo whatever we say back to us. Change handle-line to this: #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) (<- (actor-id irc-bot) 'send-line channel (format #f "Bawwwwk! ~a says: ~a" speaker line))) #+END_SRC @@ -241,8 +246,8 @@ Indeed, we do have such a method, so we /could/ rewrite handle-line like so: #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) (irc-bot-send-line irc-bot channel (format #f "Bawwwwk! ~a says: ~a" speaker line))) #+END_SRC @@ -269,8 +274,8 @@ Whee, that looks like fun! To implement it, we're going to pull out Guile's pattern matcher. #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) (define my-name (irc-bot-username irc-bot)) (define (looks-like-me? str) (or (equal? str my-name) @@ -306,8 +311,8 @@ If you're getting the sense that we could make this a bit less wordy, you're right: #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) (define my-name (irc-bot-username irc-bot)) (define (looks-like-me? str) (or (equal? str my-name) @@ -404,7 +409,7 @@ and will always yield to the scheduler. Our while loop also checks "actor-alive?" to see whether or not it is still registered. In general, if you keep a loop in your actor that regularly yields -to the scheduler, you should check this. +to the scheduler, you should check this.[fn:actor-alive-deprecated-soon] (An alternate way to handle it would be to not use a while loop at all but simply send a message to ourselves with "<-" to call the sleeper-loop handler again. @@ -526,7 +531,6 @@ which does not block the rest of the program from running. Let's try applying that to our own code by turning our manager into a micromanager. -#+END_SRC #+BEGIN_SRC scheme ;;; Update this method (define (manager-assign-task manager message difficulty) @@ -596,6 +600,20 @@ Of course, we need to update our worker accordingly as well. everywhere as we are in this program... that's just to make the examples more illustrative.) +"<-reply" is what actually returns the information to the actor +waiting on the reply. +It takes as an argument the actor sending the message, the message +it is in reply to, and the rest of the arguments are the "body" of +the message. +(If an actor handles a message that is being "waited on" but does not +explicitly reply to it, an auto-reply with an empty body will be +triggered so that the waiting actor is not left waiting around.) + +The last thing to note is the call to "self-destruct". +This does what you might expect: it removes the actor from the hive. +No new messages will be sent to it. +Ka-poof! + Running it is the same as before: #+BEGIN_SRC scheme @@ -628,19 +646,11 @@ manager> Oh! I guess you can go home then. worker> Whew! Free at last. #+END_SRC -"<-reply" is what actually returns the information to the actor -waiting on the reply. -It takes as an argument the actor sending the message, the message -it is in reply to, and the rest of the arguments are the "body" of -the message. -(If an actor handles a message that is being "waited on" but does not -explicitly reply to it, an auto-reply with an empty body will be -triggered so that the waiting actor is not left waiting around.) - -The last thing to note is the call to "self-destruct". -This does what you might expect: it removes the actor from the hive. -No new messages will be sent to it. -Ka-poof! +[fn:actor-alive-deprecated-soon] + Or rather, for now you should call =actor-alive?= if your code + is looping like this. + In the future, after an actor dies, its coroutines will + automatically be "canceled". ** Writing our own network-enabled actor @@ -656,7 +666,8 @@ Well, luckily that's pretty easy, especially with all you know so far. (define-actor () ((*init* telcmd-init) (*cleanup* telcmd-cleanup) - (new-client telcmd-new-client)) + (new-client telcmd-new-client) + (handle-line telcmd-handle-line)) (socket #:accessor telcmd-socket #:init-value #f)) #+END_SRC @@ -736,12 +747,12 @@ In our case, we politely close the socket when == dies. (cond ((eof-object? line) (close client)) (else - (telcmd-handle-line telcmd client - (string-trim-right line #\return)) + (<- (actor-id telcmd) 'handle-line + client (string-trim-right line #\return)) (when (actor-alive? telcmd) (loop))))))) - (define (telcmd-handle-line telcmd client line) + (define (telcmd-handle-line telcmd message client line) (match (string-split line #\space) (("") #f) ; ignore empty lines (("time" _ ...) @@ -766,7 +777,7 @@ agenda.[fn:setvbuf] The actual method called whenever we have a "line" of input is pretty straightforward... in fact it looks an awful lot like the IRC bot handle-line procedure we used earlier. -No surprises there! +No surprises there![fn:why-send-a-message-to-handle-line] Now let's run it: @@ -820,6 +831,20 @@ Happy hacking! finishes handling one message. Our loop couldn't look quite like this though! +[fn:why-send-a-message-to-handle-line] + Well, there may be one surprise to the astute observer. + Why are we sending a message to ourselves? + Couldn't we have just dropped the argument of "message" to + telcmd-handle-line and just called it like any other procedure? + Indeed, we /could/ do that, but sending a message to ourself has + an added advantage: if we accidentally "break" the + telcmd-handle-line procedure in some way (say we add a fun new + command we're playing with it), raising an exception won't break + and disconnect the client's main loop, it'll just break the + message handler for that one line, and our telcmd will happily + chug along accepting another command from the user while we try + to figure out what happened to the last one. + ** An intermission: about live hacking This section is optional, but highly recommended. @@ -930,8 +955,8 @@ Edit the respond section to see what channel it's really sending things to: #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) ;; [... snip ...] (define (respond respond-line) (<- (actor-id irc-bot) 'send-line (pk 'channel channel) @@ -960,8 +985,8 @@ to looks like our own username that we respond back to the sender. (We can remove the pk now that we know what's going on.) #+BEGIN_SRC scheme - (define-method (handle-line (irc-bot ) speaker channel - line emote?) + (define-method (handle-line (irc-bot ) message + speaker channel line emote?) ;; [... snip ...] (define (respond respond-line) (<- (actor-id irc-bot) 'send-line