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:
parent
067ffdf3e5
commit
b4a2d02431
@ -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
|
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"_.
|
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.
|
Look at the included example scripts for more ideas.
|
||||||
|
|
||||||
### Example: Garage door opener
|
### Example: Garage door opener
|
||||||
|
|||||||
@ -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("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('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Server File Listing</title></head>')
|
||||||
connection:send('<body>')
|
connection:send('<body>')
|
||||||
coroutine.yield()
|
|
||||||
connection:send('<h1>Server File Listing</h1>')
|
connection:send('<h1>Server File Listing</h1>')
|
||||||
|
|
||||||
local remaining, used, total=file.fsinfo()
|
local remaining, used, total=file.fsinfo()
|
||||||
@ -20,8 +19,6 @@ return function (connection, req, args)
|
|||||||
if isHttpFile then
|
if isHttpFile then
|
||||||
local url = string.match(name, ".*/(.*)")
|
local url = string.match(name, ".*/(.*)")
|
||||||
connection:send(' <li><a href="' .. url .. '">' .. url .. "</a> (" .. size .. " bytes)</li>\n")
|
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
|
||||||
end
|
end
|
||||||
connection:send("</ul>\n")
|
connection:send("</ul>\n")
|
||||||
|
|||||||
@ -20,7 +20,6 @@ return function (connection, req, args)
|
|||||||
if chunk == nil then
|
if chunk == nil then
|
||||||
continue = false
|
continue = false
|
||||||
else
|
else
|
||||||
coroutine.yield()
|
|
||||||
connection:send(chunk)
|
connection:send(chunk)
|
||||||
bytesSent = bytesSent + #chunk
|
bytesSent = bytesSent + #chunk
|
||||||
chunk = nil
|
chunk = nil
|
||||||
|
|||||||
@ -13,9 +13,37 @@ return function (port)
|
|||||||
-- We do it in a separate thread because we need to yield when sending lots
|
-- 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.
|
-- of data in order to avoid overflowing the mcu's buffer.
|
||||||
local connectionThread
|
local connectionThread
|
||||||
|
|
||||||
local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}
|
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)
|
local function onRequest(connection, req)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
local method = req.method
|
local method = req.method
|
||||||
@ -59,8 +87,7 @@ return function (port)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
connectionThread = coroutine.create(fileServeFunction)
|
startServing(fileServeFunction, connection, req, uri.args)
|
||||||
coroutine.resume(connectionThread, connection, req, uri.args)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onReceive(connection, payload)
|
local function onReceive(connection, payload)
|
||||||
@ -89,18 +116,20 @@ return function (port)
|
|||||||
else
|
else
|
||||||
args = {code = 400, errorString = "Bad Request"}
|
args = {code = 400, errorString = "Bad Request"}
|
||||||
end
|
end
|
||||||
connectionThread = coroutine.create(fileServeFunction)
|
startServing(fileServeFunction, connection, req, args)
|
||||||
coroutine.resume(connectionThread, connection, req, args)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onSent(connection, payload)
|
local function onSent(connection, payload)
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
if connectionThread then
|
if connectionThread then
|
||||||
local connectionThreadStatus = coroutine.status(connectionThread)
|
local connectionThreadStatus = coroutine.status(connectionThread)
|
||||||
if connectionThreadStatus == "suspended" then
|
if connectionThreadStatus == "suspended" then
|
||||||
-- Not finished sending file, resume.
|
-- 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
|
elseif connectionThreadStatus == "dead" then
|
||||||
-- We're done sending file.
|
-- We're done sending file.
|
||||||
connection:close()
|
connection:close()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user