diff options
Diffstat (limited to 'plugins/coro-net/init.lua')
-rw-r--r-- | plugins/coro-net/init.lua | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/plugins/coro-net/init.lua b/plugins/coro-net/init.lua new file mode 100644 index 00000000000..3ae6c2ad824 --- /dev/null +++ b/plugins/coro-net/init.lua @@ -0,0 +1,113 @@ +local exports = {} +exports.name = "creationix/coro-net" +exports.version = "1.1.1-1" +exports.dependencies = { + "creationix/coro-channel@1.2.0" +} +exports.homepage = "https://github.com/luvit/lit/blob/master/deps/coro-net.lua" +exports.description = "An coro style client and server helper for tcp and pipes." +exports.tags = {"coro", "tcp", "pipe", "net"} +exports.license = "MIT" +exports.author = { name = "Tim Caswell" } + +local uv = require('luv') +local wrapStream = require('coro-channel').wrapStream + +local function makeCallback(timeout) + local thread = coroutine.running() + local timer, done + if timeout then + timer = uv.new_timer() + timer:start(timeout, 0, function () + if done then return end + done = true + timer:close() + return assert(coroutine.resume(thread, nil, "timeout")) + end) + end + return function (err, data) + if done then return end + done = true + if timer then timer:close() end + if err then + return assert(coroutine.resume(thread, nil, err)) + end + return assert(coroutine.resume(thread, data or true)) + end +end +exports.makeCallback = makeCallback + +local function normalize(options) + local t = type(options) + if t == "string" then + options = {path=options} + elseif t == "number" then + options = {port=options} + elseif t ~= "table" then + assert("Net options must be table, string, or number") + end + if options.port or options.host then + return true, + options.host or "127.0.0.1", + assert(options.port, "options.port is required for tcp connections") + elseif options.path then + return false, options.path + else + error("Must set either options.path or options.port") + end +end + +function exports.connect(options) + local socket, success, err + local isTcp, host, port = normalize(options) + if isTcp then + assert(uv.getaddrinfo(host, port, { + socktype = options.socktype or "stream", + family = options.family or "inet", + }, makeCallback(options.timeout))) + local res + res, err = coroutine.yield() + if not res then return nil, err end + socket = uv.new_tcp() + socket:connect(res[1].addr, res[1].port, makeCallback(options.timeout)) + else + socket = uv.new_pipe(false) + socket:connect(host, makeCallback(options.timeout)) + end + success, err = coroutine.yield() + if not success then return nil, err end + local read, write = wrapStream(socket) + return read, write, socket +end + +function exports.createServer(options, onConnect) + local server + local isTcp, host, port = normalize(options) + if isTcp then + server = uv.new_tcp() + assert(server:bind(host, port)) + else + server = uv.new_pipe(false) + assert(server:bind(host)) + end + assert(server:listen(256, function (err) + assert(not err, err) + local socket = isTcp and uv.new_tcp() or uv.new_pipe(false) + server:accept(socket) + coroutine.wrap(function () + local success, failure = xpcall(function () + local read, write = wrapStream(socket) + return onConnect(read, write, socket) + end, debug.traceback) + if not success then + print(failure) + end + if not socket:is_closing() then + socket:close() + end + end)() + end)) + return server +end + +return exports |