transfer_file
Transfers file content from the server, either as one aggregated result or as a chunk stream.
transfer_file is the most stateful method in blaze::session.
It supports full in-memory downloads, progressive chunk-by-chunk streaming, and
resumed transfers from a byte offset.
Function variants
blaze::filestream_data transfer_file(std::string filename, blaze::resume_at from_where = blaze::resume_at{0});
blaze::filestream_data transfer_file(std::string filename, blaze::resume_at from_where, std::error_code& ec) noexcept;
void async_transfer_file(std::string filename, std::function<void(std::error_code, blaze::filestream_data)> callback);
void async_transfer_file(
std::string filename,
blaze::resume_at from_where,
std::function<void(std::error_code, blaze::filestream_data)> callback
);
blaze::coro::awaitable_result<blaze::filestream_data> co_transfer_file(
std::string filename,
blaze::resume_at from_where = blaze::resume_at{0}
);Status vs error
filestream_data.status is the API result. std::error_code and
std::system_error are used for transport/runtime failures only.
Parameters
struct resume_at {
std::uint64_t bytes_offset;
};Prop
Type
Result
struct filestream_data {
std::vector<uint8_t> content;
size_t file_size{0};
blaze::status status{};
std::string server_file_checksum;
bool good() const noexcept;
bool transfer_finished() const noexcept;
bool bad_checksum() const noexcept;
filestream_data& operator+=(const filestream_data& other);
};Prop
Type
Helper methods
| Helper | Meaning |
|---|---|
result.good() | result.status == blaze::status::ok |
result.transfer_finished() | result.status != blaze::status::none |
result.bad_checksum() | result.status == blaze::status::file_checksum_mismatch |
Useful in async flows
filestream_data::operator+= is designed for chunk accumulation.
It appends content, keeps the first non-zero file_size, keeps the first
non-empty server_file_checksum, and preserves the final non-none status.
How each API style behaves
The synchronous overload blocks until the transfer is finished or a transport/runtime error occurs.
contentcontains the whole transferred range in memory.statusis always final when the call returns.- This is the simplest option when you want one final byte vector.
- It is not a streaming API and is not ideal for very large files.
The asynchronous overload is a real stream.
- The callback can be invoked many times.
- Each callback receives only the current chunk/event payload.
- Intermediate callbacks have
status == blaze::status::none. - The final callback has
transfer_finished() == true. - If you need the whole file, accumulate chunks yourself.
The coroutine overload behaves like the synchronous overload from the caller's point of view.
co_transfer_filewaits for full transfer completion.- The returned
filestream_datacontains the whole transferred range. statusis final whenco_awaitcompletes.- This is convenient for coroutine-based code that still wants a full in-memory result.
Transfer lifecycle
Start the transfer after successful connect, initialize, and
authorization.
Receive stream events. The first event usually carries file_size.
Accumulate content if you need the whole transferred range.
Stop when transfer_finished() becomes true.
Check final status. On success it is ok. On integrity failure the
library returns file_checksum_mismatch.
Checksum behavior
The library validates streamed data automatically. You do not need to compute SHA-256 manually when using this API.
When transfer starts from byte 0, the library hashes all received bytes
and compares them with the final checksum metadata.
On mismatch, final status becomes
blaze::status::file_checksum_mismatch.
When transfer starts from a non-zero resume_at.bytes_offset, the library
validates the actually streamed tail range, not your already existing local
prefix.
server_file_checksum still refers to the full file on the server.
Checking returned fields
| Field | Practical check |
|---|---|
packet.content | In async mode, packet.content.empty() is normal for metadata-only final packets. |
packet.file_size | packet.file_size == 0 means file size is not known yet, transfer failed early, or the actual file is empty. |
packet.status | packet.status == blaze::status::none means transfer is still in progress. |
packet.server_file_checksum | Empty until the server sends final checksum metadata. |
Behavior notes
- Call
transfer_fileonly after successfulconnect,initialize, and authorization. - If the session is not authorized, the server returns
blaze::status::not_authorizedand no stream starts. file_sizeis the total server-side file size, not the size of the transferred range.- A resumed transfer returns only the requested tail bytes in
content. server_file_checksumis the full-file checksum from the server, not the checksum of the transferred tail.blaze::status::file_checksum_mismatchis produced by the client library after checksum validation. The server does not send this status directly.blaze::status::file_storage_quota_exceededandblaze::status::file_transfer_stoppedcan appear after a stream already started.- In async code, do not treat
!packet.good()as an error by itself, because intermediate packets havestatus == blaze::status::none.
Example
Compilation note
Synchronous and Asynchronous examples compile in the same form from C++14
to C++26.
#include "blazeauth/api/api.hpp"
#include <fstream>
#include <iostream>
#include <string>
#include <system_error>
#include <vector>
void print_error_code(const std::string& context, const std::error_code& ec) {
std::cout << context << ": " << ec.message() << " ("
<< ec.value() << " : " << ec.category().name() << ")\n";
}
std::string read_line(const std::string& label) {
std::string value;
std::cout << label << ": ";
std::getline(std::cin, value);
return value;
}
void print_status(const std::string& context, blaze::status status) {
std::cout << context << ": "
<< static_cast<unsigned int>(status)
<< " (" << blaze::to_string(status) << ")\n";
}
bool write_file(const std::string& path, const std::vector<std::uint8_t>& bytes) {
std::ofstream file(path, std::ios::binary);
if (!file) {
return false;
}
if (!bytes.empty()) {
file.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
}
return static_cast<bool>(file);
}
int main() {
const std::string websocket_api_key = read_line("Websocket API key");
const std::string client_id = read_line("Client ID");
const std::string license_key = read_line("License");
const std::string filename = read_line("Filename");
const std::string output_path = read_line("Output path");
blaze::session session;
try {
const blaze::api_server server = session.connect();
std::cout << "Connected to server location: " << server.location << '\n';
const blaze::application app = session.initialize(websocket_api_key, client_id);
if (!app.good()) {
print_status("Initialize returned status", app.status);
return 1;
}
const blaze::license auth_result = session.authorize(license_key);
if (!auth_result.good()) {
print_status("Authorize returned status", auth_result.status);
return 1;
}
const blaze::filestream_data file = session.transfer_file(filename);
if (!file.good()) {
print_status("Transfer-file returned status", file.status);
return 1;
}
if (!write_file(output_path, file.content)) {
std::cout << "Failed to write output file\n";
return 1;
}
std::cout << "Transferred bytes: " << file.content.size() << '\n';
std::cout << "Server file size: " << file.file_size << '\n';
std::cout << "Server checksum: " << file.server_file_checksum << '\n';
session.shutdown();
} catch (const std::system_error& e) {
print_error_code("Transfer-file failed", e.code());
return 1;
}
return 0;
}#include "blazeauth/api/api.hpp"
#include <fstream>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
void print_error_code(const std::string& context, const std::error_code& ec) {
std::cout << context << ": " << ec.message() << " ("
<< ec.value() << " : " << ec.category().name() << ")\n";
}
std::string read_line(const std::string& label) {
std::string value;
std::cout << label << ": ";
std::getline(std::cin, value);
return value;
}
void print_status(const std::string& context, blaze::status status) {
std::cout << context << ": "
<< static_cast<unsigned int>(status)
<< " (" << blaze::to_string(status) << ")\n";
}
bool write_file(const std::string& path, const std::vector<std::uint8_t>& bytes) {
std::ofstream file(path, std::ios::binary);
if (!file) {
return false;
}
if (!bytes.empty()) {
file.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
}
return static_cast<bool>(file);
}
struct download_state {
std::vector<std::uint8_t> bytes;
std::size_t file_size{0};
std::string checksum;
};
int main() {
const std::string websocket_api_key = read_line("Websocket API key");
const std::string client_id = read_line("Client ID");
const std::string license_key = read_line("License");
const std::string filename = read_line("Filename");
const std::string output_path = read_line("Output path");
blaze::session session;
std::promise<int> completion;
std::future<int> result = completion.get_future();
auto state = std::make_shared<download_state>();
session.async_connect(
[&session, &completion, state, websocket_api_key, client_id, license_key, filename, output_path](std::error_code connect_ec, blaze::api_server server) {
if (connect_ec) {
print_error_code("Connect failed", connect_ec);
completion.set_value(1);
return;
}
std::cout << "Connected to server location: " << server.location << '\n';
session.async_initialize(websocket_api_key, client_id,
[&session, &completion, state, license_key, filename, output_path](std::error_code init_ec, blaze::application app) {
if (init_ec) {
print_error_code("Initialize failed", init_ec);
completion.set_value(1);
return;
}
if (!app.good()) {
print_status("Initialize returned status", app.status);
completion.set_value(1);
return;
}
session.async_authorize(license_key,
[&session, &completion, state, filename, output_path](std::error_code auth_ec, blaze::license auth_result) {
if (auth_ec) {
print_error_code("Authorize failed", auth_ec);
completion.set_value(1);
return;
}
if (!auth_result.good()) {
print_status("Authorize returned status", auth_result.status);
completion.set_value(1);
return;
}
session.async_transfer_file(
filename,
[&session, &completion, state, output_path](std::error_code transfer_ec, blaze::filestream_data packet) {
if (transfer_ec) {
print_error_code("Transfer-file failed", transfer_ec);
completion.set_value(1);
return;
}
if (packet.file_size != 0 && state->file_size == 0) {
state->file_size = packet.file_size;
state->bytes.reserve(packet.file_size);
}
if (!packet.content.empty()) {
state->bytes.insert(state->bytes.end(), packet.content.begin(), packet.content.end());
}
if (!packet.transfer_finished()) {
return;
}
if (!packet.server_file_checksum.empty()) {
state->checksum = packet.server_file_checksum;
}
if (packet.bad_checksum()) {
print_status("Transfer-file returned status", packet.status);
completion.set_value(1);
return;
}
if (packet.status != blaze::status::ok) {
print_status("Transfer-file returned status", packet.status);
completion.set_value(1);
return;
}
if (!write_file(output_path, state->bytes)) {
std::cout << "Failed to write output file\n";
completion.set_value(1);
return;
}
std::cout << "Transferred bytes: " << state->bytes.size() << '\n';
std::cout << "Server file size: " << state->file_size << '\n';
std::cout << "Server checksum: " << state->checksum << '\n';
session.async_shutdown([&completion](std::error_code shutdown_ec) {
if (shutdown_ec) {
print_error_code("Shutdown failed", shutdown_ec);
completion.set_value(1);
return;
}
completion.set_value(0);
});
});
});
});
});
return result.get();
}Project must be built with C++20 support and with coroutine support available both in the language mode and in the standard library implementation for this example to compile correctly.
#include "blazeauth/api/api.hpp"
#include <fstream>
#include <future>
#include <iostream>
#include <string>
#include <system_error>
#include <vector>
void print_error_code(const std::string& context, const std::error_code& ec) {
std::cout << context << ": " << ec.message() << " ("
<< ec.value() << " : " << ec.category().name() << ")\n";
}
std::string read_line(const std::string& label) {
std::string value;
std::cout << label << ": ";
std::getline(std::cin, value);
return value;
}
void print_status(const std::string& context, blaze::status status) {
std::cout << context << ": "
<< static_cast<unsigned int>(status)
<< " (" << blaze::to_string(status) << ")\n";
}
bool write_file(const std::string& path, const std::vector<std::uint8_t>& bytes) {
std::ofstream file(path, std::ios::binary);
if (!file) {
return false;
}
if (!bytes.empty()) {
file.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
}
return static_cast<bool>(file);
}
#if BLAZEAUTH_HAS_COROUTINES
blaze::coro::task<std::error_code> run_example(
blaze::session& session,
const std::string& websocket_api_key,
const std::string& client_id,
const std::string& license_key,
const std::string& filename,
const std::string& output_path
) {
const auto [connect_ec, server] = co_await session.co_connect();
if (connect_ec) {
co_return connect_ec;
}
std::cout << "Connected to server location: " << server.location << '\n';
const auto [init_ec, app] = co_await session.co_initialize(websocket_api_key, client_id);
if (init_ec) {
co_return init_ec;
}
if (!app.good()) {
co_return blaze::make_error_code(app.status);
}
const auto [auth_ec, auth_result] = co_await session.co_authorize(license_key);
if (auth_ec) {
co_return auth_ec;
}
if (!auth_result.good()) {
co_return blaze::make_error_code(auth_result.status);
}
const auto [file_ec, file] = co_await session.co_transfer_file(filename);
if (file_ec) {
co_return file_ec;
}
if (!file.good()) {
co_return blaze::make_error_code(file.status);
}
if (!write_file(output_path, file.content)) {
co_return std::make_error_code(std::errc::io_error);
}
std::cout << "Transferred bytes: " << file.content.size() << '\n';
std::cout << "Server file size: " << file.file_size << '\n';
std::cout << "Server checksum: " << file.server_file_checksum << '\n';
const auto [shutdown_ec] = co_await session.co_shutdown();
co_return shutdown_ec;
}
int main() {
const std::string websocket_api_key = read_line("Websocket API key");
const std::string client_id = read_line("Client ID");
const std::string license_key = read_line("License");
const std::string filename = read_line("Filename");
const std::string output_path = read_line("Output path");
blaze::session session;
std::promise<std::error_code> completion;
std::future<std::error_code> result = completion.get_future();
blaze::coro::co_spawn(
[&session, &completion, websocket_api_key, client_id, license_key, filename, output_path]() -> blaze::coro::task<void> {
const std::error_code ec =
co_await run_example(session, websocket_api_key, client_id, license_key, filename, output_path);
completion.set_value(ec);
co_return;
}());
const std::error_code ec = result.get();
if (ec) {
print_error_code("Transfer-file failed", ec);
return 1;
}
return 0;
}
#else
int main() {
std::cout << "This example requires coroutine support in the Blazeauth library build.\n";
return 0;
}
#endifTransfer-file statuses
| Value | Status | Origin | Returned when |
|---|---|---|---|
0 | none | Server stream | Intermediate async chunk. |
1 | ok | Server final | Transfer completed successfully. |
3 | not_authorized | Server early | Session is not authorized for file transfer. |
6 | internal_server_error | Server early/final | Server failed before or during transfer processing. |
300 | file_not_found | Server early | Requested file does not exist in the current application. |
302 | file_checksum_mismatch | Library final | Received bytes did not match final checksum validation. |
303 | file_invalid_resume_offset | Server early | resume_at.bytes_offset is greater than or equal to file size. |
304 | file_storage_quota_exceeded | Server final | Transfer exceeded the allowed file-transfer quota for the current session plan. |
306 | file_transfer_stopped | Server final | Transfer was stopped explicitly. |
Connection-level shutdowns
Normal transfer-file results are returned in result.status or in streamed
packets. The websocket may still be closed by session-level guards:
| Close code | Meaning | When it can happen |
|---|---|---|
4200 | not_initialized | transfer_file was called before a successful initialize. |
4201 | rate_limited | Session or IP rate limiting closed the websocket around this operation. |