Permalink
Browse files

added example docs on how to stream data

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@770 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
klacke committed Sep 13, 2004
1 parent 884bd48 commit a39fab8b88d6c3cf3fd53a2be1c8d5a58bbd1f03
Showing with 120 additions and 4 deletions.
  1. +6 −0 man/yaws_api.5
  2. +13 −4 www/EXHEAD
  3. +63 −0 www/stream.yaws
  4. +38 −0 www/urandom.yaws
View
@@ -180,7 +180,13 @@ When a yaws function needs to deliver chunks of data which it gets
from a process. The other process can call this function to deliver
these chunks. It requires the \fBout/1\fR function to return the
value \fB{streamcontent, MimeType, FirstChunk}\fR to work.
+YawsPid is the process identifier of the yaws process delivering the original
+.yaws file. That is self() in the yaws code. The Pid must typically be passed (somehow) to the producer of the stream.
+.TP
+\fBstream_chunk_deliver_blocking(YawsPid, Data)\fR
+A syncronous verion of the above function. This syncronous version must always
+be used when the producer of the stream is faster than the consumer. This is usually the case since the client is the WWW browser.
.TP
\fBstream_chunk_end(YawsPid)\fR
View
@@ -9,22 +9,31 @@
<td> <A HREF="/query.yaws">Query part of url</a> </td>
<td> <A HREF="/form.yaws">Forms</a> </td>
<td> <A HREF="/redirect.yaws">Redirect</a> </td>
- <td> <A HREF="/ssi.yaws">Server side include</a> </td>
- <td> <A HREF="/bindings.yaws">Bindings</a> </td>
+ <td> <A HREF="/arg.yaws">Arg</a> </td>
</tr>
<tr border="2">
- <td> <A HREF="/arg.yaws">Arg</a> </td>
+ <td> <A HREF="/ssi.yaws">Server side include</a> </td>
+ <td> <A HREF="/bindings.yaws">Bindings</a> </td>
+
<td> <A HREF="/upload0.yaws">File upload</a> </td>
<td> <A HREF="/cookies.yaws">Cookies</a> </td>
<td> <A HREF="/pcookie.yaws">Persistent Cookies</a> </td>
<td> <A HREF="/session.yaws">Cookie sessions</a> </td>
<td> <A HREF="/appmods.yaws">Appmods</a> </td>
+
+
+
+</tr>
+
+<tr border="2">
+ <td> <A HREF="/stream.yaws">Streaming data</a> </td>
<td> <A HREF="/shopingcart/index.yaws">Tiny shopping cart</a> </td>
<td> <A HREF="/embed.yaws">Embedding Yaws</a> </td>
-
</tr>
+
+
</table>
<hr>
View
@@ -0,0 +1,63 @@
+
+<erl>
+
+
+box(Str) ->
+ {'div',[{class,"box"}],
+ {pre,[],Str}}.
+
+tbox(T) ->
+ box(lists:flatten(io_lib:format("~p",[T]))).
+
+
+ssi(File) ->
+ {'div',[{class,"box"}],
+ {pre,[],
+ {ssi, File,[],[]}}}.
+
+
+out(A) ->
+ [{ssi, "HEAD", [],[]},
+ {ssi, "EXHEAD", [],[]},
+ {ehtml,
+ [{h1, [], "Streaming data to the client"},
+
+ {p, [],
+ "Sometimes we want to stream data to the client. Maybe we don't know or cannot compute the size of the data. Regardless of what, we do not want to keep all data in memory until it's shipped to the client. We want to use chunked encodings, and simply send data in chunks to the client. This is performed in steps.First the out/1 return value:"},
+
+ box(" {streamcontent, MimeType, FirstChunk}"),
+
+ {p,[], ["Is returned from the out/1 function"
+ "This make the erlang process processing that particular page go int a receive loop, waiting for more data. Somehow, another process in the erlang system, must then deliver data to the waiting/receiving erlang processs. There are two asyncronous API functions that can be used to deliver that data."]},
+
+ box("yaws_api:stream_chunk_deliver(YawsPid, Data)"),
+
+ box("yaws_api:stream_chunk_end(YawsPid)"),
+
+ {p, [], "The YawsPid argumen is the process identifier of the original yaws process processing the page, i.e. self(), in the .yaws file."},
+
+ {p, [],"Maybe this gets clear with a programing example, let's use a process reading a random number of bytes from /dev/urandom as the source of the data"},
+
+ ssi("urandom.yaws"),
+
+ {p, [],
+ ["The above slightly bizzare code can be executed ",
+ {a, [{href, "urandom.yaws"}], "Here"},
+ " The code creates a process which reads a random amount of bytes from /dev/urandom and sends them to the client, piece by piece. "]},
+
+ {p,[], "There is also a version of the API code which delivers the data in a blocking fashion. Whenever the producer of the stream is faster than the consumer, that is the WWW client, we must use a syncronous version of the code. The api function is called:"},
+
+ box("yaws_api:stream_chunk_deliver_blocking(YawsPid, Data)")
+
+
+ ]}].
+
+
+</erl>
+
+
+</html>
+
+
+
+
View
@@ -0,0 +1,38 @@
+
+<erl>
+
+out(A) ->
+ Self = self(),
+ spawn(fun() ->
+ %% Create a random number
+ {_A1, A2, A3} = now(),
+ random:seed(erlang:phash(node(), 100000),
+ erlang:phash(A2, A3),
+ A3),
+ Sz = random:uniform(100000),
+
+ %% Read random junk
+ S="dd if=/dev/urandom count=1 bs=" ++
+ integer_to_list(Sz) ++ " 2>/dev/null",
+ P = open_port({spawn, S}, [binary,stream, eof]),
+
+ rec_loop(Self, P)
+ end),
+
+ {streamcontent, "application/octet-stream", <<>>}.
+
+
+rec_loop(YawsPid, P) ->
+ receive
+ {P, {data, BinData}} ->
+ yaws_api:stream_chunk_deliver(YawsPid, BinData),
+ rec_loop(YawsPid, P);
+ {P, eof} ->
+ port_close(P),
+ yaws_api:stream_chunk_end(YawsPid),
+ exit(normal)
+ end.
+
+
+</erl>
+

0 comments on commit a39fab8

Please sign in to comment.