3.0 KiB
fifosock Module
Since | Origin / Contributor | Maintainer | Source |
---|---|---|---|
2019-02-10 | TerryE | nwf | fifosock.lua |
This module provides a moderately convenient, efficient wrapper around the
net.socket
send
method. It ensures in-order transmission while striving to
minimize memory footprint and packet count by coalescing queued strings. It
also serves as a detailed, worked example of the fifo
module.
Use
ssend = (require "fifosock").wrap(sock)
ssend("hello, ") ssend("world\n")
-- when finished
ssend = nil
sock:on("sent", nil)
Once the sock
et has been wrapped, one should use only the resulting ssend
function in lieu of sock:send
, and one should not change the
sock:on("sent")
callback for the duration of the connection.
Use of this module creates a circular reference through the Lua registry: the
socket points at the fifosock wrapper, which points back at the socket. As
such, it is vitally important to break this cycle when the socket has outlived
its use. The usual garbage collection will not be able to reclaim abandoned
wrapped sockets. The user of fifosock
must, when disposing of the socket,
unwire the wrapper, by calling sock:on("sent", nil)
and should drop all
references to ssend
; a convenient place to do this is in the
sock:on("disconnect")
callback.
Advanced Use
In addition to passing strings representing part of the stream to be sent, it
is possible to pass the resulting ssend
function functions. These
functions will be given no parameters, but should return two values:
- A string to be sent on the socket, or
nil
if no output is desired - A replacement function, or
nil
if the function is to be dequeued. Functions may, of course, offer themselves as their own replacement to stay at the front of the queue.
This facility is useful for providing a replacement for the sock:on("sent")
callback channel. In the fragment below, "All sent" will be print
ed only
when the entirety of "hello, world\n" has been successfully sent on the
sock
et.
ssend("hello, ") ssend("world\n")
ssend(function() print("All sent") end) -- implicitly returns nil, nil
This facility is also useful for generators of the stream, roughly akin to
sendfile
-like primitives in larger systems. Here, for example, we can stream
SPIFFS data across the network without ever holding a large amount in RAM.
local function sendfile(fn)
local offset = 0
local function send()
local f = file.open(fn, "r")
if f and f:seek("set", offset) then
r = f:read()
f:close()
if r then
offset = offset + #r
return r, send
end
end
-- implicitly returns nil, nil and falls out of the stream
end
return send, function() return offset end
end
local fn = "test"
ssend(("Sending file '%s'...\n"):format(fn))
dosf, getsent = sendfile(fn)
ssend(dosf)
ssend(("Sent %d bytes from '%s'\n"):format(getsent(), fn))