1 -----------------------------------------------------------------------------
2 -- Little program to download files from URLs
3 -- LuaSocket sample files
5 -----------------------------------------------------------------------------
6 local socket
= require("socket")
7 local http
= require("socket.http")
8 local ftp
= require("socket.ftp")
9 local url
= require("socket.url")
10 local ltn12
= require("ltn12")
12 -- formats a number of seconds into human readable form
27 if l
== "s" then return string.format("%5.0f%s", s
, l
)
28 else return string.format("%5.2f%s", s
, l
) end
31 -- formats a number of bytes into human readable form
46 return string.format("%7.2f%2s", b
, l
)
49 -- returns a string with the current state of the download
50 local remaining_s
= "%s received, %s/s throughput, %2.0f%% done, %s remaining"
51 local elapsed_s
= "%s received, %s/s throughput, %s elapsed "
52 function gauge(got
, delta
, size
)
53 local rate
= got
/ delta
54 if size
and size
>= 1 then
55 return string.format(remaining_s
, nicesize(got
), nicesize(rate
),
56 100*got
/size
, nicetime((size
-got
)/rate
))
58 return string.format(elapsed_s
, nicesize(got
),
59 nicesize(rate
), nicetime(delta
))
63 -- creates a new instance of a receive_cb that saves to disk
64 -- kind of copied from luasocket's manual callback examples
66 local start
= socket
.gettime()
69 return function(chunk
)
70 -- elapsed time since start
71 local current
= socket
.gettime()
73 -- total bytes received
74 got
= got
+ string.len(chunk
)
75 -- not enough time for estimate
76 if current
- last
> 1 then
77 io
.stderr
:write("\r", gauge(got
, current
- start
, size
))
83 io
.stderr
:write("\r", gauge(got
, current
- start
), "\n")
89 -- determines the size of a http file
90 function gethttpsize(u
)
91 local r
, c
, h
= http
.request
{method
= "HEAD", url
= u
}
93 return tonumber(h
["content-length"])
97 -- downloads a file using the http protocol
98 function getbyhttp(u
, file
)
99 local save
= ltn12
.sink
.file(file
or io
.stdout
)
100 -- only print feedback if output is not stdout
101 if file
then save
= ltn12
.sink
.chain(stats(gethttpsize(u
)), save
) end
102 local r
, c
, h
, s
= http
.request
{url
= u
, sink
= save
}
103 if c
~= 200 then io
.stderr
:write(s
or c
, "\n") end
106 -- downloads a file using the ftp protocol
107 function getbyftp(u
, file
)
108 local save
= ltn12
.sink
.file(file
or io
.stdout
)
109 -- only print feedback if output is not stdout
110 -- and we don't know how big the file is
111 if file
then save
= ltn12
.sink
.chain(stats(), save
) end
112 local gett
= url
.parse(u
)
115 local ret
, err
= ftp
.get(gett
)
116 if err
then print(err
) end
119 -- determines the scheme
120 function getscheme(u
)
121 -- this is an heuristic to solve a common invalid url poblem
122 if not string.find(u
, "//") then u
= "//" .. u
end
123 local parsed
= url
.parse(u
, {scheme
= "http"})
127 -- gets a file either by http or ftp, saving as <name>
128 function get(u
, name
)
129 local fout
= name
and io
.open(name
, "wb")
130 local scheme
= getscheme(u
)
131 if scheme
== "ftp" then getbyftp(u
, fout
)
132 elseif scheme
== "http" then getbyhttp(u
, fout
)
133 else print("unknown scheme" .. scheme
) end
138 if table.getn(arg
) < 1 then
139 io
.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
141 else get(arg
[1], arg
[2]) end