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:
and here is the .pht file that generated that:
<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