runapi-core 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/runapi/core/files.rb +24 -13
- data/lib/runapi/core/http_client.rb +24 -0
- data/lib/runapi/core/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66cc8586f64564c496bb7c4008f5cbaf0a30d1b1528cea036db368a3f9bdc307
|
|
4
|
+
data.tar.gz: 43cb58a1644f09209e1da2e14c6128cf1a334fa245d0d285499b5e4e892a411f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 957bcd8962bcde64fd16281a2b21876ba93b505546277d5e61a0bd898cb9b1ec6369b34ffcbeb0b79df42e5a56fbe1ff1dc8531872f8cd29b49375c5c46a37a7
|
|
7
|
+
data.tar.gz: 43261e4cdcaef883977a9efc32ed752b9000b05602671cabc7471b000a2f01065666746ae09c4be7eeceae622cb7162f84562170eb22214b11b4b1c483e43b0d
|
data/lib/runapi/core/files.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
3
5
|
module RunApi
|
|
4
6
|
module Core
|
|
5
7
|
class Files
|
|
6
8
|
include RunApi::Core::ResourceHelpers
|
|
7
9
|
|
|
8
10
|
ENDPOINT = "/api/v1/files"
|
|
11
|
+
PREPARE_ENDPOINT = "#{ENDPOINT}/prepare"
|
|
12
|
+
CONFIRM_ENDPOINT = "#{ENDPOINT}/confirm"
|
|
9
13
|
|
|
10
14
|
class UploadResponse < RunApi::Core::BaseModel
|
|
11
15
|
required :file_name, String
|
|
@@ -25,13 +29,9 @@ module RunApi
|
|
|
25
29
|
def create(file: nil, source: nil, file_name: nil, options: nil)
|
|
26
30
|
validate_source!(file:, source:)
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
multipart_body(file, file_name:)
|
|
30
|
-
else
|
|
31
|
-
compact_params(source:, file_name:)
|
|
32
|
-
end
|
|
32
|
+
return upload_direct(file, file_name:, options:) if file
|
|
33
33
|
|
|
34
|
-
request(:post, ENDPOINT, body:, options:)
|
|
34
|
+
request(:post, ENDPOINT, body: compact_params(source:, file_name:), options:)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
private
|
|
@@ -43,15 +43,26 @@ module RunApi
|
|
|
43
43
|
raise ArgumentError, "Exactly one source is required: file or source"
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
# Local files upload straight to storage: ask for a pre-authorized target,
|
|
47
|
+
# PUT the bytes there (never through the API), then confirm. The caller still
|
|
48
|
+
# makes a single create call.
|
|
49
|
+
def upload_direct(file, file_name:, options:)
|
|
47
50
|
path = file_path(file)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
bytes = File.binread(path)
|
|
52
|
+
prepared = @http.request(
|
|
53
|
+
:post,
|
|
54
|
+
PREPARE_ENDPOINT,
|
|
55
|
+
body: compact_params(
|
|
56
|
+
filename: file_name || File.basename(path),
|
|
57
|
+
byte_size: bytes.bytesize,
|
|
58
|
+
checksum: Digest::MD5.base64digest(bytes)
|
|
59
|
+
),
|
|
60
|
+
options:
|
|
54
61
|
)
|
|
62
|
+
|
|
63
|
+
@http.upload(prepared["upload_url"], headers: prepared["headers"], body: bytes)
|
|
64
|
+
|
|
65
|
+
request(:post, CONFIRM_ENDPOINT, body: {signed_id: prepared["signed_id"]}, options:)
|
|
55
66
|
end
|
|
56
67
|
|
|
57
68
|
def file_path(file)
|
|
@@ -54,6 +54,30 @@ module RunApi
|
|
|
54
54
|
close_multipart_files(req)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# PUT bytes straight to a pre-authorized upload URL with the exact headers
|
|
58
|
+
# issued for it. Skips the base URL, auth, and retries: the URL is single-use
|
|
59
|
+
# and the body is not safe to replay.
|
|
60
|
+
def upload(url, headers:, body:)
|
|
61
|
+
uri = URI.parse(url)
|
|
62
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
63
|
+
http.use_ssl = (uri.scheme == "https")
|
|
64
|
+
http.open_timeout = @options.timeout
|
|
65
|
+
http.read_timeout = @options.timeout
|
|
66
|
+
|
|
67
|
+
req = Net::HTTP::Put.new(uri.request_uri)
|
|
68
|
+
headers.each { |key, value| req[key.to_s] = value }
|
|
69
|
+
req.body = body
|
|
70
|
+
|
|
71
|
+
response = http.start { |connection| connection.request(req) }
|
|
72
|
+
return if response.is_a?(Net::HTTPSuccess)
|
|
73
|
+
|
|
74
|
+
raise Error.from_response(response, response.body)
|
|
75
|
+
rescue ::Net::OpenTimeout, ::Net::ReadTimeout => e
|
|
76
|
+
raise TimeoutError, e.message
|
|
77
|
+
rescue ::SocketError, ::Errno::ECONNREFUSED, ::Errno::ECONNRESET => e
|
|
78
|
+
raise NetworkError, e.message
|
|
79
|
+
end
|
|
80
|
+
|
|
57
81
|
private
|
|
58
82
|
|
|
59
83
|
def build_connection
|
data/lib/runapi/core/version.rb
CHANGED