-
Notifications
You must be signed in to change notification settings - Fork 20
/
dpd_cart_client.ex
61 lines (51 loc) · 2.33 KB
/
dpd_cart_client.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
defmodule Sipper.DpdCartClient do
@subdomain "elixirsips"
@feed_url "https://#{@subdomain}.dpdcart.com/feed"
@feed_timeout_ms 15_000 # The default 5000 will time out sometimes.
@file_timeout_ms 1000 * 60 * 60 * 3
def get_feed!({_user, _pw} = auth) do
response = HTTPotion.get(@feed_url, basic_auth: auth, timeout: @feed_timeout_ms)
%HTTPotion.Response{body: body, status_code: 200} = response
body
end
def get_file({id, name}, {_user, _pw} = auth, callback: cb) do
url = file_url(id, name)
HTTPotion.get(url, basic_auth: auth, timeout: @file_timeout_ms, stream_to: self)
# The files in episode 89 (and maybe others) redirect to S3.
# We'll optimistically assume all redirects are external with no need for auth.
cb_plus_redirect_handling = fn
{:redirect, new_url} -> get_external_file(new_url, cb)
other -> cb.(other)
end
receive_file(total_bytes: :unknown, data: "", callback: cb_plus_redirect_handling)
end
defp get_external_file(url, callback) do
HTTPotion.get(url, timeout: @file_timeout_ms, stream_to: self)
receive_file(total_bytes: :unknown, data: "", callback: callback)
end
defp receive_file(total_bytes: total_bytes, data: data, callback: cb) do
receive do
%HTTPotion.AsyncHeaders{status_code: 302, headers: h} ->
# A HTTP redirect.
# We'll get an empty chunk and an "end", so let's get those out of the way.
receive do; %HTTPotion.AsyncChunk{chunk: ""} -> nil; end
receive do; %HTTPotion.AsyncEnd{} -> nil; end
# Inform about the redirect so another request can be made.
cb.({:redirect, h[:Location]})
%HTTPotion.AsyncHeaders{status_code: 200, headers: h} ->
{total_bytes, _} = h[:"Content-Length"] |> Integer.parse
cb.({:file_progress, 0, total_bytes})
receive_file(total_bytes: total_bytes, data: data, callback: cb)
%HTTPotion.AsyncChunk{chunk: new_data} ->
accumulated_data = data <> new_data
accumulated_bytes = byte_size(accumulated_data)
cb.({:file_progress, accumulated_bytes, total_bytes})
receive_file(total_bytes: total_bytes, data: accumulated_data, callback: cb)
%HTTPotion.AsyncEnd{} ->
cb.({:file_done, data})
end
end
defp file_url(id, name) do
"https://#{@subdomain}.dpdcart.com/feed/download/#{id}/#{name}"
end
end