Post your best Lua script examples here

User avatar
By dpwhittaker
#10079 I've taken a different stab at the lhttpd.lua port, here.

Goals:
1. Keep it small - I wanted it under 2k to save as much room as possible for the actual web site, but didn't quite make it
2. Support cgi-style .lua scripts - the first version claimed support but I couldn't get it working and didn't see any code that would support it.
3. Enable larger files to be served, including images - by avoiding readlines, chunking sends, and waiting for the sent callback every 1460 bytes, it should serve any file you can fit in flash
4. Allow multiple line lua code and <? for ... do ?> Some html <? value ?> more html <?end?> constructs

The main differences are:

1. .pht files delimit code with <? code ?>, not <?lua code ?>... this is primarily due to the way I am abusing file.read(char) to find the next transition between html and lua: "?" is a less common character in html than "a", and having the start and end delimiters be the same length allowed some other optimizations.
2. .pht files can use <?= expression?> to emit the value of the expression. This is converted to <? req.send(expression) ?>.
3. req.send replaces print. This is where the coroutine.yield happens to let the data send before resuming your script.
4. req also contains other goodies: all the headers and querystring parameters, and "body". Be sure to include "local req = ..." at the top of your .lua files to use this table.

The pht andvances were especially fun - I went a completely different way. It basically uses "load" to incrementally build a .lua file on the fly, converting everything between ?> and the next <? to a req.send([[...]]). It uses file.read("?"), then checks if the last two characters are "<?" (and ">"/"?>" to find the end of code). This lets it read bigger chunks at a time, which should increase performance. Here is a screenshot of its output:

Image

and here is the .pht file that generated that:

Code: Select all<html>
   <body>
      <img src="/NodeMCU.jpg"/>
      <table>
         <tr><th>Key</th><th>Value</th></tr>
         <? for k, v in pairs(req) do ?>
         <tr><td><?=k?></td><td><?=tostring(v)?></td></tr>
         <? end ?>
      </table>
      <?
      s = "This is a test of multiline."
      s = s.. "<br/>Will this work?"
      if s:len() > 10 then req.send(s) end
      ?>
   </body>
</html>


To Do:

0. Get it out of dropbox and on github.
1. Handle larger POSTs than 1460 bytes. I'm thinking about two approaches here: have the user put a function on req to handle the additional chunks (it would fall back to re-calling the file with the next chunk replacing the req.body value), or using something like "next = coroutine.yield("next")" that would tell the "sent" callback to stop resuming the coroutine and let the "receive" callback do it when it gets more data. May be difficult to handle the end of stream (keep a sum of packet lengths and compare to Content-Length?). Also what to do if "receive" is called during a yield for a send.
2. Implement automatic node.compile for .lua files. I think I can string.dump the function generated by the load in the pht routine for a similar effect there. It is easy to run out of memory on pht files especially. Use the compiled version from then on.
3. Any other ideas?

Let me know what you think.
David Whittaker
User avatar
By alonewolfx2
#10081 Can I test your code? It seems very good but is memory enough for this?
User avatar
By dpwhittaker
#10092 Please do! Memory is my greatest concern. The included test files worked alright, but I'd be interested to see how larger pht files worked. I used an integer build, so I don't know if it will work at all on float.

I can imagine a memory saving optimization of the pht routine: load a chunk at a time. If it doesn't compile, append the next chunk and try again. setfenv to carry the local environment through each chunk. However, that would increase the size and may not necessarily be useful, especially if precompilation solves any memory problems.

So, if you want to poke around the edges and see if you can find the threshold of what it can handle, be my guest! Give me some lua and/or pht scripts that run out of memory, and it will give me a challenge to make those work :D .