Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ec1e1c1
Use yerpc from my branch
Jun 12, 2026
4ae6c59
move bindings generation to build.rs
d2weber Jun 15, 2026
4349957
fixup: CMakeLists bindings with correct target dir
d2weber Jun 16, 2026
ccaedca
fixup: cmake: add missing COMMAND
d2weber Jun 16, 2026
bc1afdc
fixup: update Cargo.lock
d2weber Jun 16, 2026
bc8f2bf
Move transport to qt subdir
d2weber Jun 16, 2026
d14782b
fixup: Add env variables
d2weber Jun 16, 2026
c8fda2e
fix paths in CMakeLists.txt
d2weber Jun 16, 2026
bfc4ed5
dbg env
d2weber Jun 17, 2026
54391c4
vendor dc
d2weber Jun 17, 2026
bf11cc3
Debug env only
d2weber Jun 17, 2026
1c1097c
fixup vendor
d2weber Jun 17, 2026
9faeb1e
Revert "Debug env only"
d2weber Jun 17, 2026
f7d6d48
Revert "dbg env"
d2weber Jun 17, 2026
d085ca3
update lockfile
d2weber Jun 17, 2026
f1141b3
Edition 2018
d2weber Jun 17, 2026
479cf07
Add HOST_CC=gcc
d2weber Jun 17, 2026
911cacb
Revert "Add HOST_CC=gcc"
d2weber Jun 17, 2026
e7c4a9d
Refactor CMakeLists.txt and rename target
d2weber Jun 17, 2026
fe349bb
cmake: Fix env vars
d2weber Jun 18, 2026
772b0a6
cmake: rework, remove commands
d2weber Jun 18, 2026
ff15e02
cmake: make headers optional
d2weber Jun 18, 2026
a5a58d0
Update bindings Cargo.toml
d2weber Jun 18, 2026
ea866a1
cmake fixup
d2weber Jun 18, 2026
5451b78
cmake: simplify
d2weber Jun 18, 2026
7c8c880
Add CffiDeltaChat wrapper
d2weber Jun 18, 2026
8f30506
Use std::mutex
d2weber Jun 18, 2026
be55c15
Add root namespace
d2weber Jun 18, 2026
97675a5
update yerpc commit
d2weber Jun 18, 2026
da4de6e
cmake fixup
d2weber Jun 18, 2026
0516440
cmake fixup 2
d2weber Jun 18, 2026
c5535f0
cmake fixup 3
d2weber Jun 18, 2026
cb590eb
add nodiscard
d2weber Jun 18, 2026
a76868e
more nodiscard
d2weber Jun 18, 2026
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
60 changes: 33 additions & 27 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,51 @@ cmake_minimum_required(VERSION 3.16)
project(deltachat LANGUAGES C)
include(GNUInstallDirs)

option(WITH_JSONRPC_BINDINGS "Generate jsonrpc bindings" OFF)

find_program(CARGO cargo)

if(APPLE)
set(DYNAMIC_EXT "dylib")
set(DYNAMIC_EXT "dylib")
elseif(UNIX)
set(DYNAMIC_EXT "so")
set(DYNAMIC_EXT "so")
else()
set(DYNAMIC_EXT "dll")
set(DYNAMIC_EXT "dll")
endif()

if(DEFINED ENV{CARGO_BUILD_TARGET})
set(ARCH_DIR "$ENV{CARGO_BUILD_TARGET}")
set(CARGO_OUT_DIR "${CMAKE_BINARY_DIR}/target/$ENV{CARGO_BUILD_TARGET}/release")
else()
set(ARCH_DIR "./")
set(CARGO_OUT_DIR "${CMAKE_BINARY_DIR}/target/release")
endif()

