Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Checks: >
bugprone-*,
-bugprone-easily-swappable-parameters,
clang-analyzer-*,
-clang-analyzer-optin.cplusplus.VirtualCall,
clang-diagnostic-*,
cppcore-guidelines-*,
google-*,
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.45.0 - 2025-12-09

### Enhancements
- Added download retry, resumption, and checksum verification to
`Historical::BatchDownload`
- Added new venue, dataset, and publisher for Cboe Futures Exchange (`XCBF.PITCH`)
- Upgraded default `httplib` version to 0.28.0

## 0.44.0 - 2025-11-18

### Enhancements
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24..4.0)

project(
databento
VERSION 0.44.0
VERSION 0.45.0
LANGUAGES CXX
DESCRIPTION "Official Databento client library"
)
Expand Down Expand Up @@ -178,7 +178,7 @@ if(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_HTTPLIB)
find_package(httplib REQUIRED)
endif()
else()
set(httplib_version 0.20.0)
set(httplib_version 0.28.0)
FetchContent_Declare(
httplib
URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v${httplib_version}.tar.gz
Expand Down
2 changes: 2 additions & 0 deletions cmake/SourcesAndHeaders.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(headers
include/databento/detail/json_helpers.hpp
include/databento/detail/scoped_fd.hpp
include/databento/detail/scoped_thread.hpp
include/databento/detail/sha256_hasher.hpp
include/databento/detail/tcp_client.hpp
include/databento/detail/zstd_stream.hpp
include/databento/enums.hpp
Expand Down Expand Up @@ -54,6 +55,7 @@ set(sources
src/detail/http_client.cpp
src/detail/json_helpers.cpp
src/detail/scoped_fd.cpp
src/detail/sha256_hasher.cpp
src/detail/tcp_client.cpp
src/detail/zstd_stream.cpp
src/enums.cpp
Expand Down
1 change: 1 addition & 0 deletions cmake/StandardSettings.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Project settings
#

option(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_DATE "Use an external date library" OFF)
option(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_JSON "Use an external JSON library" OFF)
option(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_HTTPLIB "Use an external httplib library" OFF)
option(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_GTEST "Use an external google test (gtest) library" ON)
Expand Down
2 changes: 1 addition & 1 deletion include/databento/detail/http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class HttpClient {

nlohmann::json GetJson(const std::string& path, const httplib::Params& params);
nlohmann::json PostJson(const std::string& path, const httplib::Params& form_params);
void GetRawStream(const std::string& path, const httplib::Params& params,
void GetRawStream(const std::string& path, const httplib::Headers& headers,
const httplib::ContentReceiver& callback);
void PostRawStream(const std::string& path, const httplib::Params& form_params,
const httplib::ContentReceiver& callback);
Expand Down
26 changes: 26 additions & 0 deletions include/databento/detail/sha256_hasher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <cstddef> // byte, size_t
#include <memory> // unique_ptr
#include <string>
#include <string_view>

// Forward declaration
struct evp_md_ctx_st;
using EVP_MD_CTX = evp_md_ctx_st;

namespace databento::detail {
// One-off hash
std::string Sha256Hash(std::string_view data);

class Sha256Hasher {
public:
Sha256Hasher();

void Update(const std::byte* buffer, std::size_t length);
std::string Finalize();

private:
std::unique_ptr<::EVP_MD_CTX, void (*)(::EVP_MD_CTX*)> ctx_;
};
} // namespace databento::detail
1 change: 1 addition & 0 deletions include/databento/file_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class InFileStream : public IReadable {
class OutFileStream : public IWritable {
public:
explicit OutFileStream(const std::filesystem::path& file_path);
OutFileStream(const std::filesystem::path& file_path, std::ios_base::openmode mode);

void WriteAll(const std::byte* buffer, std::size_t length) override;

Expand Down
4 changes: 3 additions & 1 deletion include/databento/historical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <filesystem>
#include <map> // multimap
#include <string>
#include <string_view>
#include <vector>

#include "databento/batch.hpp" // BatchJob
Expand Down Expand Up @@ -225,7 +226,8 @@ class Historical {
std::string user_agent_ext);

BatchJob BatchSubmitJob(const HttplibParams& params);
void DownloadFile(const std::string& url, const std::filesystem::path& output_path);
void DownloadFile(const std::string& url, const std::filesystem::path& output_path,
std::string_view hash, std::uint64_t exp_size);
std::vector<BatchJob> BatchListJobs(const HttplibParams& params);
std::vector<DatasetConditionDetail> MetadataGetDatasetCondition(
const HttplibParams& params);
Expand Down
6 changes: 6 additions & 0 deletions include/databento/publishers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ enum class Venue : std::uint16_t {
Xeur = 50,
// European Energy Exchange
Xeee = 51,
// Cboe Futures Exchange
Xcbf = 52,
};

// A source of data.
Expand Down Expand Up @@ -191,6 +193,8 @@ enum class Dataset : std::uint16_t {
XeurEobi = 38,
// European Energy Exchange EOBI
XeeeEobi = 39,
// Cboe Futures Exchange PITCH
XcbfPitch = 40,
};

// A specific Venue from a specific data source.
Expand Down Expand Up @@ -403,6 +407,8 @@ enum class Publisher : std::uint16_t {
XeurEobiXoff = 103,
// European Energy Exchange EOBI - Off-Market Trades
XeeeEobiXoff = 104,
// Cboe Futures Exchange
XcbfPitchXcbf = 105,
};

// Get a Publisher's Venue.
Expand Down
2 changes: 1 addition & 1 deletion pkg/PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Maintainer: Databento <support@databento.com>
_pkgname=databento-cpp
pkgname=databento-cpp-git
pkgver=0.44.0
pkgver=0.45.0
pkgrel=1
pkgdesc="Official C++ client for Databento"
arch=('any')
Expand Down
5 changes: 2 additions & 3 deletions src/detail/http_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,12 @@ nlohmann::json HttpClient::PostJson(const std::string& path,
return HttpClient::CheckAndParseResponse(path, std::move(res));
}

void HttpClient::GetRawStream(const std::string& path, const httplib::Params& params,
void HttpClient::GetRawStream(const std::string& path, const httplib::Headers& headers,
const httplib::ContentReceiver& callback) {
const std::string full_path = httplib::append_query_params(path, params);
std::string err_body{};
int err_status{};
const httplib::Result res = client_.Get(
full_path, MakeStreamResponseHandler(err_status),
path, headers, MakeStreamResponseHandler(err_status),
[&callback, &err_body, &err_status](const char* data, std::size_t length) {
// if an error response was received, read all content into
// err_body
Expand Down
40 changes: 40 additions & 0 deletions src/detail/sha256_hasher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "databento/detail/sha256_hasher.hpp"

#include <openssl/evp.h>

#include <ios> // hex, setw, setfill
#include <sstream>

#include "databento/exceptions.hpp"

std::string databento::detail::Sha256Hash(std::string_view data) {
Sha256Hasher hasher{};
hasher.Update(reinterpret_cast<const std::byte*>(data.data()), data.length());
return hasher.Finalize();
}

using databento::detail::Sha256Hasher;

Sha256Hasher::Sha256Hasher() : ctx_{::EVP_MD_CTX_new(), &::EVP_MD_CTX_free} {
::EVP_DigestInit_ex(ctx_.get(), ::EVP_sha256(), NULL);
}

void Sha256Hasher::Update(const std::byte* buffer, std::size_t length) {
if (!::EVP_DigestUpdate(ctx_.get(), buffer, length)) {
throw databento::Exception{"Failed to update SHA256 digest"};
}
}

std::string Sha256Hasher::Finalize() {
std::array<unsigned char, EVP_MAX_MD_SIZE> hash{};
unsigned int hash_length = 0;
if (!::EVP_DigestFinal_ex(ctx_.get(), hash.data(), &hash_length)) {
throw databento::Exception{"Failed to finalize SHA256 digest"};
}

std::ostringstream hash_hex_stream;
for (size_t i = 0; i < hash_length; ++i) {
hash_hex_stream << std::hex << std::setw(2) << std::setfill('0') << +hash[i];
}
return hash_hex_stream.str();
}
13 changes: 9 additions & 4 deletions src/file_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ InFileStream::InFileStream(const std::filesystem::path& file_path)
: stream_{file_path, std::ios::binary} {
if (stream_.fail()) {
throw InvalidArgumentError{"InFileStream", "file_path",
"Non-existent or invalid file at " + file_path.string()};
"Non-existent or invalid file: " + file_path.string()};
}
}

Expand All @@ -33,10 +33,15 @@ std::size_t InFileStream::ReadSome(std::byte* buffer, std::size_t max_length) {
using databento::OutFileStream;

OutFileStream::OutFileStream(const std::filesystem::path& file_path)
: stream_{file_path, std::ios::binary} {
: OutFileStream{file_path, std::ios::binary} {}

OutFileStream::OutFileStream(const std::filesystem::path& file_path,
std::ios_base::openmode mode)
: stream_{file_path, mode} {
if (stream_.fail()) {
throw InvalidArgumentError{"OutFileStream", "file_path",
"Non-existent or invalid file"};
throw InvalidArgumentError{
"OutFileStream", "file_path",
"Can't open file for writing at path: " + file_path.string()};
}
}

Expand Down
Loading
Loading