diff options
| author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2022-08-24 12:31:18 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-24 12:31:18 +0200 |
| commit | 87c48f3e4ddba13d9c014067e62568ba906cc410 (patch) | |
| tree | c99889ec0b9bbab2bc5ee14cd9046d0a122eb226 /samples/get.lua | |
| parent | 95b7efa9da506ef968c1347edf3fc56370f0deed (diff) | |
| parent | 97d5194f302d3fb9fe27874d9b5f73004a208d01 (diff) | |
| download | luasocket-87c48f3e4ddba13d9c014067e62568ba906cc410.tar.gz luasocket-87c48f3e4ddba13d9c014067e62568ba906cc410.tar.bz2 luasocket-87c48f3e4ddba13d9c014067e62568ba906cc410.zip | |
Merge pull request #364 from lunarmodules/cleanup
Diffstat (limited to 'samples/get.lua')
| -rw-r--r-- | samples/get.lua | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/samples/get.lua b/samples/get.lua new file mode 100644 index 0000000..d53c465 --- /dev/null +++ b/samples/get.lua | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | ----------------------------------------------------------------------------- | ||
| 2 | -- Little program to download files from URLs | ||
| 3 | -- LuaSocket sample files | ||
| 4 | -- Author: Diego Nehab | ||
| 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") | ||
| 11 | |||
| 12 | -- formats a number of seconds into human readable form | ||
| 13 | function nicetime(s) | ||
| 14 | local l = "s" | ||
| 15 | if s > 60 then | ||
| 16 | s = s / 60 | ||
| 17 | l = "m" | ||
| 18 | if s > 60 then | ||
| 19 | s = s / 60 | ||
| 20 | l = "h" | ||
| 21 | if s > 24 then | ||
| 22 | s = s / 24 | ||
| 23 | l = "d" -- hmmm | ||
| 24 | end | ||
| 25 | end | ||
| 26 | end | ||
| 27 | if l == "s" then return string.format("%5.0f%s", s, l) | ||
| 28 | else return string.format("%5.2f%s", s, l) end | ||
| 29 | end | ||
| 30 | |||
| 31 | -- formats a number of bytes into human readable form | ||
| 32 | function nicesize(b) | ||
| 33 | local l = "B" | ||
| 34 | if b > 1024 then | ||
| 35 | b = b / 1024 | ||
| 36 | l = "KB" | ||
| 37 | if b > 1024 then | ||
| 38 | b = b / 1024 | ||
| 39 | l = "MB" | ||
| 40 | if b > 1024 then | ||
| 41 | b = b / 1024 | ||
| 42 | l = "GB" -- hmmm | ||
| 43 | end | ||
| 44 | end | ||
| 45 | end | ||
| 46 | return string.format("%7.2f%2s", b, l) | ||
| 47 | end | ||
| 48 | |||
| 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)) | ||
| 57 | else | ||
| 58 | return string.format(elapsed_s, nicesize(got), | ||
| 59 | nicesize(rate), nicetime(delta)) | ||
| 60 | end | ||
| 61 | end | ||
| 62 | |||
| 63 | -- creates a new instance of a receive_cb that saves to disk | ||
| 64 | -- kind of copied from luasocket's manual callback examples | ||
| 65 | function stats(size) | ||
| 66 | local start = socket.gettime() | ||
| 67 | local last = start | ||
| 68 | local got = 0 | ||
| 69 | return function(chunk) | ||
| 70 | -- elapsed time since start | ||
| 71 | local current = socket.gettime() | ||
| 72 | if chunk then | ||
| 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)) | ||
| 78 | io.stderr:flush() | ||
| 79 | last = current | ||
| 80 | end | ||
| 81 | else | ||
| 82 | -- close up | ||
| 83 | io.stderr:write("\r", gauge(got, current - start), "\n") | ||
| 84 | end | ||
| 85 | return chunk | ||
| 86 | end | ||
| 87 | end | ||
| 88 | |||
| 89 | -- determines the size of a http file | ||
| 90 | function gethttpsize(u) | ||
| 91 | local r, c, h = http.request {method = "HEAD", url = u} | ||
| 92 | if c == 200 then | ||
| 93 | return tonumber(h["content-length"]) | ||
| 94 | end | ||
| 95 | end | ||
| 96 | |||
| 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 | ||
| 104 | end | ||
| 105 | |||
| 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) | ||
| 113 | gett.sink = save | ||
| 114 | gett.type = "i" | ||
| 115 | local ret, err = ftp.get(gett) | ||
| 116 | if err then print(err) end | ||
| 117 | end | ||
| 118 | |||
| 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"}) | ||
| 124 | return parsed.scheme | ||
| 125 | end | ||
| 126 | |||
| 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 | ||
| 134 | end | ||
| 135 | |||
| 136 | -- main program | ||
| 137 | arg = arg or {} | ||
| 138 | if #arg < 1 then | ||
| 139 | io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n") | ||
| 140 | os.exit(1) | ||
| 141 | else get(arg[1], arg[2]) end | ||
