Class: Scanii::Client
- Inherits:
-
Object
- Object
- Scanii::Client
- Defined in:
- lib/scanii/client.rb
Overview
Synchronous client for the Scanii REST API v2.2.
Construct with either key: + secret: (HTTP Basic Auth) or token: (auth-token authentication). Mixing the two raises ArgumentError.
Per SDK Principle 3 the client is integration-only: it does not retry, batch, or paginate. Each public method maps to exactly one HTTP request.
Constant Summary collapse
- DEFAULT_ENDPOINT =
"https://api.scanii.com".freeze
- DEFAULT_TIMEOUT =
60- API_VERSION_PATH =
"/v2.2".freeze
- USER_AGENT =
"scanii-ruby/#{Scanii::VERSION}".freeze
Instance Attribute Summary collapse
-
#endpoint ⇒ Object
readonly
Returns the value of attribute endpoint.
-
#timeout ⇒ Object
readonly
Returns the value of attribute timeout.
-
#user_agent ⇒ Object
readonly
Returns the value of attribute user_agent.
Instance Method Summary collapse
-
#create_auth_token(timeout_seconds) ⇒ Scanii::AuthToken
Mint a short-lived auth token.
-
#delete_auth_token(id) ⇒ Boolean
Revoke an auth token.
-
#fetch(url, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Ask Scanii to download a remote URL and scan it asynchronously.
-
#initialize(key: nil, secret: nil, token: nil, endpoint: DEFAULT_ENDPOINT, timeout: DEFAULT_TIMEOUT, user_agent: nil) ⇒ Client
constructor
A new instance of Client.
-
#ping ⇒ Boolean
Verify that the configured credentials reach the API.
-
#process(io, filename:, content_type: nil, metadata: nil, callback: nil) ⇒ Scanii::ProcessingResult
Submit an IO-like object for synchronous scanning.
-
#process_async(io, filename:, content_type: nil, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Submit an IO-like object for server-side asynchronous scanning.
-
#process_async_file(file_path, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Submit a file path for server-side asynchronous scanning.
-
#process_file(file_path, metadata: nil, callback: nil) ⇒ Scanii::ProcessingResult
Submit a file path for synchronous scanning.
-
#process_from_url(location, callback: nil, metadata: nil) ⇒ Scanii::ProcessingResult
Submit a remote URL for synchronous scanning.
-
#retrieve(id) ⇒ Scanii::ProcessingResult
Retrieve a previously submitted scan result by id.
-
#retrieve_auth_token(id) ⇒ Scanii::AuthToken
Inspect a previously created auth token.
-
#retrieve_trace(id) ⇒ Scanii::TraceResult?
Retrieve the processing event trace for a previously submitted scan.
Constructor Details
#initialize(key: nil, secret: nil, token: nil, endpoint: DEFAULT_ENDPOINT, timeout: DEFAULT_TIMEOUT, user_agent: nil) ⇒ Client
Returns a new instance of Client.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/scanii/client.rb', line 44 def initialize(key: nil, secret: nil, token: nil, endpoint: DEFAULT_ENDPOINT, timeout: DEFAULT_TIMEOUT, user_agent: nil) if endpoint == DEFAULT_ENDPOINT warn "[scanii] DEPRECATION: No explicit endpoint set; defaulting to " \ "#{DEFAULT_ENDPOINT} (AUTO routing). This does not guarantee regional data " \ "placement. Pass an explicit regional endpoint (e.g. Scanii::Target::US1) " \ "for data residency compliance. The AUTO default will be removed in a " \ "future major version." end @auth_header = build_auth_header(key, secret, token) @endpoint = endpoint.to_s.sub(%r{/+\z}, "") raise ArgumentError, "endpoint must not be empty" if @endpoint.empty? @base_uri = URI.parse("#{@endpoint}#{API_VERSION_PATH}") raise ArgumentError, "endpoint must be http(s)" unless %w[http https].include?(@base_uri.scheme) @timeout = Integer(timeout) @user_agent = user_agent && !user_agent.empty? ? "#{user_agent} #{USER_AGENT}" : USER_AGENT end |
Instance Attribute Details
#endpoint ⇒ Object (readonly)
Returns the value of attribute endpoint.
29 30 31 |
# File 'lib/scanii/client.rb', line 29 def endpoint @endpoint end |
#timeout ⇒ Object (readonly)
Returns the value of attribute timeout.
29 30 31 |
# File 'lib/scanii/client.rb', line 29 def timeout @timeout end |
#user_agent ⇒ Object (readonly)
Returns the value of attribute user_agent.
29 30 31 |
# File 'lib/scanii/client.rb', line 29 def user_agent @user_agent end |
Instance Method Details
#create_auth_token(timeout_seconds) ⇒ Scanii::AuthToken
Mint a short-lived auth token. timeout_seconds must be positive.
280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/scanii/client.rb', line 280 def create_auth_token(timeout_seconds) ts = Integer(timeout_seconds) raise ArgumentError, "timeout_seconds must be positive" if ts <= 0 status, resp_body, headers = post( "/auth/tokens", body: URI.encode_www_form("timeout" => ts), content_type: "application/x-www-form-urlencoded" ) raise_for_status(status, resp_body, headers) unless [200, 201].include?(status) AuthToken.from_response(resp_body, headers) end |
#delete_auth_token(id) ⇒ Boolean
Revoke an auth token.
309 310 311 312 313 314 315 |
# File 'lib/scanii/client.rb', line 309 def delete_auth_token(id) raise ArgumentError, "id must not be empty" if id.nil? || id.empty? status, resp_body, headers = request("DELETE", "/auth/tokens/#{url_encode(id)}") raise_for_status(status, resp_body, headers) unless status == 204 true end |
#fetch(url, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Ask Scanii to download a remote URL and scan it asynchronously.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/scanii/client.rb', line 173 def fetch(url, metadata: nil, callback: nil) raise ArgumentError, "url must not be empty" if url.nil? || url.empty? form = { "location" => url } form["callback"] = callback if callback && !callback.empty? ( || {}).each { |k, v| form["metadata[#{k}]"] = v.to_s } status, resp_body, headers = post( "/files/fetch", body: URI.encode_www_form(form), content_type: "application/x-www-form-urlencoded" ) raise_for_status(status, resp_body, headers) unless status == 202 PendingResult.from_response(resp_body, headers) end |
#ping ⇒ Boolean
Verify that the configured credentials reach the API.
269 270 271 272 273 274 |
# File 'lib/scanii/client.rb', line 269 def ping status, resp_body, headers = request("GET", "/ping") return true if status == 200 raise_for_status(status, resp_body, headers) end |
#process(io, filename:, content_type: nil, metadata: nil, callback: nil) ⇒ Scanii::ProcessingResult
Submit an IO-like object for synchronous scanning.
io is duck-typed: anything responding to read(n) returning a String. Both File (opened with File.open(path, “rb”)) and StringIO work. The body is streamed to the socket; file content is never fully buffered.
Passing a String path is deprecated — use #process_file instead.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/scanii/client.rb', line 81 def process(first_arg, filename: nil, content_type: nil, metadata: nil, callback: nil) if first_arg.is_a?(String) # @deprecated Use {#process_file} instead. Will be removed in a future major version. warn "[DEPRECATION] `Scanii::Client#process(path)` is deprecated; " \ "use `process_file(path)` instead. Will be removed in a future major version." return process_file(first_arg, metadata: , callback: callback) end raise ArgumentError, "io must respond to read" unless first_arg.respond_to?(:read) raise ArgumentError, "filename: is required" if filename.nil? || filename.to_s.empty? fields = build_text_fields(, callback) stream, ct, length = Multipart.stream_encode(fields, first_arg, filename.to_s, content_type) status, resp_body, headers = post("/files", body_stream: stream, content_type: ct, content_length: length) raise_for_status(status, resp_body, headers) unless status == 201 ProcessingResult.from_response(resp_body, headers) end |
#process_async(io, filename:, content_type: nil, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Submit an IO-like object for server-side asynchronous scanning.
Returns a pending id; the final result is delivered to callback (when supplied) or fetched via #retrieve.
Passing a String path is deprecated — use #process_async_file instead.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/scanii/client.rb', line 133 def process_async(first_arg, filename: nil, content_type: nil, metadata: nil, callback: nil) if first_arg.is_a?(String) # @deprecated Use {#process_async_file} instead. Will be removed in a future major version. warn "[DEPRECATION] `Scanii::Client#process_async(path)` is deprecated; " \ "use `process_async_file(path)` instead. Will be removed in a future major version." return process_async_file(first_arg, metadata: , callback: callback) end raise ArgumentError, "io must respond to read" unless first_arg.respond_to?(:read) raise ArgumentError, "filename: is required" if filename.nil? || filename.to_s.empty? fields = build_text_fields(, callback) stream, ct, length = Multipart.stream_encode(fields, first_arg, filename.to_s, content_type) status, resp_body, headers = post("/files/async", body_stream: stream, content_type: ct, content_length: length) raise_for_status(status, resp_body, headers) unless status == 202 PendingResult.from_response(resp_body, headers) end |
#process_async_file(file_path, metadata: nil, callback: nil) ⇒ Scanii::PendingResult
Submit a file path for server-side asynchronous scanning.
Opens the file in binary mode and delegates to #process_async.
161 162 163 164 165 166 167 |
# File 'lib/scanii/client.rb', line 161 def process_async_file(file_path, metadata: nil, callback: nil) assert_readable(file_path) File.open(file_path.to_s, "rb") do |f| process_async(f, filename: File.basename(file_path.to_s), metadata: , callback: callback) end end |
#process_file(file_path, metadata: nil, callback: nil) ⇒ Scanii::ProcessingResult
Submit a file path for synchronous scanning.
Opens the file in binary mode, streams it to Scanii, and closes it. Delegates to #process with filename set to the basename.
110 111 112 113 114 115 |
# File 'lib/scanii/client.rb', line 110 def process_file(file_path, metadata: nil, callback: nil) assert_readable(file_path) File.open(file_path.to_s, "rb") do |f| process(f, filename: File.basename(file_path.to_s), metadata: , callback: callback) end end |
#process_from_url(location, callback: nil, metadata: nil) ⇒ Scanii::ProcessingResult
Submit a remote URL for synchronous scanning.
Sends the URL as a location field in a multipart/form-data POST to /files. The Scanii server fetches and scans the URL synchronously and returns a ProcessingResult. This is distinct from #fetch, which submits to /files/fetch for asynchronous server-side fetching.
location must be a String URL. This matches the existing #fetch String-URL convention and the Java reference (processFromUrl(String)).
This is a v2.2 preview surface; the API shape may shift before it is marked stable.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/scanii/client.rb', line 239 def process_from_url(location, callback: nil, metadata: nil) raise ArgumentError, "location must not be empty" if location.nil? || location.to_s.empty? fields = build_text_fields(, callback) fields["location"] = location.to_s boundary = Multipart.make_boundary body = String.new(encoding: Encoding::BINARY) fields.each do |name, value| body << "--#{boundary}\r\n".b body << "Content-Disposition: form-data; name=\"#{name}\"\r\n".b body << "Content-Type: text/plain; charset=UTF-8\r\n\r\n".b body << value.to_s.b body << "\r\n".b end body << "--#{boundary}--\r\n".b status, resp_body, headers = post( "/files", body: body, content_type: Multipart.make_content_type(boundary) ) raise_for_status(status, resp_body, headers) unless status == 201 ProcessingResult.from_response(resp_body, headers) end |
#retrieve(id) ⇒ Scanii::ProcessingResult
Retrieve a previously submitted scan result by id.
193 194 195 196 197 198 199 |
# File 'lib/scanii/client.rb', line 193 def retrieve(id) raise ArgumentError, "id must not be empty" if id.nil? || id.empty? status, resp_body, headers = request("GET", "/files/#{url_encode(id)}") raise_for_status(status, resp_body, headers) unless status == 200 ProcessingResult.from_response(resp_body, headers) end |
#retrieve_auth_token(id) ⇒ Scanii::AuthToken
Inspect a previously created auth token.
297 298 299 300 301 302 303 |
# File 'lib/scanii/client.rb', line 297 def retrieve_auth_token(id) raise ArgumentError, "id must not be empty" if id.nil? || id.empty? status, resp_body, headers = request("GET", "/auth/tokens/#{url_encode(id)}") raise_for_status(status, resp_body, headers) unless status == 200 AuthToken.from_response(resp_body, headers) end |
#retrieve_trace(id) ⇒ Scanii::TraceResult?
Retrieve the processing event trace for a previously submitted scan.
Returns nil when no trace exists for the given id (HTTP 404).
This is a v2.2 preview surface; the API shape may shift before it is marked stable.
211 212 213 214 215 216 217 218 219 |
# File 'lib/scanii/client.rb', line 211 def retrieve_trace(id) raise ArgumentError, "id must not be empty" if id.nil? || id.empty? status, resp_body, headers = request("GET", "/files/#{url_encode(id)}/trace") return nil if status == 404 raise_for_status(status, resp_body, headers) unless status == 200 TraceResult.from_response(resp_body, headers) end |