C++ APISession methods

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

HelperMeaning
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.

  • content contains the whole transferred range in memory.
  • status is 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_file waits for full transfer completion.
  • The returned filestream_data contains the whole transferred range.
  • status is final when co_await completes.
  • 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

FieldPractical check
packet.contentIn async mode, packet.content.empty() is normal for metadata-only final packets.
packet.file_sizepacket.file_size == 0 means file size is not known yet, transfer failed early, or the actual file is empty.
packet.statuspacket.status == blaze::status::none means transfer is still in progress.
packet.server_file_checksumEmpty until the server sends final checksum metadata.

Behavior notes

  • Call transfer_file only after successful connect, initialize, and authorization.
  • If the session is not authorized, the server returns blaze::status::not_authorized and no stream starts.
  • file_size is 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_checksum is the full-file checksum from the server, not the checksum of the transferred tail.
  • blaze::status::file_checksum_mismatch is produced by the client library after checksum validation. The server does not send this status directly.
  • blaze::status::file_storage_quota_exceeded and blaze::status::file_transfer_stopped can appear after a stream already started.
  • In async code, do not treat !packet.good() as an error by itself, because intermediate packets have status == 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;
}

#endif

Transfer-file statuses

ValueStatusOriginReturned when
0noneServer streamIntermediate async chunk.
1okServer finalTransfer completed successfully.
3not_authorizedServer earlySession is not authorized for file transfer.
6internal_server_errorServer early/finalServer failed before or during transfer processing.
300file_not_foundServer earlyRequested file does not exist in the current application.
302file_checksum_mismatchLibrary finalReceived bytes did not match final checksum validation.
303file_invalid_resume_offsetServer earlyresume_at.bytes_offset is greater than or equal to file size.
304file_storage_quota_exceededServer finalTransfer exceeded the allowed file-transfer quota for the current session plan.
306file_transfer_stoppedServer finalTransfer 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 codeMeaningWhen it can happen
4200not_initializedtransfer_file was called before a successful initialize.
4201rate_limitedSession or IP rate limiting closed the websocket around this operation.

On this page