First, realize that we didn't knock this off in two afternoons. So it is 
OK to hit your head against the wall.

>> 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
>
>  
>
You could use the builtin crlf as a replacement.

>>             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 :-)
>  
>
That copy doesn't block, because it gets diverted to the copy in the 
async:// handler IIRC. Also, async:// does all low-level input and 
output buffering.
And async opening + async dns://

>>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?
>
>  
>
It can be done many ways indeed. Pick your own example.

>> 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?
>
>  
>
Gabriele? I missed it, it looks like setting up a tunnel to me.

>> ] [
>>     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?
>
>  
>
The real connecttion :-)  Anyway... this is the way to go. If you take a 
look at the renewed xml-rpc you will find an add-server function that 
abstract this away nicely.

>>        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 :-)
>
>  
>
Go clean your mouth!

>>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!
>  
>
I know! That's why I thought I'd share it with you all.

>Thanks for your tutorial, very educative!
>
>  
>
Put it to work.  async:// is so clever. Carl explained it Eastern 2003 
in a private chat, then I started experimenting and Gabriele turned that 
into async://
It took some more experimenting, and finally we have a tutorial.

--Maarten
-- 
To unsubscribe from this list, just send an email to
[EMAIL PROTECTED] with unsubscribe as the subject.

Reply via email to