Lua: Retrieve partial ftp file at specific range – Method 2


We wrote an article: Lua: Retrieve partial ftp file at specific range about method 1, but in some case, we see when you receive more than 60000 you won’t receive exact range, example get range from 10000-80000, but you will receive content of range 10000-end.
So we must write second method, use command REST.

Step 1: Edit file /usr/share/lua/5.1/socket/ftp.lua

Add function rest:

function metat.__index:rest(start)

	local x,y =    self.try(self.tp:command("rest", start))
	local a,b =    self.try(self.tp:check(350))
	 
    return 1
end

Edit function tget

local function tget(gett)
    gett = override(gett)
    socket.try(gett.host, "missing hostname")
    local f = _M.open(gett.host, gett.port, gett.create)
    f:greet()
    f:login(gett.user, gett.password)
    if gett.type then f:type(gett.type) end  
    --f:size(gett) --you can use to get filesize, but must use function size at end of this tutorial
 
	if gett.rang then
		local pp = gett.rang:gsub(" .+","")
		pp = tonumber(pp)
	if pp>0 then	f:rest(pp)  end
	end
	
	if gett.rang and gett.rang ~= '' then
		gett._tp = f
	end
	
    f:epsv()
    f:receive(gett)
    f:quit()
    return f:close()
end

Step 2: Lua code

  
	function download(u,rang,sink)
	    
	   local t = {}
	   local p = url.parse(u)
	   p.command = "retr"
	   p.type = "i"
	   
	   if sink then
			p.sink = sink(t)
	   else
			p.sink = ltn12.sink.table(t)
	   end
	   
	   p.argument = string.gsub(p.path, "^/", "")
	   if p.argument == "" then p.argument = nil end
	   p.check = 250
	   if rang and rang ~= "" then
		  p.rang = rang
		   
		  p._count = 0
		 
		local x1,_ = rang:gsub(".+ (.+)","%1")
		 
		local x2,_ = rang:gsub(" .+","")
		 
		p._max = tonumber(x1)-tonumber(x2) +1
		p.sink = function (chunk,err) 
			if chunk then 

				p._count = p._count + chunk:len()
				 if p._count>=p._max then 
				 
				  table.insert(t, chunk:sub(1,chunk:len() - p._count + p._max))
					if p._tp then						 
						p._count = nil
						p._max = nil
						p._tp:close() 
						p._tp = nil
						 
					end
				return nil
				else table.insert(t, chunk)
				end
			end
			return 1
		end
		  
		  
	   end
	   local a,b = ftp.get(p)
	   
	   return table.concat(t,'') -- , p.size --to get more filesize
	end

Example of usage function download:

						local content  =  download(ftp_link,rang)
						ngx.say(content)

Bunus: function size

function metat.__index:size(path)

	local x,y =    self.try(self.tp:command("size",path.path))	 
	local a,b =    self.try(self.tp:check{"1..","2..",213})
	 
	if b then 		 
		local l = b:gsub(".+ (.+)","%1")
		path.size = tonumber(l) --store filesize here
	end
    return 1
end

Leave a Reply