Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85802984
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cf0a698
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+
+*~
+build
+\#*
+.#*
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..444bf43
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,12 @@
+[submodule "external/lager"]
+ path = external/lager
+ url = https://github.com/arximboldi/lager.git
+[submodule "external/zug"]
+ path = external/zug
+ url = https://github.com/arximboldi/zug.git
+[submodule "external/immer"]
+ path = external/immer
+ url = https://github.com/arximboldi/immer.git
+[submodule "external/json"]
+ path = external/json
+ url = https://github.com/nlohmann/json.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..fb3e053
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 3.8)
+
+if(NOT DEFINED PROJECT_NAME)
+ if(NOT DEFINED libkazv_INSTALL_HEADERS)
+ set(libkazv_INSTALL_HEADERS ON)
+ endif()
+endif()
+
+project(libkazv)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
+
+# Build shared libraries by default
+if(NOT DEFINED BUILD_SHARED_LIBS)
+ set(BUILD_SHARED_LIBS ON)
+endif()
+
+include(FetchContent)
+set(USE_SYSTEM_CURL ON)
+set(BUILD_CPR_TESTS OFF)
+FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/whoshuu/cpr.git GIT_TAG c8d33915dbd88ad6c92b258869b03aba06587ff9) # the commit hash for 1.5.0
+FetchContent_MakeAvailable(cpr)
+
+FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2 GIT_TAG v2.13.0)
+FetchContent_MakeAvailable(Catch2)
+
+set(JSON_BuildTests OFF)
+FetchContent_Declare(nlohmann_json GIT_REPOSITORY https://github.com/nlohmann/json GIT_TAG v3.9.1)
+FetchContent_MakeAvailable(nlohmann_json)
+
+set(immer_BUILD_TESTS OFF)
+set(immer_BUILD_EXAMPLES OFF)
+set(immer_BUILD_DOCS OFF)
+set(immer_BUILD_EXTRAS OFF)
+FetchContent_Declare(immer GIT_REPOSITORY https://github.com/arximboldi/immer GIT_TAG 2076affd9d814afc019ba8cd8c2b18a6c79c9589)
+FetchContent_MakeAvailable(immer)
+
+set(zug_BUILD_TESTS OFF)
+set(zug_BUILD_EXAMPLES OFF)
+set(zug_BUILD_DOCS OFF)
+FetchContent_Declare(zug GIT_REPOSITORY https://github.com/arximboldi/zug GIT_TAG 0bf540906165143eb8b195284c588be29438a16b)
+FetchContent_MakeAvailable(zug)
+
+# Do not let the option()s override variables here
+cmake_policy(SET CMP0077 NEW)
+set(lager_BUILD_TESTS OFF)
+set(lager_BUILD_EXAMPLES OFF)
+set(lager_BUILD_DOCS OFF)
+set(lager_EMBED_RESOURCES_PATH OFF)
+FetchContent_Declare(lager GIT_REPOSITORY https://github.com/arximboldi/lager GIT_TAG a112eed88789bb2986b7924b5b1e71c8a410f81a)
+FetchContent_MakeAvailable(lager)
+
+
+
+option(libkazv_BUILD_TESTS "Build tests" ON)
+option(libkazv_BUILD_EXAMPLES "Build examples" ON)
+
+add_subdirectory(src)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..0c2ad61
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,53 @@
+
+include_directories(api .)
+
+set(libkazv_SRCS
+# api/wellknown.cpp
+ api/basejob.cpp
+ api/login.cpp
+ client/client.cpp
+ )
+
+add_library(kazv ${libkazv_SRCS})
+add_library(libkazv::kazv ALIAS kazv)
+
+target_link_libraries(kazv
+ PUBLIC cpr::cpr
+ PUBLIC nlohmann_json::nlohmann_json
+ PUBLIC immer
+ PUBLIC zug
+ PUBLIC lager)
+target_include_directories(kazv
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/kazv>
+ )
+
+install(
+ TARGETS kazv
+
+ LIBRARY
+ )
+
+if(libkazv_INSTALL_HEADERS)
+ install(
+ DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}/
+
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/kazv"
+
+ FILES_MATCHING PATTERN "*.hpp"
+
+ PATTERN "tests" EXCLUDE
+ )
+endif()
+
+# export(TARGETS kazv)
+
+if(libkazv_BUILD_TESTS)
+ add_subdirectory(tests)
+endif()
+
+if(libkazv_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
diff --git a/src/api/basejob.cpp b/src/api/basejob.cpp
new file mode 100644
index 0000000..fb251b8
--- /dev/null
+++ b/src/api/basejob.cpp
@@ -0,0 +1,116 @@
+
+#include <cpr/cpr.h>
+#include <lager/util.hpp>
+
+#include "basejob.hpp"
+
+namespace Kazv
+{
+ BaseJob::Get BaseJob::GET{};
+ BaseJob::Post BaseJob::POST{};
+ BaseJob::Put BaseJob::PUT{};
+ BaseJob::Delete BaseJob::DELETE{};
+
+ struct BaseJob::Private
+ {
+ Private(std::string serverUrl,
+ std::string requestUrl,
+ Method method,
+ std::string token,
+ ReturnType returnType,
+ Body body);
+ std::string fullRequestUrl;
+ Method method;
+ ReturnType returnType;
+ cpr::Header header;
+ BytesBody body;
+ };
+
+ BaseJob::Private::Private(std::string serverUrl,
+ std::string requestUrl,
+ Method method,
+ std::string token,
+ ReturnType returnType,
+ Body body)
+ : fullRequestUrl(serverUrl + requestUrl)
+ , method(std::move(method))
+ , returnType(returnType)
+ , header()
+ , body()
+
+ {
+ if (token.size()) {
+ header["Authorization"] = "Bearer " + token;
+ }
+
+ if (isBodyJson(body)) {
+ JsonBody j = std::get<JsonBody>(std::move(body));
+ header["Content-Type"] = "application/json";
+ this->body = j.get().dump();
+ } else if (std::holds_alternative<BytesBody>(body)) {
+ BytesBody b = std::get<BytesBody>(std::move(body));
+ this->body = b;
+ }
+ }
+
+ BaseJob::BaseJob(std::string serverUrl,
+ std::string requestUrl,
+ Method method,
+ std::string token,
+ ReturnType returnType,
+ Body body)
+ : m_d(std::move(Private(serverUrl, requestUrl, method, token, returnType, body)))
+ {
+ }
+
+ auto BaseJob::fetch() const -> std::future<Response>
+ {
+ cpr::Url url{m_d->fullRequestUrl};
+ cpr::Body body(m_d->body);
+ cpr::Header header{m_d->header};
+
+ auto callback = [returnType = m_d->returnType](cpr::Response r) -> Response {
+ Body body = r.text;
+
+ if (returnType == ReturnType::Json) {
+ try {
+ body = JsonBody(std::move(json::parse(r.text)));
+ } catch (const json::exception &) {
+ // the response is not valid json
+ }
+ }
+
+ return { r.status_code, body };
+ };
+
+ return std::visit(lager::visitor{
+ [=](Get) {
+ return cpr::GetCallback(callback, url, header, body);
+ },
+ [=](Post) {
+ return cpr::PostCallback(callback, url, header, body);
+ },
+ [=](Put) {
+ return cpr::PutCallback(callback, url, header, body);
+ },
+ [=](Delete) {
+ return cpr::DeleteCallback(callback, url, header, body);
+ }
+ }, m_d->method);
+ }
+
+ bool BaseJob::shouldReturnJson() const
+ {
+ return m_d->returnType == ReturnType::Json;
+ };
+
+ std::string BaseJob::url() const
+ {
+ return m_d->fullRequestUrl;
+ };
+
+ JsonWrap jsonBody(const BaseJob::Response &res)
+ {
+ return std::get<JsonWrap>(res.body);
+ }
+}
diff --git a/src/api/basejob.hpp b/src/api/basejob.hpp
new file mode 100644
index 0000000..fa97302
--- /dev/null
+++ b/src/api/basejob.hpp
@@ -0,0 +1,76 @@
+
+#pragma once
+
+#include <variant>
+#include <tuple>
+#include <functional>
+#include <string>
+#include <immer/map.hpp>
+#include <immer/array.hpp>
+#include <future>
+
+#include "types.hpp"
+#include "descendent.hpp"
+
+namespace Kazv
+{
+ class BaseJob
+ {
+ public:
+ struct Get {};
+ struct Post {};
+ struct Put {};
+ struct Delete {};
+ using Method = std::variant<Get, Post, Put, Delete>;
+
+ static Get GET;
+ static Post POST;
+ static Put PUT;
+ static Delete DELETE;
+
+ using Query = immer::map<std::string, std::string>;
+
+ using BytesBody = Bytes;
+ using JsonBody = JsonWrap;
+ struct EmptyBody {};
+ using Body = std::variant<EmptyBody, JsonBody, BytesBody>;
+
+ static constexpr bool isBodyJson(const Body &body) {
+ return std::holds_alternative<JsonBody>(body);
+ };
+
+ using StatusCode = int;
+ struct Response {
+ StatusCode statusCode;
+ Body body;
+ };
+
+ constexpr bool success(const Response &res) const {
+ return res.statusCode < 300 && (!shouldReturnJson() || isBodyJson(res.body));
+ }
+
+ enum ReturnType {
+ Json,
+ Byte,
+ };
+
+ BaseJob(std::string serverUrl,
+ std::string requestUrl,
+ Method method,
+ std::string token = {},
+ ReturnType returnType = ReturnType::Json,
+ Body body = EmptyBody{});
+
+ std::future<Response> fetch() const;
+
+ bool shouldReturnJson() const;
+
+ std::string url() const;
+
+ private:
+ struct Private;
+ Descendent<Private> m_d;
+ };
+
+ JsonWrap jsonBody(const BaseJob::Response &res);
+}
diff --git a/src/api/constants.hpp b/src/api/constants.hpp
new file mode 100644
index 0000000..a6cfacf
--- /dev/null
+++ b/src/api/constants.hpp
@@ -0,0 +1,9 @@
+
+#include <string>
+
+namespace Kazv
+{
+ using namespace std::string_literals;
+ const std::string CLIENT_MAJOR_VERSION = "r0"s;
+ const std::string BASE_PATH = "/_matrix/client/"s + CLIENT_MAJOR_VERSION;
+}
diff --git a/src/api/login.cpp b/src/api/login.cpp
new file mode 100644
index 0000000..52c1575
--- /dev/null
+++ b/src/api/login.cpp
@@ -0,0 +1,47 @@
+
+#include "constants.hpp"
+#include "login.hpp"
+
+namespace Kazv
+{
+ GetLoginFlowsJob::GetLoginFlowsJob(std::string serverUrl)
+ : BaseJob(std::move(serverUrl), BASE_PATH + "/login"s, GET)
+ {
+ }
+
+
+ json loginDataToJson(std::string serverUrl,
+ std::string username,
+ std::string password,
+ std::optional<std::string> deviceName)
+ {
+ json j = json::object();
+ j["type"] = "m.login.password";
+ j["identifier"] = json::object();
+ j["identifier"]["type"] = "m.id.user";
+ j["identifier"]["user"] = std::move(username);
+ j["password"] = std::move(password);
+ j["initial_device_display_name"] = deviceName
+ ? std::move(deviceName.value())
+ : "libkazv"s;
+
+ return j;
+ }
+
+
+ LoginJob::LoginJob(std::string serverUrl,
+ std::string username,
+ std::string password,
+ std::optional<std::string> deviceName)
+ : BaseJob(serverUrl,
+ BASE_PATH + "/login"s,
+ POST,
+ std::string{},
+ ReturnType::Json,
+ JsonBody(loginDataToJson(serverUrl,
+ std::move(username),
+ std::move(password),
+ std::move(deviceName))))
+ {
+ }
+};
diff --git a/src/api/login.hpp b/src/api/login.hpp
new file mode 100644
index 0000000..8b6d92c
--- /dev/null
+++ b/src/api/login.hpp
@@ -0,0 +1,19 @@
+
+#include "basejob.hpp"
+
+namespace Kazv
+{
+ class GetLoginFlowsJob : public BaseJob
+ {
+ public:
+ GetLoginFlowsJob(std::string serverUrl);
+ };
+ class LoginJob : public BaseJob
+ {
+ public:
+ LoginJob(std::string serverUrl,
+ std::string username,
+ std::string password,
+ std::optional<std::string> deviceName);
+ };
+};
diff --git a/src/api/wellknown.cpp b/src/api/wellknown.cpp
new file mode 100644
index 0000000..34a0211
--- /dev/null
+++ b/src/api/wellknown.cpp
@@ -0,0 +1,10 @@
+
+#include "wellknown.hpp"
+
+namespace Kazv
+{
+ GetWellKnownJob::GetWellKnownJob(std::string serverUrl)
+ : BaseJob(std::move(serverUrl), "/.well-known/matrix/client", GET)
+ {
+ }
+}
diff --git a/src/api/wellknown.hpp b/src/api/wellknown.hpp
new file mode 100644
index 0000000..86e87e6
--- /dev/null
+++ b/src/api/wellknown.hpp
@@ -0,0 +1,14 @@
+
+#pragma once
+
+#include "basejob.hpp"
+#include "types.hpp"
+
+namespace Kazv
+{
+ class GetWellKnownJob : public BaseJob
+ {
+ public:
+ GetWellKnownJob(std::string serverUrl);
+ };
+}
diff --git a/src/client/client.cpp b/src/client/client.cpp
new file mode 100644
index 0000000..21e6cff
--- /dev/null
+++ b/src/client/client.cpp
@@ -0,0 +1,89 @@
+
+#include <lager/util.hpp>
+#include <lager/context.hpp>
+#include <functional>
+
+#include "client.hpp"
+#include "api/login.hpp"
+#include "types.hpp"
+#include "iostream"
+
+namespace Kazv
+{
+ lager::effect<Client::Action> loginEffect(Client::LoginAction a)
+ {
+ return
+ [=](auto &&ctx) {
+ LoginJob job(a.serverUrl,
+ a.username,
+ a.password,
+ a.deviceName);
+ auto res = job.fetch();
+ std::cout << "Result validity: " << res.valid() << std::endl;
+ auto r = res.get();
+ if (job.success(r)) {
+ std::cout << "Job success" << std::endl;
+ const json &j = jsonBody(r).get();
+ try {
+ std::string serverUrl = j.contains("well_known")
+ ? j.at("well_known").at("m.homeserver").at("base_url").get<std::string>()
+ : a.serverUrl;
+ ctx.dispatch(Client::LoadUserInfoAction{
+ serverUrl,
+ j.at("user_id"),
+ j.at("access_token"),
+ j.at("device_id"),
+ /* loggedIn = */ true
+ });
+ } catch (const json::out_of_range &e) {
+ std::cout << "Bad login" << e.what() << std::endl;
+ ctx.dispatch(Error::SetErrorAction{e.what()});
+ }
+ }
+ };
+ }
+
+ lager::effect<Client::Action> logoutEffect(Client::LogoutAction a)
+ {
+ return
+ [=](auto &&ctx) {
+ ctx.dispatch(Client::LoadUserInfoAction{
+ ""s,
+ ""s,
+ ""s,
+ ""s,
+ /* loggedIn = */ true
+ });
+ };
+ }
+
+
+ auto Client::update(Client m, Action a) -> Result
+ {
+ std::cout << "Client::update()" << std::endl;
+ return
+ std::visit(lager::visitor{
+ [=](Error::Action a) mutable -> Result {
+ m.error = Error::update(m.error, a);
+ return {std::move(m), lager::noop};
+ },
+ [=](LoginAction a) mutable -> Result {
+ return {std::move(m), loginEffect(std::move(a))};
+ },
+ [=](LogoutAction a) mutable -> Result {
+ return {std::move(m), logoutEffect(std::move(a))};
+ },
+ [=](LoadUserInfoAction a) mutable -> Result {
+ std::cout << "LoadUserInfoAction: " << a.userId << std::endl;
+ // Need to use set()s
+ Client newClient{a.serverUrl,
+ a.userId,
+ a.token,
+ a.deviceId,
+ a.loggedIn,
+ Error::NoError{}};
+ return { std::move(newClient), lager::noop };
+ },
+ }, std::move(a));
+ }
+}
diff --git a/src/client/client.hpp b/src/client/client.hpp
new file mode 100644
index 0000000..b59d925
--- /dev/null
+++ b/src/client/client.hpp
@@ -0,0 +1,48 @@
+
+#pragma once
+
+#include <tuple>
+#include <variant>
+#include <string>
+
+#include <lager/context.hpp>
+
+#include "error.hpp"
+
+namespace Kazv
+{
+ struct Client
+ {
+ std::string serverUrl;
+ std::string userId;
+ std::string token;
+ std::string deviceId;
+ bool loggedIn;
+ Error error;
+
+ struct LoginAction {
+ std::string serverUrl;
+ std::string username;
+ std::string password;
+ std::optional<std::string> deviceName;
+ };
+
+ struct LoadUserInfoAction {
+ std::string serverUrl;
+ std::string userId;
+ std::string token;
+ std::string deviceId;
+ bool loggedIn;
+ };
+
+ struct LogoutAction {};
+
+ using Action = std::variant<LoginAction,
+ LogoutAction,
+ LoadUserInfoAction,
+ Error::Action
+ >;
+ using Result = std::pair<Client, lager::effect<Action>>;
+ static Result update(Client m, Action a);
+ };
+}
diff --git a/src/client/discovery.hpp b/src/client/discovery.hpp
new file mode 100644
index 0000000..887a2e0
--- /dev/null
+++ b/src/client/discovery.hpp
@@ -0,0 +1,26 @@
+
+#include "types.hpp"
+
+namespace Kazv
+{
+ struct Result {
+ Status status;
+ std::optional<std::string> homeserver;
+ std::optional<std::string> identityServer;
+ };
+
+ Result parseHomeserver(Response r);
+
+ auto GetWellKnownJob::parse(Response r) -> Result
+ {
+ if (r.statusCode == 404) {
+ return Result{SUCC};
+ } else if (r.statusCode != 200
+ || !isBodyJson(r.body)) {
+ return Result{FAIL};
+ } else {
+ return Result{FAIL};
+ }
+ }
+
+}
diff --git a/src/client/error.hpp b/src/client/error.hpp
new file mode 100644
index 0000000..ad80e29
--- /dev/null
+++ b/src/client/error.hpp
@@ -0,0 +1,31 @@
+
+#include "types.hpp"
+#include <variant>
+
+namespace Kazv
+{
+ struct Error
+ {
+ struct NoError {};
+ using JsonError = JsonWrap;
+ std::variant<NoError, JsonError, std::string> error;
+
+ struct SetErrorAction {
+ std::variant<NoError, JsonError, std::string> error;
+ };
+
+ using Action = std::variant<SetErrorAction>;
+
+ static inline Error update(Error e, Action a) {
+ return Error{std::get<SetErrorAction>(a).error};
+ }
+
+ constexpr bool hasError() const {
+ return !std::holds_alternative<NoError>(error);
+ }
+
+ constexpr bool isJson() const {
+ return !std::holds_alternative<JsonError>(error);
+ }
+ };
+};
diff --git a/src/descendent.hpp b/src/descendent.hpp
new file mode 100644
index 0000000..973531d
--- /dev/null
+++ b/src/descendent.hpp
@@ -0,0 +1,46 @@
+
+#pragma once
+
+#include <memory>
+
+namespace Kazv
+{
+ template<typename T>
+ class Descendent
+ {
+ struct concept
+ {
+ virtual ~concept() = default;
+ virtual const T *ptr() const = 0;
+ virtual T *ptr() = 0;
+ virtual std::unique_ptr<concept> clone() const = 0;
+ };
+ template<typename U>
+ struct model : public concept
+ {
+ model(U x) : instance(std::move(x)) {}
+ const T *ptr() const { return &instance; }
+ T *ptr() { return &instance; }
+ // or std::unique_ptr<model<U> >(new model<U>(U(instance))) if you do not have C++14
+ std::unique_ptr<concept> clone() const { return std::make_unique<model<U> >(U(instance)); }
+ U instance;
+ };
+
+ std::unique_ptr<concept> m_d;
+ public:
+ template<typename U>
+ Descendent(U x) : m_d(std::make_unique<model<U> >(std::move(x))) {}
+
+ Descendent(const Descendent & that) : m_d(std::move(that.m_d->clone())) {}
+ Descendent(Descendent && that) : m_d(std::move(that.m_d)) {}
+
+ Descendent & operator=(const Descendent &that) { Descendent t(that); *this = std::move(t); return *this; }
+ Descendent & operator=(Descendent && that) { m_d = std::move(that.m_d); return *this; }
+
+ const T *data() const { return m_d->ptr(); }
+ const T *constData() const { return m_d->ptr(); }
+ T *data() { return m_d->ptr(); }
+ const T *operator->() const { return m_d->ptr(); }
+ T *operator->() { return m_d->ptr(); }
+ };
+}
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
new file mode 100644
index 0000000..bd2fabc
--- /dev/null
+++ b/src/examples/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+add_executable(basicexample
+ basic/main.cpp)
+
+target_link_libraries(basicexample
+ PRIVATE kazv
+ PRIVATE immer
+ PRIVATE zug
+ PRIVATE lager)
diff --git a/src/examples/basic/main.cpp b/src/examples/basic/main.cpp
new file mode 100644
index 0000000..0b1af8c
--- /dev/null
+++ b/src/examples/basic/main.cpp
@@ -0,0 +1,31 @@
+
+#include <string>
+#include <iostream>
+#include <lager/store.hpp>
+#include <lager/event_loop/manual.hpp>
+
+#include <client/client.hpp>
+
+using namespace std::string_literals;
+
+int main()
+{
+ auto store = lager::make_store<Kazv::Client::Action>(
+ Kazv::Client{},
+ &Kazv::Client::update,
+ lager::with_manual_event_loop{});
+
+ std::string homeserver;
+ std::string username;
+ std::string password;
+ std::cout << "Homeserver: ";
+ std::getline(std::cin, homeserver);
+ std::cout << "Username: ";
+ std::getline(std::cin, username);
+ std::cout << "Password: ";
+ std::getline(std::cin, password);
+ store.dispatch(Kazv::Client::LoginAction{homeserver, username, password, "libkazv basic example"s});
+
+ std::cout << "Token: " << store.get().token << std::endl;
+
+}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
new file mode 100644
index 0000000..bf55846
--- /dev/null
+++ b/src/tests/CMakeLists.txt
@@ -0,0 +1,16 @@
+
+
+include(CTest)
+
+add_executable(basejobtest
+ testallapi.cpp
+
+ basejobtest.cpp
+ )
+target_link_libraries(basejobtest
+ PRIVATE Catch2::Catch2
+ PRIVATE kazv
+ PRIVATE nlohmann_json::nlohmann_json
+ PRIVATE immer
+ PRIVATE lager
+ PRIVATE zug)
diff --git a/src/tests/basejobtest.cpp b/src/tests/basejobtest.cpp
new file mode 100644
index 0000000..3cda132
--- /dev/null
+++ b/src/tests/basejobtest.cpp
@@ -0,0 +1,27 @@
+
+#include <catch2/catch.hpp>
+
+#include <iostream>
+#include <future>
+
+#include <basejob.hpp>
+#include "tests.hpp"
+
+using namespace Kazv;
+
+TEST_CASE("Base job should fetch correctly", "[basejob]")
+{
+ BaseJob job(TEST_SERVER_URL, "/.well-known/matrix/client", BaseJob::Get{});
+
+ auto futureResponse = job.fetch();
+ BaseJob::Response r = futureResponse.get();
+
+ if (r.statusCode == 200) {
+ REQUIRE( BaseJob::isBodyJson(r.body) );
+
+ json j = std::get<BaseJob::JsonBody>(r.body).get();
+
+ REQUIRE_NOTHROW( (j["m.homeserver"]["base_url"]) );
+ REQUIRE( (j["m.homeserver"]["base_url"].size() > 0) );
+ }
+}
diff --git a/src/tests/testallapi.cpp b/src/tests/testallapi.cpp
new file mode 100644
index 0000000..621d513
--- /dev/null
+++ b/src/tests/testallapi.cpp
@@ -0,0 +1,3 @@
+
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
diff --git a/src/tests/tests.hpp b/src/tests/tests.hpp
new file mode 100644
index 0000000..4ffc17b
--- /dev/null
+++ b/src/tests/tests.hpp
@@ -0,0 +1,9 @@
+
+#pragma once
+#include <string>
+
+#ifndef TEST_SERVER
+#define TEST_SERVER "https://matrix.org"
+#endif
+
+const std::string TEST_SERVER_URL{TEST_SERVER};
diff --git a/src/types.hpp b/src/types.hpp
new file mode 100644
index 0000000..499faa8
--- /dev/null
+++ b/src/types.hpp
@@ -0,0 +1,33 @@
+
+#pragma once
+#include <string>
+#include <nlohmann/json.hpp>
+#include <immer/array.hpp>
+
+namespace Kazv
+{
+ using json = nlohmann::json;
+
+ using Bytes = std::string;
+
+ enum Status : bool
+ {
+ FAIL,
+ SUCC,
+ };
+
+ class JsonWrap
+ {
+ // Cannot use box here, because it causes the resulting json
+ // to be wrapped into an array.
+ // https://github.com/arximboldi/immer/issues/155
+ immer::array<json> m_d;
+ public:
+ JsonWrap(json&& j) : m_d(1, std::move(j)) {}
+ JsonWrap(const json& j) : m_d(1, j) {}
+
+ auto get() const { return m_d.at(0); }
+ };
+
+ using namespace std::string_literals;
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Oct 8, 10:31 PM (15 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784328
Default Alt Text
(24 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment