remove out of date cont-responder docs

chris.double 2006-02-23 02:15:32 +00:00
parent a452f95788
commit 9f5845d09e
2 changed files with 2 additions and 377 deletions

View File

@ -193,7 +193,7 @@ M: promised-label set-label-color set-promised-label-color ;
M: promised-label set-label-font set-promised-label-font ;
: fib ( n -- n )
yield dup 2 < [ drop 1 ] [ dup 1 - fib swap 2 - fib + ] if ;
1 sleep dup 2 < [ drop 1 ] [ dup 1 - fib swap 2 - fib + ] if ;
: test-promise-ui ( -- )
<promise> dup <promised-label> gadget. [ 30 fib unparse swap fulfill ] cons spawn drop ;
<promise> dup <promised-label> gadget. [ 15 fib unparse swap fulfill ] cons spawn drop ;

View File

@ -1,375 +0,0 @@
cont-responder v0.3
===================
NOTE: This documentation is slightly out of date with respect to the
current code but contains the basic idea.
In a continuation based web application the current position within
the web application is identified by a random URL. In this example the
URL is generated as a string of random digits:
: get-random-id ( -- id )
#! Generate a random id to use for continuation URL's
<% 16 [ random-digit % ] times %> ;
Each URL is associated with a quotation or continuation. When that URL
is accessed, that quotation is executed. The quotation will receive an
alist on the top of the stack which holds any POST or query
parameters. A global table is maintained that holds the association of
quotations to id's.
: continuation-table ( -- <namespace> )
#! Return the global table of continuations
"cont" get ;
: reset-continuation-table ( -- )
#! Create the initial global table
<namespace> "cont" set ;
: register-continuation ( quot -- id )
#! Store a continuation in the table and associate it with
#! a random id.
continuation-table [ get-random-id dup [ set ] dip ] bind ;
: get-registered-continuation ( id -- cont )
#! Return the continuation associated with the given id.
continuation-table [ get ] bind ;
: resume-continuation ( value id -- )
#! Call the continuation associated with the given id,
#! with 'value' on the top of the stack.
get-registered-continuation call ;
When a an URL is accessed, the continuation for the specific URL is
obtained and called. That continuation needs to exit back to the
caller when it has some HTML that it needs to display. returning that
HTML to the caller. To exit back to the caller it calls an 'exit
continuation' that is stored in an "exit" variable:
: exit-continuation ( -- exit )
#! Get the current exit continuation
"exit" get ;
: call-exit-continuation ( value -- )
#! Call the exit continuation, passing it the given value on the
#! top of the stack.
"exit" get call ;
: with-exit-continuation ( quot -- )
#! Call the quotation with the variable "exit" bound such that when
#! the exit continuation is called, computation will resume from the
#! end of this 'with-exit-continuation' call, with the value passed
#! to the exit continuation on the top of the stack.
[ "exit" set call call-exit-continuation ] callcc1 nip ;
All this calling of continuations is hidden behind a single 'show'
call. 'show' will take a quotation on the stack. That quotation should
return an HTML string. 'show' will call it to generate the HTML and
call the exit continuation with this string on the stack so it gets
returned to the httpd responder. The quotation receives a 'url' on the
top of the stack which is the 'id' of the continuation to resume when
that URL is accessed.
The HTML page that 'show' displays can contain links to
'callbacks'. These are links to other quotations that when called
will perform some action and return back to the calling page. To
return back to the calling page 'show' must capture and store the
current continuation before 'show' does anything so it can be later
return to by the callback. The following words store the current
continuation and retrieve it:
: store-callback-cc ( -- )
#! Store the current continuation in the variable 'callback-cc'
#! so it can be returned to later by callbacks. Note that it
#! recalls itself when the continuation is called to ensure that
#! it resets it's value back to the most recent show call.
[
[ "callback-cc" set call ] callcc0 drop store-callback-cc
] callcc0 ;
To generate the string of HTML I use 'with-string-stream' which calls
a quotation and all output inside that call gets appended to a string:
: with-string-stream ( quot -- string )
#! Call the quotation with standard output bound to a string output
#! stream. Return the string on exit.
<namespace> [
"stdio" <string-output-stream> put call "stdio" get stream>str
] bind ;
: show ( quot -- alist )
#! Call the quotation with the URL associated with the current
#! continuation. Return the HTML string generated by that code
#! to the exit continuation. When the URL is later referenced then
#! computation will resume from this 'show' call with a alist on
#! the stack containing any query or post parameters.
store-callback-cc
[
register-continuation swap with-string-stream
call-exit-continuation
] callcc1
nip ;
An httpd get responder is used that takes the ID as an argument, retrieves
the continuation associated with it and calls it. For the post
responder the post data is converted into an alist and it is put on
the top of the stack when calling the continuation.
: cont-get-responder ( id -- )
#! httpd responder that retrieves a continuation and calls it.
[ f swap resume-continuation ] with-exit-continuation
serving-html print drop ;
: post-request>alist ( post-request -- alist )
#! Return an alist containing name/value pairs from the
#! post data.
dup "&" swap str-contains [
"(.+)&(.+)" groups [ "(.+)=(.+)" groups uncons car cons ] inject
] [
"(.+)=(.+)" groups uncons car cons unit
] ifte ;
: cont-post-responder ( id -- )
#! httpd responder that retrieves a continuation for the given
#! id and calls it with the POST data as an alist on the top
#! of the stack.
[
read-post-request post-request>alist swap resume-continuation
] with-exit-continuation
serving-html print drop ;
Some code to install the responder:
: install-cont-responder ( -- )
#! Install the cont-responder in the table of httpd responders
"httpd-responders" get [
<responder> [
[ cont-get-responder ] "get" set
[ cont-post-responder ] "post" set
reset-continuation-table
] extend "cont" set
] bind ;
Now to test it. Here's a function that displays some text on an HTML page:
: display-page ( title -- )
#! Display a page with some text to test the cont-responder.
#! The page has a link to the 'next' continuation.
[
swap [
"<a href='" write write "'>Next</a>" write
] html-document
] show drop ;
Note that it contains an A HREF link to the URL that resumes the
computation (The quotation passed to show has this URL passed to it by
show).
An example of a POST request is a page that requests input of a
name. The following function calls show to display it and returns the
result of the 'name' field by retrieving it from the alist. Notice how
the 'action' of the post request is set to the URL passed in to the
quotation passed to show. So the 'next' that happens here is not an A
HREF but the action field of the POST.
: display-get-name-page ( -- name )
#! Display a page prompting for input of a name and return that name.
[
"Enter your name" [
"<form method='post' action='" write write "'>" write
"Name: <input type='text' name='name' size='20'>" write
"<input type='submit' value='Ok'>" write
"</form>" write
] html-document
] show
"name" swap assoc ;
A word that displays a sequence of these pages would be:
: test-cont-responder ( alist - )
#! Test the cont-responder responder by displaying a few pages in a row.
drop
"Page one" display-page
"Hello " display-get-name-page cat2 display-page
"Page three" display-page ;
This displays the first page, then a page prompting for the
name. "Hello " is concatenated to the result of the page and a third
page is displayed. A fourth page is available as well.
The following registers this word with the continuation system:
: register-test-cont-responder ( -- id )
#! Register the test-cont-responder word so that accessing the
#! URL with the returned ID will call it.
"httpd-responders" get [
"cont" get [
[ test-cont-responder ] register-continuation
] bind
] bind ;
This returns an ID which can be used from the web server to resume
it. Start the web server:
8888 httpd
Now access the URL with that id:
http://localhost:8888/cont/1234567890
(replace 1234567890 with the ID returned by register-continuation above)
You'll see the first page and a link. Click the link and you'll see
the second page requesting a name. Enter the name and press 'Ok'. A
third page will display a message using that name. You can book mark,
refresh, go back, enter a new name, etc as expected.
You can do any form of computation inside the handlers. Here's an
example of looping a set number of times:
: test-cont-responder2 ( alist - )
#! Test the cont-responder responder by displaying a few pages in a loop.
[ "one" "two" "three" "four" ] [ display-page ] each
"Done!" display-page ;
: register-test-cont-responder2 ( -- id )
#! Register the test-cont-responder2 word so that accessing the
#! URL with the returned ID will call it.
"httpd-responders" get [
"cont" get [
[ test-cont-responder2 ] register-continuation
] bind
] bind ;
There is currently a limited ability to do 'callbacks'. You can
register a quotation as an HTML A HREF anchor thar when accessed by
the browser will run the quotation and then return to the most recent
'show' call. This has the effect of allowing 'subroutine' calls as
page links that can do anything (including display other pages and
complicated action) and will return back to the originating page. The
word to generate this link is:
: quot-href ( text quot -- )
#! Write to standard output an HTML HREF where the href,
#! when referenced, will call the quotation and then return
#! back to the most recent 'show' call (via the callback-cc).
#! The text of the link will be the 'text' argument on the
#! stack.
"<a href='" write
"callback-cc" get [ call ] cons append register-continuation write
"'>" write
write
"</a>" write ;
An example of use is a simple menu page that displays links to the
words written previously:
: test-cont-responder3 ( alist - )
#! Test the quot-href word by displaying a menu of the current
#! test words. Note that we drop the 'url' argument to the show
#! quotation as we don't link to a 'next' page.
drop
[
drop
"Menu" [
"<ol>" write
"<li>" write
"Test responder1" [ test-cont-responder ] quot-href
"</li>" write
"<li>" write
"Test responder2" [ test-cont-responder2 ] quot-href
"</li>" write
"</ol>" write
] html-document
] show drop ;
: register-test-cont-responder3 ( -- id )
#! Register the test-cont-responder3 word so that accessing the
#! URL with the returned ID will call it.
"httpd-responders" get [
"cont" get [
[ test-cont-responder3 ] register-continuation
] bind
] bind ;
You should now be able to click on the menu items, navigate through
those pages and when the sequence of pages ends, return back to the
original menu page.
Note that this is just a proof of concept. In a real framework the
continuations need to be expired after time. It would also enable
generating links to other pages, etc rather than just a sequence of
pages. I plan to flesh this out over the next few days and present
some more useful examples. My main point was to see if it was possible
to do this type of thing in Factor.
The number of words required to get things going is amazingly small
and it was very easy to develop this far.
The code is contained in cont-responder.factor. Here are the steps to
run all the examples starting with a default Factor 0.60 install:
1) java -cp Factor.jar factor.FactorInterpreter
-db:factor.db.FileStore:factor.db
At the prompt enter:
---8<---
USE: httpd-responder
default-responders
exit
---8<---
2) java -cp Factor.jar factor.FactorInterpreter
-db:factor.db.FileStore:factor.db
-no-compile
At the prompt enter:
---8<---
USE: httpd
"cont-responder.factor" run-file
USE: cont-responder
init-cont-responder
register-test-cont-responder .
---8<---
Make note of the number returned by the last line call this [1].
---8<---
register-test-cont-responder2 .
---8<---
Make note of the number returned by the last line call this [2].
---8<---
register-test-cont-responder3 .
---8<---
Make note of the number returned by the last line call this [3].
---8<---
8888 httpd
---8<---
For the first example go to http://localhost:8888/cont/[1]
where you replace [1] with the number from [1] above. In my system
it was:
http://localhost:8888/cont/0406763029866672
For the second example go to http://localhost:8888/cont/[2]
where you replace [2] with the number from [2] above. In my system
it was:
http://localhost:8888/cont/6018237533813007
For the menu example go to http://localhost:8888/cont/[3]
where you replace [3] with the number from [3] above. In my system
it was:
http://localhost:8888/cont/3568874223456634
3) You can use the inspector to look at the continuation table:
http://localhost:8888/inspect/global'httpd-responders'cont'cont