Fix the problem with the more modern SDK only allowing one outstanding

connection:send at a time. Long and short of it, don't use coroutine.yield
any more when serving content.
This commit is contained in:
Philip Gladstone 2015-11-22 13:39:03 -05:00
parent 067ffdf3e5
commit b4a2d02431
4 changed files with 36 additions and 16 deletions

View File

@ -78,11 +78,6 @@ A (very) simple web server written in Lua for the ESP8266 running the NodeMCU fi
For example, if the client requests _http://2.2.2.2/foo.lua?color=red_ then the server will execute the function
in your Lua script _foo.lua_ and pass in _connection_ and _args_, where _args.color = "red"_.
If you are going to be sending lots (as in over a KB) of data in your script, you should yield the thread/coroutine
every now and then in order to avoid overflowing the send buffer in the microcontroller. Use:
coroutine.yield()
Look at the included example scripts for more ideas.
### Example: Garage door opener

View File

@ -2,7 +2,6 @@ return function (connection, req, args)
connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n")
connection:send('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Server File Listing</title></head>')
connection:send('<body>')
coroutine.yield()
connection:send('<h1>Server File Listing</h1>')
local remaining, used, total=file.fsinfo()
@ -20,8 +19,6 @@ return function (connection, req, args)
if isHttpFile then
local url = string.match(name, ".*/(.*)")
connection:send(' <li><a href="' .. url .. '">' .. url .. "</a> (" .. size .. " bytes)</li>\n")
-- this list could be very long, so we'll yield in order to avoid overflowing the send buffer.
coroutine.yield()
end
end
connection:send("</ul>\n")

View File

@ -20,7 +20,6 @@ return function (connection, req, args)
if chunk == nil then
continue = false
else
coroutine.yield()
connection:send(chunk)
bytesSent = bytesSent + #chunk
chunk = nil

View File

@ -13,9 +13,37 @@ return function (port)
-- We do it in a separate thread because we need to yield when sending lots
-- of data in order to avoid overflowing the mcu's buffer.
local connectionThread
local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}
local function startServing(fileServeFunction, connection, req, args)
local bufferedConnection = {}
connectionThread = coroutine.create(function(fileServeFunction, connection, req, args)
fileServeFunction(connection, req, args)
connection:flush()
end)
function bufferedConnection:flush()
connection:send(table.concat(self.data, ""))
self.data = {}
self.size = 0
end
function bufferedConnection:send(payload)
local l = payload:len()
if l + self.size > 1400 then
self:flush()
coroutine.yield()
end
table.insert(self.data, payload)
self.size = self.size + l
end
bufferedConnection.size = 0
bufferedConnection.data = {}
local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
if not status then
print(err)
end
end
local function onRequest(connection, req)
collectgarbage()
local method = req.method
@ -59,8 +87,7 @@ return function (port)
end
end
end
connectionThread = coroutine.create(fileServeFunction)
coroutine.resume(connectionThread, connection, req, uri.args)
startServing(fileServeFunction, connection, req, uri.args)
end
local function onReceive(connection, payload)
@ -89,18 +116,20 @@ return function (port)
else
args = {code = 400, errorString = "Bad Request"}
end
connectionThread = coroutine.create(fileServeFunction)
coroutine.resume(connectionThread, connection, req, args)
startServing(fileServeFunction, connection, req, args)
end
end
local function onSent(connection, payload)
collectgarbage()
if connectionThread then
local connectionThreadStatus = coroutine.status(connectionThread)
local connectionThreadStatus = coroutine.status(connectionThread)
if connectionThreadStatus == "suspended" then
-- Not finished sending file, resume.
coroutine.resume(connectionThread)
local status, err = coroutine.resume(connectionThread)
if not status then
print(err)
end
elseif connectionThreadStatus == "dead" then
-- We're done sending file.
connection:close()