Files
Jason Larabie 52b6c66fa1 Add C++ Bindings (#3544)
# Description of Changes

This adds C++ server bindings (/crate/bindings-cpp) to allow writing C++
20 modules.

- Emscripten WASM build system integration with CMake
- Macro-based code generation (SPACETIMEDB_TABLE, SPACETIMEDB_REDUCER,
etc)
- All SpacetimeDB types supported (primitives, Timestamp, Identity,
Uuid, etc)
- Product types via SPACETIMEDB_STRUCT
- Sum types via SPACETIMEDB_ENUM
- Constraints marked with FIELD* macros

# API and ABI breaking changes

None

# Expected complexity level and risk

2 - Doesn't heavily impact any other areas but is complex macro C++
structure to support a similar developer experience, did have a small
impact on init command

# Testing

- [x] modules/module-test-cpp - heavily tested every reducer
- [x] modules/benchmarks-cpp - tested through the standalone (~6x faster
than C#, ~6x slower than Rust)
- [x] modules/sdk-test-cpp
- [x] modules/sdk-test-procedure-cpp
- [x] modules/sdk-test-view-cpp  
- [x] Wrote several test modules myself
- [x] Quickstart smoketest [Currently in progress]
- [ ] Write Blackholio C++ server module

---------

Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-02-07 04:26:45 +00:00

84 lines
3.1 KiB
C++

#ifndef SPACETIMEDB_HTTP_CLIENT_IMPL_H
#define SPACETIMEDB_HTTP_CLIENT_IMPL_H
#pragma once
#include "spacetimedb/http_wire.h"
#include "spacetimedb/http_convert.h"
#include "spacetimedb/abi/abi.h"
#include "spacetimedb/bsatn/bsatn.h"
#include "spacetimedb/internal/Module.h"
namespace SpacetimeDB {
inline Outcome<HttpResponse> HttpClient::SendImpl(const HttpRequest& request) {
// Convert user-facing request to wire format
wire::HttpRequest wire_request = convert::to_wire(request);
// Serialize wire request to BSATN
bsatn::Writer writer;
bsatn::serialize(writer, wire_request);
std::vector<uint8_t> request_bytes = writer.take_buffer();
// Prepare body bytes
const std::vector<uint8_t>& body_bytes = request.body.bytes;
// Call host function
// Note: For empty body, we need to pass a valid pointer, not null
const uint8_t* body_ptr = body_bytes.empty() ? reinterpret_cast<const uint8_t*>("") : body_bytes.data();
BytesSource out[2] = {BytesSource{0}, BytesSource{0}};
Status status = procedure_http_request(
request_bytes.data(), request_bytes.size(),
body_ptr, body_bytes.size(),
out
);
// Check for errors
if (status.inner != 0) {
// HTTP_ERROR (21) means the HTTP call failed - error message is in out[0]
if (status.inner == 21) {
// Read error message from out[0]
std::vector<uint8_t> error_bytes = Internal::ConsumeBytes(out[0]);
LOG_INFO("HTTP: Error bytes: " + std::to_string(error_bytes.size()));
// Decode BSATN string
bsatn::Reader reader(error_bytes.data(), error_bytes.size());
std::string error_message = bsatn::deserialize<std::string>(reader);
LOG_INFO("HTTP: Error message: " + error_message);
return Err<HttpResponse>(std::move(error_message));
}
// Other errors (WOULD_BLOCK_TRANSACTION, etc.)
if (status.inner == 17) {
return Err<HttpResponse>("HTTP requests are blocked inside transactions. Call HTTP before with_tx() or try_with_tx().");
}
LOG_INFO("HTTP: Unknown error code: " + std::to_string(status.inner));
return Err<HttpResponse>("HTTP request failed with status code: " + std::to_string(status.inner));
}
// Success - decode response from out[0] and body from out[1]
std::vector<uint8_t> response_bytes = Internal::ConsumeBytes(out[0]);
std::vector<uint8_t> response_body_bytes = Internal::ConsumeBytes(out[1]);
// Decode wire response
bsatn::Reader response_reader(response_bytes.data(), response_bytes.size());
wire::HttpResponse wire_response = bsatn::deserialize<wire::HttpResponse>(response_reader);
// Convert wire response to user-facing type
HttpResponse response = convert::from_wire(wire_response);
// Set the body
response.body = HttpBody{std::move(response_body_bytes)};
return Ok(std::move(response));
}
} // namespace SpacetimeDB
#endif // SPACETIMEDB_HTTP_CLIENT_IMPL_H