module lunch.http; import std.stdio; import std.file; import std.traits; import std.string; import std.net.curl : c_get = get, c_post = post, c_put = put, HTTP, CurlException, AutoProtocol; import core.thread; import lunch.logger; private ReturnType!fun _retry(alias fun)(Parameters!fun args) { CurlException last_ex; for (int n = 0; n < 10; n++) { try return fun(args); catch (CurlException ex) last_ex = ex; Thread.sleep(dur!"msecs"(500)); } throw last_ex; } private const(char)[] _sanitize(const(char)[] url) { return url.replace(" ", "%20"); } T[] get(Conn = AutoProtocol, T = char)(const(char)[] url, Conn conn = Conn()) { try { T[] res = _retry!(c_get!(Conn, T))(_sanitize(url), conn); infof("GET %s", url); return res; } catch (CurlException ex) { erroref("GET %s", ex, url); assert(0); } } T[] post(T = char, PostUnit)(const(char)[] url, const(PostUnit)[] postData, HTTP conn = HTTP()) { try { T[] res = _retry!(c_post!(T, PostUnit))(_sanitize(url), postData, conn); infof("POST %s", url); return res; } catch (CurlException ex) { erroref("POST %s", ex, url); assert(0); } } T[] put(Conn = AutoProtocol, T = char, PutUnit)(const(char)[] url, const(PutUnit)[] putData, Conn conn = Conn()) { try { T[] res = _retry!(c_put!(Conn, T, PutUnit))(_sanitize(url), putData, conn); infof("PUT %s", url); return res; } catch (CurlException ex) { erroref("PUT %s", ex, url); assert(0); } } private void _download(const(char)[] url, string file) { scope (failure) if (exists(file)) remove(file); File handle = File(file, "wb"); HTTP http = HTTP(_sanitize(url)); http.onReceive = (ubyte[] data) { handle.rawWrite(data); return data.length; }; http.perform(); } void download(const(char)[] url, string file) { try { _retry!_download(url, file); infof("DL %s", url); } catch (CurlException ex) { erroref("DL %s", cast(Exception)ex, url); assert(0); } }