add_custom_command(
OUTPUT
"${CMAKE_BINARY_DIR}/target/release/libdeltachat.a"
"${CMAKE_BINARY_DIR}/target/release/libdeltachat.${DYNAMIC_EXT}"
"${CMAKE_BINARY_DIR}/target/release/pkgconfig/deltachat.pc"
COMMAND
PREFIX=${CMAKE_INSTALL_PREFIX}
LIBDIR=${CMAKE_INSTALL_FULL_LIBDIR}
INCLUDEDIR=${CMAKE_INSTALL_FULL_INCLUDEDIR}
${CARGO} build --target-dir=${CMAKE_BINARY_DIR}/target --release
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/deltachat-ffi
)
if(WITH_JSONRPC_BINDINGS)
set(JSONRPC_ARGS --package deltachat-jsonrpc-bindings)
endif()

add_custom_target(
lib_deltachat
ALL
DEPENDS
"${CMAKE_BINARY_DIR}/target/release/libdeltachat.a"
"${CMAKE_BINARY_DIR}/target/release/libdeltachat.${DYNAMIC_EXT}"
"${CMAKE_BINARY_DIR}/target/release/pkgconfig/deltachat.pc"
lib_deltachat
ALL
COMMAND
${CMAKE_COMMAND} -E env
CARGO_TARGET_DIR="${CMAKE_BINARY_DIR}/target"
PREFIX="${CMAKE_INSTALL_PREFIX}"
LIBDIR="${CMAKE_INSTALL_FULL_LIBDIR}"
INCLUDEDIR="${CMAKE_INSTALL_FULL_INCLUDEDIR}"
${CARGO} build --release --package deltachat_ffi ${JSONRPC_ARGS}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
)

