mirror of
				https://github.com/Ysurac/openmptcprouter-feeds.git
				synced 2025-03-09 15:40:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			316 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
--[[
 | 
						||
LuaSocket 2.0.2 license
 | 
						||
Copyright <20> 2004-2007 Diego Nehab
 | 
						||
 | 
						||
Permission is hereby granted, free of charge, to any person obtaining a
 | 
						||
copy of this software and associated documentation files (the "Software"),
 | 
						||
to deal in the Software without restriction, including without limitation
 | 
						||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						||
and/or sell copies of the Software, and to permit persons to whom the
 | 
						||
Software is furnished to do so, subject to the following conditions:
 | 
						||
 | 
						||
The above copyright notice and this permission notice shall be included in
 | 
						||
all copies or substantial portions of the Software.
 | 
						||
 | 
						||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
						||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
						||
DEALINGS IN THE SOFTWARE.
 | 
						||
]]--
 | 
						||
--[[
 | 
						||
	Changes made by LuCI project:
 | 
						||
		* Renamed to luci.ltn12 to avoid collisions with luasocket
 | 
						||
		* Added inline documentation
 | 
						||
]]--
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- LTN12 - Filters, sources, sinks and pumps.
 | 
						||
-- LuaSocket toolkit.
 | 
						||
-- Author: Diego Nehab
 | 
						||
-- RCS ID: $Id$
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- Declare module
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
local string = require("string")
 | 
						||
local table = require("table")
 | 
						||
local base = _G
 | 
						||
 | 
						||
-- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts 
 | 
						||
module("luci.ltn12")
 | 
						||
 | 
						||
filter = {}
 | 
						||
source = {}
 | 
						||
sink = {}
 | 
						||
pump = {}
 | 
						||
 | 
						||
-- 2048 seems to be better in windows...
 | 
						||
BLOCKSIZE = 2048
 | 
						||
_VERSION = "LTN12 1.0.1"
 | 
						||
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- Filter stuff
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
 | 
						||
 | 
						||
-- by passing it each chunk and updating a context between calls. 
 | 
						||
function filter.cycle(low, ctx, extra)
 | 
						||
    base.assert(low)
 | 
						||
    return function(chunk)
 | 
						||
        local ret
 | 
						||
        ret, ctx = low(ctx, chunk, extra)
 | 
						||
        return ret
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
-- (thanks to Wim Couwenberg)
 | 
						||
function filter.chain(...)
 | 
						||
    local n = table.getn(arg)
 | 
						||
    local top, index = 1, 1
 | 
						||
    local retry = ""
 | 
						||
    return function(chunk)
 | 
						||
        retry = chunk and retry
 | 
						||
        while true do
 | 
						||
            if index == top then
 | 
						||
                chunk = arg[index](chunk)
 | 
						||
                if chunk == "" or top == n then return chunk
 | 
						||
                elseif chunk then index = index + 1
 | 
						||
                else
 | 
						||
                    top = top+1
 | 
						||
                    index = top
 | 
						||
                end
 | 
						||
            else
 | 
						||
                chunk = arg[index](chunk or "")
 | 
						||
                if chunk == "" then
 | 
						||
                    index = index - 1
 | 
						||
                    chunk = retry
 | 
						||
                elseif chunk then
 | 
						||
                    if index == n then return chunk
 | 
						||
                    else index = index + 1 end
 | 
						||
                else base.error("filter returned inappropriate nil") end
 | 
						||
            end
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- Source stuff
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
 | 
						||
 | 
						||
-- create an empty source
 | 
						||
local function empty()
 | 
						||
    return nil
 | 
						||
end
 | 
						||
 | 
						||
function source.empty()
 | 
						||
    return empty
 | 
						||
end
 | 
						||
 | 
						||
function source.error(err)
 | 
						||
    return function()
 | 
						||
        return nil, err
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
function source.file(handle, io_err)
 | 
						||
    if handle then
 | 
						||
        return function()
 | 
						||
            local chunk = handle:read(BLOCKSIZE)
 | 
						||
            if chunk and chunk:len() == 0 then chunk = nil end
 | 
						||
            if not chunk then handle:close() end
 | 
						||
            return chunk
 | 
						||
        end
 | 
						||
    else return source.error(io_err or "unable to open file") end
 | 
						||
end
 | 
						||
 | 
						||
function source.simplify(src)
 | 
						||
    base.assert(src)
 | 
						||
    return function()
 | 
						||
        local chunk, err_or_new = src()
 | 
						||
        src = err_or_new or src
 | 
						||
        if not chunk then return nil, err_or_new
 | 
						||
        else return chunk end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
function source.string(s)
 | 
						||
    if s then
 | 
						||
        local i = 1
 | 
						||
        return function()
 | 
						||
            local chunk = string.sub(s, i, i+BLOCKSIZE-1)
 | 
						||
            i = i + BLOCKSIZE
 | 
						||
            if chunk ~= "" then return chunk
 | 
						||
            else return nil end
 | 
						||
        end
 | 
						||
    else return source.empty() end
 | 
						||
end
 | 
						||
 | 
						||
function source.rewind(src)
 | 
						||
    base.assert(src)
 | 
						||
    local t = {}
 | 
						||
    return function(chunk)
 | 
						||
        if not chunk then
 | 
						||
            chunk = table.remove(t)
 | 
						||
            if not chunk then return src()
 | 
						||
            else return chunk end
 | 
						||
        else
 | 
						||
            t[#t+1] = chunk
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
function source.chain(src, f)
 | 
						||
    base.assert(src and f)
 | 
						||
    local last_in, last_out = "", ""
 | 
						||
    local state = "feeding"
 | 
						||
    local err
 | 
						||
    return function()
 | 
						||
        if not last_out then
 | 
						||
            base.error('source is empty!', 2)
 | 
						||
        end
 | 
						||
        while true do
 | 
						||
            if state == "feeding" then
 | 
						||
                last_in, err = src()
 | 
						||
                if err then return nil, err end
 | 
						||
                last_out = f(last_in)
 | 
						||
                if not last_out then
 | 
						||
                    if last_in then
 | 
						||
                        base.error('filter returned inappropriate nil')
 | 
						||
                    else
 | 
						||
                        return nil
 | 
						||
                    end
 | 
						||
                elseif last_out ~= "" then
 | 
						||
                    state = "eating"
 | 
						||
                    if last_in then last_in = "" end
 | 
						||
                    return last_out
 | 
						||
                end
 | 
						||
            else
 | 
						||
                last_out = f(last_in)
 | 
						||
                if last_out == "" then
 | 
						||
                    if last_in == "" then
 | 
						||
                        state = "feeding"
 | 
						||
                    else
 | 
						||
                        base.error('filter returned ""')
 | 
						||
                    end
 | 
						||
                elseif not last_out then
 | 
						||
                    if last_in then
 | 
						||
                        base.error('filter returned inappropriate nil')
 | 
						||
                    else
 | 
						||
                        return nil
 | 
						||
                    end
 | 
						||
                else
 | 
						||
                    return last_out
 | 
						||
                end
 | 
						||
            end
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
-- Sources will be used one after the other, as if they were concatenated
 | 
						||
-- (thanks to Wim Couwenberg)
 | 
						||
function source.cat(...)
 | 
						||
    local src = table.remove(arg, 1)
 | 
						||
    return function()
 | 
						||
        while src do
 | 
						||
            local chunk, err = src()
 | 
						||
            if chunk then return chunk end
 | 
						||
            if err then return nil, err end
 | 
						||
            src = table.remove(arg, 1)
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- Sink stuff
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
 | 
						||
 | 
						||
function sink.table(t)
 | 
						||
    t = t or {}
 | 
						||
    local f = function(chunk, err)
 | 
						||
        if chunk then t[#t+1] = chunk end
 | 
						||
        return 1
 | 
						||
    end
 | 
						||
    return f, t
 | 
						||
end
 | 
						||
 | 
						||
function sink.simplify(snk)
 | 
						||
    base.assert(snk)
 | 
						||
    return function(chunk, err)
 | 
						||
        local ret, err_or_new = snk(chunk, err)
 | 
						||
        if not ret then return nil, err_or_new end
 | 
						||
        snk = err_or_new or snk
 | 
						||
        return 1
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
function sink.file(handle, io_err)
 | 
						||
    if handle then
 | 
						||
        return function(chunk, err)
 | 
						||
            if not chunk then
 | 
						||
                handle:close()
 | 
						||
                return 1
 | 
						||
            else return handle:write(chunk) end
 | 
						||
        end
 | 
						||
    else return sink.error(io_err or "unable to open file") end
 | 
						||
end
 | 
						||
 | 
						||
-- creates a sink that discards data
 | 
						||
local function null()
 | 
						||
    return 1
 | 
						||
end
 | 
						||
 | 
						||
function sink.null()
 | 
						||
    return null
 | 
						||
end
 | 
						||
 | 
						||
function sink.error(err)
 | 
						||
    return function()
 | 
						||
        return nil, err
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
function sink.chain(f, snk)
 | 
						||
    base.assert(f and snk)
 | 
						||
    return function(chunk, err)
 | 
						||
        if chunk ~= "" then
 | 
						||
            local filtered = f(chunk)
 | 
						||
            local done = chunk and ""
 | 
						||
            while true do
 | 
						||
                local ret, snkerr = snk(filtered, err)
 | 
						||
                if not ret then return nil, snkerr end
 | 
						||
                if filtered == done then return 1 end
 | 
						||
                filtered = f(done)
 | 
						||
            end
 | 
						||
        else return 1 end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
-- Pump stuff
 | 
						||
-----------------------------------------------------------------------------
 | 
						||
 | 
						||
 | 
						||
function pump.step(src, snk)
 | 
						||
    local chunk, src_err = src()
 | 
						||
    local ret, snk_err = snk(chunk, src_err)
 | 
						||
    if chunk and ret then return 1
 | 
						||
    else return nil, src_err or snk_err end
 | 
						||
end
 | 
						||
 | 
						||
function pump.all(src, snk, step)
 | 
						||
    base.assert(src and snk)
 | 
						||
    step = step or pump.step
 | 
						||
    while true do
 | 
						||
        local ret, err = step(src, snk)
 | 
						||
        if not ret then
 | 
						||
            if err then return nil, err
 | 
						||
            else return 1 end
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 |