Dynamicly generated websites in Erlang

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Scott Lystig Fritchie-2
Hi,

What options are there for dynamically generating websites in erlang?
I'm using INETS webserver right now, but it only serves static pages
afaik.  I'd like to be able to generate different pages based on

1) a template file and
2) information pulled out of databases (either postgresql or I might
look into mnesia, not sure if it's appropriate in this case).

I may not need the template feature, but that's what I've used in the
past (with IMHO and Common Lisp).

I've been told that I could use some of the code in bluetail's ticket
tracker, but from a quick look at it I think I'd much rather use other
(easier hopefully) options, if there are any.

Thanks for reading, and any responses.

Sincerely,
jsj


--
the sky is tired of being blue



Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Mickael Remond-2
J Scott Jaderholm (scott) wrote:
> Hi,
>
> What options are there for dynamically generating websites in erlang?
> I'm using INETS webserver right now, but it only serves static pages
> afaik.  I'd like to be able to generate different pages based on

In fact, INETS can also generate dynamic content. You can execute Erlang
code in INETS.

What you should look for is: mod_esi (Erlang Scripting Interface):
  http://www.erlang.org/doc/r7b/lib/inets-2.5.3/doc/html/mod_esi.html
 
I wrote a french article on this topic and I could translate it if you
are interested.
This is a very nice feature to create a web interface to setup the
parameter when developping an Erlang server.
 
 
> I've been told that I could use some of the code in bluetail's
> ticket
> tracker, but from a quick look at it I think I'd much rather use
> other
> (easier hopefully) options, if there are any.
 
If I remember correctly, BTT use INETS to serve its dynamic content,
and Mnesia as its database.
 
The other alternative is mod_erl (which is preliminary implementation
of an Erlang module for the Apache web server). You can get it at:
  http://www.rfc1149.net/devel/mod_erl.html.en
   
--
Micka?l R?mond
http://www.erlang-fr.org/


Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

J Scott Jaderholm
Mickael Remond <mickael.remond> writes:

> J Scott Jaderholm (scott) wrote:
> > Hi,
> >
> > What options are there for dynamically generating websites in erlang?
> > I'm using INETS webserver right now, but it only serves static pages
> > afaik.  I'd like to be able to generate different pages based on
>
> In fact, INETS can also generate dynamic content. You can execute Erlang
> code in INETS.
>
> What you should look for is: mod_esi (Erlang Scripting Interface):
>   http://www.erlang.org/doc/r7b/lib/inets-2.5.3/doc/html/mod_esi.html
>  
> I wrote a french article on this topic and I could translate it if you
> are interested.

I'd definitely like that.  I read the Reference Manual but I'm not
quite grasping it from that.

I copied httpd_example.erl into my server_root, but the docs say to
copy the whole examples directory into /var/tmp.  I'm not sure why I
need to do this, but I did it anyway, and I get this when I run

5> start("/home/lispbliss/erl/inets/server_root/httpd_example.erl").
** exited: {undef,[{shell_default,start,
                                  ["/home/lispbliss/erl/inets/server_root/httpd_example.erl"]},
                   {shell,local_func,4},
                   {erl_eval,exprs,4},
                   {shell,eval_loop,2}]} **
6>


I've searched usenet and the archive of this list and have found
*very* little on mod_esi, are there any other documents explaining
mod_esi?

Sincerely,
jsj



Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

tobbe
In reply to this post by Scott Lystig Fritchie-2

> I've been told that I could use some of the code in bluetail's ticket
> tracker, but from a quick look at it I think I'd much rather use other
> (easier hopefully) options, if there are any.

Don't let the amount of code scare you. It is rather easy
to get going with INETS. Just copy the example server root
directory from the standard Erlang/OTP application, e.g:

  cp -R /usr/local/usr_lib/erlang/lib/inets-2.5.3/examples/server_root xxx

Modify the xxx/conf/httpd.conf file.
Especially the directive where you state your Erlang module to be called:

 ErlScriptAlias /my my

Create a file: xxx/inets.config which points out the conf file above:

cat > xxx/inets.config
[{inets,
  [{services,
    [{httpd,"/....../xxx/conf/httpd.conf"}]}]}].
^D

Start Erlang with the switches: -config /...../xxx/inets -s my

In your startup code in my.erl, call:  application:start(inets)

Now when you point a Web browser towards:

 <a href="http://something:aport/my/my/test">http://something:aport/my/my/test

The function: my:test/2 should be called by INETS,
and whatever it returns is sent back to the web browser.
Example (my.erl):

 test(Env,Input) ->
    InData = httpd:parse_query(Input),
    io:format("GOT THIS: ~p~n",[InData]),
    %% Returning this
    ["<HTML>",        
     "<HEAD>",
     "<TITLE> A Test Page </TITLE>",
     "</HEAD>",
     "<BODY>",
     "<H1> A TEST </H1>",
     "</BODY>",
     "</HTML>"].

For creating HTML content, the faqoff/html_lib.erl
module in the BTT package can be useful.

Good luck ! /Tobbe

       

 





--
--
Torbj?rn T?rnkvist , tel: +46 8 545 55 023 , fax: +46 8 654 70 71
Alteon Web Systems , St.Eriksgatan 44 , SE-112 34 Stockholm , Sweden            
Email: ttornkvist , Web: http://www.alteon.com


Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Mickael Remond-2
In reply to this post by J Scott Jaderholm
J Scott Jaderholm (jsj) wrote:
> Mickael Remond <mickael.remond> writes:
> > I wrote a french article on this topic and I could translate it if you
> > are interested.
>
> I'd definitely like that.  I read the Reference Manual but I'm not
> quite grasping it from that.

Ok. I will work on it.

--
Micka?l R?mond
 http://www.erlang-fr.org/



Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Ulf Wiger-4
In reply to this post by Scott Lystig Fritchie-2
On 26 Mar 2001, J Scott Jaderholm wrote:

>Hi,
>
>What options are there for dynamically generating websites in
>erlang? I'm using INETS webserver right now, but it only serves
>static pages afaik.  I'd like to be able to generate different pages
>based on
>
>1) a template file and
>
>2) information pulled out of databases (either postgresql or I might
>look into mnesia, not sure if it's appropriate in this case).


Personally, I use mnesia in a web server application that I maintain.
It works very well for my purposes. If you need to use a different
database, you may want to look at the ODBC client, or simply write
your own glue code to access the database.

If you can read a PowerPoint presentation, you may want to look at

http://www.erlang.se/euc/00/xmerl.ppt

There is an example of how to put together fairly generic Erlang
terms and then convert them to HTML (or e.g. XML) on the way out.
(the actual example starts on slide 13.)

xmerl-0.15 has conversion functions for most HTML tags, and you
can easily put your own conversion layer on top. I've tested it
in a prototype where I inserted nice splash headers and images etc
without having to change a line of code in the program logic (just in
the conversion layer to HTML.)

This would give you something a bit similar to templates, I think.

No good documentation though. Sorry about that.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

J Scott Jaderholm
In reply to this post by tobbe

Hi Torbjorn,

Torbjorn Tornkvist <tobbe> writes:

> Especially the directive where you state your Erlang module to be called:
>
>  ErlScriptAlias /my my

I create a directory my in my server_root and put my.erl in there.


> Start Erlang with the switches: -config /...../xxx/inets -s my

I do and get this error
{'init terminating in do_boot',{undef,[{my,start,[]},{init,start_it,1},{init,start_em,1}]}}
init terminating in do_boot ()


Btw, is it normal to get like 4-5 PROGRESS REPORTs when startin inets?

> In your startup code in my.erl, call:  application:start(inets)

I'm not sure waht you mean by startup code.

> Now when you point a Web browser towards:
>
>  <a href="http://something:aport/my/my/test">http://something:aport/my/my/test

On mod_esi.html#ErlScriptAlias it says to use my:test syntax.  Is this
just outdated?

> For creating HTML content, the faqoff/html_lib.erl
> module in the BTT package can be useful.

Ahh, thank you, I've looked at that and I'll study it more indepth
once I get eli working.

Thanks for your valuable response.

Sincerely,
jsj



Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

tobbe

> > Start Erlang with the switches: -config /...../xxx/inets -s my
>
> I do and get this error
> {'init terminating in do_boot',{undef,[{my,start,[]},{init,start_it,1},{init,start_em,1}]}}
> init terminating in do_boot ()

Try and add the path to your erlang module:

erl -config /...../xxx/inets -pa /where/my-code/is -s my

> Btw, is it normal to get like 4-5 PROGRESS REPORTs when startin
> inets?

Yes, especially if you are using the: -boot start_sasl
switch.

> > In your startup code in my.erl, call:  application:start(inets)
>
> I'm not sure waht you mean by startup code.

In my.erl you probably have something like:

start() ->
        spawn(?MODULE, init, []).

init() ->
        application:start(inets),
        %% more init stuff here... ?
        loop().

loop() ->
        %% A receive-loop here....
        receive
          Msg ->
            io:format("loop got: ~p~n",[Msg]),
            loop()
        end.


Cheers /Tobbe




Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Ulf Wiger-4
In reply to this post by J Scott Jaderholm
On 27 Mar 2001, J Scott Jaderholm wrote:

>
>Hi Torbjorn,
>
>Torbjorn Tornkvist <tobbe> writes:
>
>> Start Erlang with the switches: -config /...../xxx/inets -s my
>
>I do and get this error

>{'init terminating in
>do_boot',{undef,[{my,start,[]},{init,start_it,1},{init,start_em,1}]}}
>init terminating in do_boot ()

You need to write a function my:start(). The '-s my' flag is basically
short for '-s my start', that is, "start a process by calling
my:start()". More on that below.


>Btw, is it normal to get like 4-5 PROGRESS REPORTs when startin
>inets?

Yes. When you start your Erlang node with SASL activated (e.g. 'erl
-boot start_sasl'), you will get a progress report for every process
started using proc_lib.erl. This includes all processes based on OTP
behaviours (gen_server, gen_fsm, supervisor, ...)

If they really bug you, you can turn them off with the flag
'-sasl errlog_type error'. This will only give you the error and crash
reports.


>> In your startup code in my.erl, call:  application:start(inets)
>
>I'm not sure waht you mean by startup code.

my:start() needs to start a process (see 'erl -man init'


    "The functions are executed sequentially  in  the  ini-
    tialization  process,  which  then terminates normally
    and passes control to the user. This means that  a  -s
    call  which does not terminate will block further pro-
    cessing; to avoid this, use some variant of  spawn  in
    such cases."

Of course, this man page also recommends that the -run flag be used
instead of the -s flag. In this case, it doesn't matter.

I noticed that Tobbe gave you an example of run.erl, so I'll stop
here.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB




Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Chris Pressey
In reply to this post by Scott Lystig Fritchie-2
J Scott Jaderholm wrote:
> What options are there for dynamically generating websites in erlang?
> I'm using INETS webserver right now, but it only serves static pages
> afaik.  I'd like to be able to generate different pages based on
> 1) a template file [...]
> I may not need the template feature, but that's what I've used in the
> past (with IMHO and Common Lisp).

Assuming you can coerce INETS into doing what you want, you might want
to check out Joe Armstrong's EHTML contribution as a solution for your
template feature.  It allows you to define new HTML tags, and to embed
Erlang directly in the template.

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Dynamicly generated websites in Erlang

Kent Boortz-2

Chris Pressey <cpressey> writes:
> Assuming you can coerce INETS into doing what you want, you might want
> to check out Joe Armstrong's EHTML contribution as a solution for your
> template feature.  It allows you to define new HTML tags, and to embed
> Erlang directly in the template.

Ehtml is what is used for most parts of www.erlang.org but we don't use
it dynamically. We use it together with Unix make and Erlang ermake
to generate the pages before we rsync them over from our internal net
to www.erlang.org.

The erlang code to embed is funs (maybe I haven't read the manual
closely enough but I don't think you can use named functions). It is
an interesting challenge to express what you want to do using no named
functions. I include the current included file with new tag
definitions used at www.erlang.org as an example. Maybe a bit ugly but
it works and is reasonable easy to change or extend. I like the idea
generating pages only when changed, not for every server request,

kent


<def name="header">
fun(Args, Str) ->
% Find the relative path to the top directory of the HTML tree
  RelPath =
    case lists:keysearch("path_to_top", 1, Args) of
      {value,{_,""}} ->
        "";
      false ->
        "";
      {value,{_,"/"}} ->
        "/";
      {value,{_,Value}} ->
        filename:join(filename:split(Value)) ++ "/"
    end,
["
<!-- Form around whole table to avoid Netscape space after form problem -->
<form action=\"http://www.erlang.org/cgi-bin/se_search\" method=\"get\">
  <input type=\"hidden\" name=\"data\" value=\"search_index\">
  <input type=\"hidden\" name=\"result_max\" value=\"10\">

<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
  <tr>
    <td bgcolor=\"#336699\" width=\"1%\" align=\"left\"><a href=\"http://www.ericsson.se\"><img src=\"",RelPath,"images/erilogo.gif\" alt=\"Ericsson\" border=\"0\" width=\"123\" height=\"34\"></a></td>
    <td bgcolor=\"#336699\" align=right><font face=\"Helvetica,Ariel\" size=+2 color=\"#FFFFFF\">Open Source Erlang</font></td>
    <td bgcolor=\"#336699\" width=\"1%\" valign=\"top\" align=\"right\"><img src=\"",RelPath,"images/corner.gif\" alt border=\"0\" width=\"10\" height=\"34\"></td>
  </tr>
  <tr>
    <td bgcolor=\"#ADD8E6\" height=\"30\" align=\"left\" valign=\"middle\">
      <b><font face=\"Helvetica,Ariel\" size=\"2\" color=\"#336699\">&nbsp; Ericsson Utvecklings AB</font></b>
    </td>
    <td bgcolor=\"#ADD8E6\" height=\"30\" align=\"right\" valign=\"bottom\">
        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
          <tr>
            <td valign=\"middle\" height=\"20\">
              <font face=\"Helvetica,Ariel\" size=\"2\" color=\"#336699\">
                <a href=\"http://www.erlang.org/search/\">Search</a>&nbsp;
              </font>
            </td>
            <td valign=\"middle\" height=\"20\">
              <font face=\"Helvetica,Ariel\" size=\"1\" color=\"#336699\">
                <input type=\"text\" size=\"15\" name=\"query\">
              </font>
            </td>
          </tr>
        </table>
    </td>
    <td bgcolor=\"#ADD8E6\">
        &nbsp;
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"32\">
      &nbsp;
    </td>
  </tr>
</table>

</form>

<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">
  <tr>
    <td valign=\"top\" width=\"135\">
      <table>
        <tr>
          <td>
            <a href=\"",RelPath,"index.html\"><img src=\"",RelPath,"images/erlang.gif\" border=\"0\" alt=\"Home\"></a>
          </td>
        </tr>
        <tr>
          <td>
      <b>&middot;&nbsp;<a href=\"",RelPath,"index.html\"><font face=\"Helvetica,Ariel\" size=-1>Home</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"mirrors.html\"><font face=\"Helvetica,Ariel\" size=-1>Mirrors</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"download.html\"><font face=\"Helvetica,Ariel\" size=-1>Download</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"links.html\"><font face=\"Helvetica,Ariel\" size=-1>Links and Activities</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"faq.html\"><font face=\"Helvetica,Ariel\" size=-1>FAQs + Contact</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"starting.html\"><font face=\"Helvetica,Ariel\" size=-1>Getting started</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"doc.html\"><font face=\"Helvetica,Ariel\" size=-1>Documentation</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"examples.html\"><font face=\"Helvetica,Ariel\" size=-1>Examples</font></a></b><br>
      <b>&middot;&nbsp;<a href=\"",RelPath,"user.html\"><font face=\"Helvetica,Ariel\" size=-1>User Contributions</font></a></b><br>
      <br>
      <br>
      <br>
      <i><font face=\"Helvetica,Ariel\" size=-2>For comments or questions about this site, contact
      <a href=\"mailto:kent\">kent</a></font></i>
          </td>
        </tr>
      </table>
    </td>
    <td valign=\"top\" width=\"29\" background=\"",RelPath,"images/vr.gif\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
    <td valign=\"top\">
"]
end
</def>

<def name="footer">
fun(_, Str) ->
{{Year, Month, Day},{Hour, Minute, Second}} = calendar:universal_time(),
Updated = io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w UTC\n",[Year, Month, Day, Hour, Minute]),
["
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"34\">
      &nbsp;
    </td>
  </tr>
  <tr>
    <td colspan=\"3\" height=\"34\" align=\"center\" bgcolor=\"#ADD8E6\">
      Last updated &nbsp; ",Updated,"
    </td>
  </tr>
</table>
"]
end
</def>


<def name="color">
fun(_,S) ->
        ["<table width=\"100%\" bgcolor=\"#ADD8E6\" border=0 cellspacing=0
cellpadding=4><tr><td>\n",S,"</td></tr></table>\n"]
end
</def>

<def name="banner">
fun(_,Str) ->
        ["<color><center><b>",Str,"</b></center></color><p>"]
end
</def>

<def name="box">
  fun(_, Str) ->
          Entity =
              fun($&) -> "&amp;";
                 ($<) -> "&lt;";
                 ($>) -> "&gt;";
                 (C)  -> C
              end,
["<table border=1 cellpadding=10>
  <tr>
    <td>
      <pre><b>
",lists:map(Entity,Str),"
      </b></pre>
    </td>
  </tr>
</table>"]
  end

</def>

<def name="lit">
  fun(_, Str) ->
          Entity =
              fun($&) -> "&amp;";
                 ($<) -> "&lt;";
                 ($>) -> "&gt;";
                 (C)  -> C
              end,
["<pre><b>
", lists:map(Entity,Str), "
</b></pre>"]
  end
</def>

<def name="indent">
fun(_, Str) ->
        ["<blockquote>",Str,"</blockquote>"]
end
</def>

<def name="insert_file">
  fun(_, Str) ->
     {ok, Bin} = file:read_file(Str),
          Entity =
              fun($&) -> "&amp;";
                 ($<) -> "&lt;";
                 ($>) -> "&gt;";
                 (C)  -> C
              end,
["<pre>
",lists:map(Entity,binary_to_list(Bin)),"
</pre>"]
end
</def>


<!-- ############################################################ -->

<def name="yes">
fun(_, Str) ->
        X = "download/" ++ Str,
        Meg = case file:file_info(X) of
          {ok, Tup} ->
             I = element(1, Tup) div (100 * 1024),  % 1/10 meg
             K = element(1, Tup) div 1024,  % Kbytes
             if
                I == 0 -> "(" ++ integer_to_list(K) ++ "&nbsp;KB)";
                true ->  
                  case lists:reverse(integer_to_list(I)) of
                     [Last] -> "(0." ++ integer_to_list(I) ++ "&nbsp;MB)";
                     [Last|T] -> "(" ++ lists:reverse(T) ++ "." ++
                                 [Last] ++ "&nbsp;MB)";
                     _ -> ""
                  end
               end;
            _ ->
                "Broken link !!! "
         end,            
 Yes = "yes",
 ["<td><a href=\"download/",  Str,"\">",  Yes, "</a>", "&nbsp;&nbsp;", Meg, "</td>"]
end
</def>


<def name="download_file">
fun(_, String) ->
        X = "download/" ++ String,
        Meg = case file:file_info(X) of
          {ok, Tup} ->
             I = element(1, Tup) div (100 * 1024),  % 1/10 meg
             K = element(1, Tup) div 1024,  % Kbytes
             if
                I == 0 -> "(" ++ integer_to_list(K) ++ "&nbsp;KB)";
                true ->  
                  case lists:reverse(integer_to_list(I)) of
                     [Last] -> "(0." ++ integer_to_list(I) ++ "&nbsp;MB)";
                     [Last|T] -> "(" ++ lists:reverse(T) ++ "." ++
                                 [Last] ++ "&nbsp;MB)";
                     _ -> ""
                  end
               end;
            _ ->
                "Broken link !!! "
         end,      
        ["<dt><a href=\"download/",
         String,"\">",  "<b>", String, "</b>", "</a>", "&nbsp;&nbsp;", Meg]


        end
</def>


<def name="no">
fun(_, Str) ->
        ["<td>no</td>"]
end
</def>


<def name="soon">
fun(_, Str) ->
        ["<td>soon</td>"]
end
</def>

<def name="na">
fun(_, Str) ->
        ["<td>&nbsp;</td>"]
end
</def>

<def name="mirrors">
fun(_, Str) ->
    {ok,Binary} = file:read_file("MIRRORS"),
    Chars = binary_to_list(Binary),
    Lines = string:tokens(Chars, "\n"),
    Fun =
        fun(Line, Acc)
           ->
                case Line of
                    "URL:" ++ URL ->
                        Url = string:strip(URL),
                        Acc ++ "  <li><a href=\"" ++ Url ++ "\">" ++ Url ++ "</a>\n";
                    "TXT:" ++ TXT ->
                        Txt = string:strip(TXT),
                        Acc ++ "      (" ++ Txt ++ ")\n";
                    _ ->
                        Acc
                end
        end,
    lists:foldl(Fun, [], Lines)
end
</def>