install(FILES "deltachat-ffi/deltachat.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${CMAKE_BINARY_DIR}/target/${ARCH_DIR}/release/libdeltachat.a" DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES "${CMAKE_BINARY_DIR}/target/${ARCH_DIR}/release/libdeltachat.${DYNAMIC_EXT}" DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES "${CMAKE_BINARY_DIR}/target/${ARCH_DIR}/release/pkgconfig/deltachat.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(FILES "deltachat-ffi/deltachat.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
install(FILES "${CARGO_OUT_DIR}/libdeltachat.a" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES "${CARGO_OUT_DIR}/libdeltachat.${DYNAMIC_EXT}" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES "${CARGO_OUT_DIR}/pkgconfig/deltachat.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

if(WITH_JSONRPC_BINDINGS)
set(JSONRPC_HPP "${CMAKE_CURRENT_SOURCE_DIR}/deltachat-jsonrpc-bindings/qt/deltachat-jsonrpc")
install(FILES "${JSONRPC_HPP}/generated/types.hpp" "${JSONRPC_HPP}/generated/client.hpp"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/deltachat-jsonrpc/generated")
install(FILES "${JSONRPC_HPP}/cffi_client.hpp"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/deltachat-jsonrpc")
endif()
15 changes: 10 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ members = [
"deltachat-ffi",
"deltachat_derive",
"deltachat-jsonrpc",
"deltachat-jsonrpc-bindings",
"deltachat-rpc-server",
"deltachat-ratelimit",
"deltachat-repl",
Expand Down Expand Up @@ -203,7 +204,7 @@ thiserror = "2"
tokio = "1"
tokio-util = "0.7.18"
tracing-subscriber = "0.3"
yerpc = "0.6.4"
yerpc = { git="https://github.com/d2weber/yerpc.git", branch="qt_bindings" }

[features]
default = ["vendored"]
Expand Down
1 change: 1 addition & 0 deletions deltachat-jsonrpc-bindings/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
generated
11 changes: 11 additions & 0 deletions deltachat-jsonrpc-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "deltachat-jsonrpc-bindings"
version = "2.51.0"
edition = "2024"

[build-dependencies]
deltachat-jsonrpc = { workspace = true }

[features]
default = ["vendored"]
vendored = ["deltachat-jsonrpc/vendored"]
6 changes: 6 additions & 0 deletions deltachat-jsonrpc-bindings/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use deltachat_jsonrpc::api::{generate_qt_bindings, generate_ts_bindings};

fn main() {
generate_ts_bindings();
generate_qt_bindings("deltachat");
}
104 changes: 104 additions & 0 deletions deltachat-jsonrpc-bindings/qt/deltachat-jsonrpc/cffi_client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#pragma once

#include "deltachat-jsonrpc/generated/types.hpp"
#include "deltachat-jsonrpc/generated/client.hpp"
#include "deltachat.h"

#include <cstdint>
#include <mutex>
#include <thread>

namespace deltachat {

class CffiTransport : public Transport {
public:
explicit CffiTransport(dc_accounts_t* accounts)
: jsonrpc_(dc_jsonrpc_init(accounts))
{
if (!jsonrpc_) std::abort();
thread_ = std::thread([this] { run(); });
}

virtual ~CffiTransport() {
done_ = true;
// Unblock dc_jsonrpc_next_response by sending a dummy request
if (jsonrpc_) dc_jsonrpc_request(jsonrpc_, "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"get_system_info\"}");
if (thread_.joinable()) thread_.join();
std::lock_guard lk(mu_);
for (auto& [id, prom] : pending_) {
prom.set_value({{}, "Transport destructed", -32060});
}
pending_.clear();
if (jsonrpc_) dc_jsonrpc_unref(jsonrpc_);
}

virtual std::future<Result<QJsonValue>> send(const QString method, const QJsonValue params) override {
uint32_t id = next_id_++;
QJsonObject envelope{
{"jsonrpc", "2.0"},
{"id", static_cast<qint64>(id)},
{"method", method},
{"params", params},
};

std::promise<Result<QJsonValue>> prom;
std::future<Result<QJsonValue>> fut = prom.get_future();

{
std::lock_guard lk(mu_);
pending_[id] = std::move(prom);
}

QByteArray json = QJsonDocument(envelope).toJson(QJsonDocument::Compact);
dc_jsonrpc_request(jsonrpc_, json.constData());
return fut;
}
private:
void run() {
while (!done_) {
char* raw_json = dc_jsonrpc_next_response(jsonrpc_);
if (!raw_json) {
break;
}
QByteArray json{raw_json};
dc_str_unref(raw_json);
if (done_) break;

QJsonObject obj = QJsonDocument::fromJson(json).object();

if (!obj["id"].isDouble()) {
qCritical() << "No valid rpc id in" << QString{json};
continue;
}
uint32_t id = static_cast<uint32_t>(obj["id"].toInt());

std::promise<Result<QJsonValue>> prom;
{
std::lock_guard<std::mutex> lk(mu_);
if (auto nh = pending_.extract(id)) {
prom = std::move(nh.mapped());
} else {
qCritical() << "Could not map response" << QString{json};
continue;
}
}
prom.set_value(parseResult(obj));
}
}

private:
dc_jsonrpc_instance_t* jsonrpc_;
std::thread thread_;
std::mutex mu_;
std::atomic<uint32_t> next_id_{1};
std::atomic<bool> done_{false};
std::unordered_map<uint32_t, std::promise<Result<QJsonValue>>> pending_;
};

class CffiDeltaChat : public RawClient {
public:
explicit CffiDeltaChat(dc_accounts_t* accounts)
: RawClient(std::make_unique<CffiTransport>(accounts)) {}
};

}
3 changes: 3 additions & 0 deletions deltachat-jsonrpc-bindings/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}
6 changes: 5 additions & 1 deletion deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ impl CommandApi {
}
}

#[rpc(all_positional, ts_outdir = "typescript/generated")]
#[rpc(
all_positional,
ts_outdir = "typescript/generated",
qt_outdir = "qt/deltachat-jsonrpc/generated"
)]
impl CommandApi {
/// Test function.
async fn sleep(&self, delay: f64) {
Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
./deltachat-contact-tools
./deltachat-ffi
./deltachat-jsonrpc
./deltachat-jsonrpc-bindings
./deltachat-ratelimit
./deltachat-repl
./deltachat-rpc-client
Expand Down
Loading