[REBOL] Re: The REBOL async:// tutorial - take 1
From: petr:krenzelok:trz:cz at: 3-Mar-2004 17:58
Maarten Koopmans napsal(a):
Hi,
that stuff looks really excelent! Strange thing is, that even if the
code looks pretty straightforward, I don't understand every detail of
it, but that is what there are questions for :-)
> handler: func [port [port!] state [word! error!] /local tmp cmd] [
> if error? :state [print mold disarm state return true]
> switch state [
> connect [
> ; do HTTP request
> insert port {GET /fg/anen.jpg HTTP/1.0^M^JHost:
>www.3dwallpaper.com^M^J^M^J}
>
That one - raw tcp stream, right? I wonder if some kind of dialect (set
of functions) could be produced to handle that ugly MJMJMJ and GET
commands etc., as e.g. read/custom allows. Just a theoretical question,
if it even would be worth it, nothing more
> false
> ]
> read [false]
> write [false]
> close [
> ; get data
> data: copy port
>
OK, so that one does not block right? And it is so just because we are
inside handler function, which is being called once some event happens
on port, so theoretically some data should be awaiting us. I just wonder
it comes in 'close switch part. We get here once other side closed
connection? So if I understand it correctly, we read it in parts, but
'read part does nothing, rebol is internally buffering data (how large
data is rebol able to buffer easily that way?) and once other side
closes connection, we can read it by copy (which will not block, even if
no-wait was not used), and whole data is being read out of the port
buffer at once? Well, I hope I am still on track :-)
>Now for a simple server:
>
>First we add a listening server port to the system/ports/wait-list, like:
>
Why? Is that needed? Am I right thinking it is because of View? Once
View starts, it adds event-port into wait-list and if we want to process
all various events properly, we have to go via wait-list?
> either error? try [listen: open/no-wait tcp://:8000] [
> port: open async://localhost:8000
> port/awake: do handler
>
Above code somehow escapes my understanding :-) So if we are not able to
open listen port (because e.g. we are already listening), we open
connection on localhost to that port? What is that good for?
> ] [
> listen/awake: func [l /local p] [
> print "Got connection."
> p: first listen
> remove find system/ports/wait-list listen
> port: make port! [scheme: 'async sub-port: p]
>
that is something I never understood. That is why I was not able to
further more deeply adapt Sterling's proxy.r script. It contained way
too much port subport and proxy (as a port :-) stuff for my brain to
swallow :-) 'p is assigned first connected client. It does not contain
any sub-port, yet it can communicate. IIRC someone said, that sub-port
contains real communication port. But I don't understand the difference,
even without sub-port, I am able to send data here and there and I can
see it buffered in port/state. What is sub-port then?
> open port
> port/awake: do handler
> false
> ]
> insert tail system/ports/wait-list listen
> port: none
> ]
>
so overall - it is clever - once first event happens on listening port,
we remove it from wait-list, reassign handler and insert it back into
wait-list. That sounds like nice constructor/init method in OOP :-)
>As you can see, its awake function convert the accepted port to an async
>one and sets the handler. So what is the handler then?
>
> handler: [ use [ buffer ][
>
> buffer: copy []
>
> func [port [port!] state [word! error!] /local tmp cmd] [
> if error? :state [print mold disarm state return true]
> switch state [
> connect [print "Connected." false]
> read [
> append buffer copy port
> while [tmp: find buffer newline] [
> cmd: copy/part buffer tmp
> remove/part buffer next tmp
> do-cmd cmd
> ]
> false
> ]
> write [false]
> close [print "Peer closed connection." close port true]
> ]
> ]
> ]
> ]
>
>The first thing to notice is the fact that we use 'use to create a context
>that returns a function! value. This function (and only this particluar
>value) has access to its buffer. By doing the handler block in the server
>part above, every accepted port gets a copy of theis function value with
>its own "static" buffer space. A very simple but effective trick.
>
cool!
Thanks for your tutorial, very educative!
-pekr-