Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
69 changes: 43 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,59 @@ include(GNUInstallDirs)
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(ARCH_DIR "$ENV{CARGO_BUILD_TARGET}")
else()
set(ARCH_DIR "./")
set(ARCH_DIR "./")
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
# Keep same env for all cargo calls to enable caching
set(CARGO_BUILD ${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
)

set(CARGO_OUT_DIR "${CMAKE_BINARY_DIR}/target/${ARCH_DIR}/release")

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"
deltachat_ffi
ALL
COMMAND
${CARGO_BUILD} --package deltachat_ffi
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")


add_custom_target(
deltachat_jsonrpc_bindings
COMMAND
${CARGO_BUILD} --package deltachat-jsonrpc-bindings
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
)

install(
FILES
"${CMAKE_CURRENT_SOURCE_DIR}/deltachat-jsonrpc-bindings/qt/generated/types.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/deltachat-jsonrpc-bindings/qt/generated/client.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/deltachat-jsonrpc-bindings/qt/transport.hpp"
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}/deltachat-jsonrpc"
)
16 changes: 11 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
14 changes: 14 additions & 0 deletions deltachat-jsonrpc-bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "deltachat-jsonrpc-bindings"
version = "2.51.0"
edition = "2018"

[dependencies]

[build-dependencies]
deltachat = { workspace = true, default-features = false }
deltachat-jsonrpc = { workspace = true }

[features]
default = ["vendored"]
vendored = ["deltachat/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();
}
96 changes: 96 additions & 0 deletions deltachat-jsonrpc-bindings/qt/transport.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once

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

#include <QMutex>
#include <QMutexLocker>

#include <thread>
#include <cstdint>

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();
QMutexLocker 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();

{
QMutexLocker 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;
{
QMutexLocker 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_;
QMutex mu_;
std::atomic<uint32_t> next_id_{1};
std::atomic<bool> done_{false};
std::unordered_map<uint32_t, std::promise<Result<QJsonValue>>> pending_;
};
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!");
}
2 changes: 1 addition & 1 deletion deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl CommandApi {
}
}

#[rpc(all_positional, ts_outdir = "typescript/generated")]
#[rpc(all_positional, ts_outdir = "typescript/generated", qt_outdir = "qt/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