Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140416
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
29 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/base/basejob.cpp b/src/base/basejob.cpp
index 0c6b46f..fcd7c8c 100644
--- a/src/base/basejob.cpp
+++ b/src/base/basejob.cpp
@@ -1,292 +1,296 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "libkazv-config.hpp"
#include <lager/util.hpp>
#include <vector>
#include <tuple>
#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,
Query query,
Header header,
std::string jobId,
std::optional<FileDesc> responseFile);
std::string fullRequestUrl;
Method method;
ReturnType returnType;
Body body;
Query query;
Header header;
JsonWrap data;
std::string jobId;
std::optional<std::string> queueId;
JobQueuePolicy queuePolicy;
std::optional<FileDesc> responseFile;
};
BaseJob::Private::Private(std::string serverUrl,
std::string requestUrl,
Method method,
std::string token,
ReturnType returnType,
Body body,
Query query,
Header header,
std::string jobId,
std::optional<FileDesc> responseFile)
: fullRequestUrl(serverUrl + requestUrl)
, method(std::move(method))
, returnType(returnType)
, body()
, query(std::move(query))
, jobId(std::move(jobId))
, responseFile(std::move(responseFile))
{
auto header_ = header.get();
if (token.size()) {
header_["Authorization"] = "Bearer " + token;
}
// convert to BytesBody, if possible
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<EmptyBody>(body)) {
this->body = BytesBody();
} else {
this->body = std::move(body);
}
this->header = header_;
}
BaseJob::BaseJob(std::string serverUrl,
std::string requestUrl,
Method method,
std::string jobId,
std::string token,
ReturnType returnType,
Body body,
Query query,
Header header,
std::optional<FileDesc> responseFile)
- : m_d(std::move(Private(serverUrl, requestUrl, method, token,
- returnType, body, query, header, jobId, responseFile)))
+ : m_d(std::make_unique<Private>(serverUrl, requestUrl, method, token,
+ returnType, body, query, header, jobId, responseFile))
{
}
+ KAZV_DEFINE_COPYABLE_UNIQUE_PTR(BaseJob, m_d)
+
+ BaseJob::~BaseJob() = default;
+
bool BaseJob::shouldReturnJson() const
{
return m_d->returnType == ReturnType::Json;
};
std::string BaseJob::url() const
{
return m_d->fullRequestUrl;
};
auto BaseJob::requestBody() const -> Body
{
return m_d->body;
}
auto BaseJob::requestHeader() const -> Header
{
return m_d->header;
}
auto BaseJob::returnType() const -> ReturnType
{
return m_d->returnType;
}
auto BaseJob::requestQuery() const -> Query
{
return m_d->query;
}
auto BaseJob::requestMethod() const -> Method
{
return m_d->method;
}
JsonWrap Response::jsonBody() const
{
return std::get<JsonWrap>(body);
}
json Response::dataJson(const std::string &key) const
{
return extraData.get()[key];
}
std::string Response::dataStr(const std::string &key) const
{
return dataJson(key);
}
std::string Response::jobId() const
{
return dataStr("-job-id");
}
bool BaseJob::contentTypeMatches(immer::array<std::string> expected, std::string actual)
{
for (const auto &i : expected) {
if (i == "*/*"s) {
return true;
} else {
std::size_t pos = i.find("/*"s);
if (pos != std::string::npos) {
std::string majorType(i.data(), i.data() + pos + 1); // includes `/'
if (actual.find(majorType) == 0) {
return true;
}
} else if (i == actual) {
return true;
}
}
}
return false;
}
Response BaseJob::genResponse(Response r) const
{
auto j = m_d->data.get();
j["-job-id"] = m_d->jobId;
r.extraData = j;
return r;
}
void BaseJob::attachData(JsonWrap j)
{
m_d->data = j;
}
BaseJob BaseJob::withData(JsonWrap j) &&
{
auto ret = BaseJob(std::move(*this));
ret.attachData(j);
return ret;
}
BaseJob BaseJob::withData(JsonWrap j) const &
{
auto ret = BaseJob(*this);
ret.attachData(j);
return ret;
}
BaseJob BaseJob::withQueue(std::string id, JobQueuePolicy policy) &&
{
auto ret = BaseJob(std::move(*this));
ret.m_d->queueId = id;
ret.m_d->queuePolicy = policy;
return ret;
}
BaseJob BaseJob::withQueue(std::string id, JobQueuePolicy policy) const &
{
auto ret = BaseJob(*this);
ret.m_d->queueId = id;
ret.m_d->queuePolicy = policy;
return ret;
}
json BaseJob::dataJson(const std::string &key) const
{
return m_d->data.get()[key];
}
std::string BaseJob::dataStr(const std::string &key) const
{
return dataJson(key);
}
std::string BaseJob::jobId() const
{
return m_d->jobId;
}
std::optional<std::string> BaseJob::queueId() const
{
return m_d->queueId;
}
JobQueuePolicy BaseJob::queuePolicy() const
{
return m_d->queuePolicy;
}
std::optional<FileDesc> BaseJob::responseFile() const
{
return m_d->responseFile;
}
std::string Response::errorCode() const
{
// https://matrix.org/docs/spec/client_server/latest#api-standards
if (isBodyJson(body)) {
auto jb = jsonBody();
if (jb.get().contains("errcode")) {
auto code = jb.get()["errcode"].get<std::string>();
if (code != "M_UNKNOWN") {
return code;
}
}
}
return std::to_string(statusCode);
}
std::string Response::errorMessage() const
{
if (isBodyJson(body)) {
auto jb = jsonBody();
if (jb.get().contains("error")) {
auto msg = jb.get()["error"].get<std::string>();
return msg;
}
}
return "";
}
bool operator==(BaseJob a, BaseJob b)
{
return a.m_d->fullRequestUrl == b.m_d->fullRequestUrl
&& a.m_d->method == b.m_d->method
&& a.m_d->returnType == b.m_d->returnType
&& a.m_d->body == b.m_d->body
&& a.m_d->query == b.m_d->query
&& a.m_d->header == b.m_d->header
&& a.m_d->data == b.m_d->data
&& a.m_d->jobId == b.m_d->jobId;
}
bool operator!=(BaseJob a, BaseJob b)
{
return !(a == b);
}
}
diff --git a/src/base/basejob.hpp b/src/base/basejob.hpp
index d575668..91281b8 100644
--- a/src/base/basejob.hpp
+++ b/src/base/basejob.hpp
@@ -1,269 +1,272 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include "libkazv-config.hpp"
#include <optional>
#include <variant>
#include <tuple>
#include <functional>
#include <string>
#include <map>
#include <future>
#include <immer/map.hpp>
#include <immer/array.hpp>
#include <immer/box.hpp>
#include "types.hpp"
-#include "descendent.hpp"
-
+#include "copy-helper.hpp"
#include "file-desc.hpp"
namespace Kazv
{
using Header = immer::box<std::map<std::string, std::string>>;
using BytesBody = Bytes;
using JsonBody = JsonWrap;
using FileBody = FileDesc;
struct EmptyBody {};
using Body = std::variant<EmptyBody, JsonBody, BytesBody, FileBody>;
inline bool operator==(EmptyBody, EmptyBody)
{
return true;
}
inline bool isBodyJson(Body body) {
return std::holds_alternative<JsonBody>(body);
};
enum JobQueuePolicy
{
AlwaysContinue,
CancelFutureIfFailed
};
struct Response {
using StatusCode = int;
StatusCode statusCode;
Body body;
Header header;
JsonWrap extraData;
std::string errorCode() const;
std::string errorMessage() const;
JsonWrap jsonBody() const;
constexpr bool success() const {
return statusCode < 400;
}
json dataJson(const std::string &key) const;
std::string dataStr(const std::string &key) const;
std::string jobId() const;
};
inline bool operator==(Response a, Response b)
{
return a.statusCode == b.statusCode
&& a.body == b.body
&& a.header == b.header
&& a.extraData == b.extraData;
}
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;
class Query : public std::vector<std::pair<std::string, std::string>>
{
using BaseT = std::vector<std::pair<std::string, std::string>>;
public:
using BaseT::BaseT;
void add(std::string k, std::string v) {
push_back({k, v});
}
};
using Body = ::Kazv::Body;
using BytesBody = ::Kazv::BytesBody;
using JsonBody = ::Kazv::JsonBody;
using EmptyBody = ::Kazv::EmptyBody;
using Header = ::Kazv::Header;
using Response = ::Kazv::Response;
enum ReturnType {
Json,
File,
};
BaseJob(std::string serverUrl,
std::string requestUrl,
Method method,
std::string jobId,
std::string token = {},
ReturnType returnType = ReturnType::Json,
Body body = EmptyBody{},
Query query = {},
Header header = {},
std::optional<FileDesc> responseFile = std::nullopt);
+ KAZV_DECLARE_COPYABLE(BaseJob)
+
+ ~BaseJob();
+
bool shouldReturnJson() const;
std::string url() const;
Body requestBody() const;
Header requestHeader() const;
ReturnType returnType() const;
/// returns the non-encoded query as an array of pairs
Query requestQuery() const;
Method requestMethod() const;
static bool contentTypeMatches(immer::array<std::string> expected, std::string actual);
Response genResponse(Response r) const;
BaseJob withData(JsonWrap j) &&;
BaseJob withData(JsonWrap j) const &;
BaseJob withQueue(std::string id, JobQueuePolicy policy = AlwaysContinue) &&;
BaseJob withQueue(std::string id, JobQueuePolicy policy = AlwaysContinue) const &;
json dataJson(const std::string &key) const;
std::string dataStr(const std::string &key) const;
std::string jobId() const;
std::optional<std::string> queueId() const;
JobQueuePolicy queuePolicy() const;
std::optional<FileDesc> responseFile() const;
protected:
void attachData(JsonWrap data);
private:
friend bool operator==(BaseJob a, BaseJob b);
struct Private;
- Descendent<Private> m_d;
+ std::unique_ptr<Private> m_d;
};
bool operator==(BaseJob a, BaseJob b);
bool operator!=(BaseJob a, BaseJob b);
inline bool operator==(BaseJob::Get, BaseJob::Get) { return true; }
inline bool operator==(BaseJob::Post, BaseJob::Post) { return true; }
inline bool operator==(BaseJob::Put, BaseJob::Put) { return true; }
inline bool operator==(BaseJob::Delete, BaseJob::Delete) { return true; }
namespace detail
{
template<class T>
struct AddToQueryT
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
q.add(name, std::to_string(std::forward<U>(arg)));
}
};
template<>
struct AddToQueryT<std::string>
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
q.add(name, std::forward<U>(arg));
}
};
template<>
struct AddToQueryT<bool>
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
q.add(name, std::forward<U>(arg) ? "true"s : "false"s);
}
};
template<class T>
struct AddToQueryT<immer::array<T>>
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
for (auto v : std::forward<U>(arg)) {
q.add(name, v);
}
}
};
template<>
struct AddToQueryT<json>
{
// https://github.com/nlohmann/json/issues/2040
static void call(BaseJob::Query &q, std::string /* name */, const json &arg) {
// assume v is string type
for (auto [k, v] : arg.items()) {
q.add(k, v);
}
}
};
}
template<class T>
inline void addToQuery(BaseJob::Query &q, std::string name, T &&arg)
{
detail::AddToQueryT<std::decay_t<T>>::call(q, name, std::forward<T>(arg));
}
namespace detail
{
template<class T>
struct AddToQueryIfNeededT
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
using ArgT = std::decay_t<U>;
if constexpr (detail::hasEmptyMethod(boost::hana::type_c<ArgT>)) {
if (! arg.empty()) {
addToQuery(q, name, std::forward<U>(arg));
}
} else {
addToQuery(q, name, std::forward<U>(arg));
}
}
};
template<class T>
struct AddToQueryIfNeededT<std::optional<T>>
{
template<class U>
static void call(BaseJob::Query &q, std::string name, U &&arg) {
if (arg.has_value()) {
addToQuery(q, name, std::forward<U>(arg).value());
}
}
};
}
template<class T>
inline void addToQueryIfNeeded(BaseJob::Query &q, std::string name, T &&arg)
{
detail::AddToQueryIfNeededT<std::decay_t<T>>::call(q, name, std::forward<T>(arg));
}
}
diff --git a/src/base/copy-helper.hpp b/src/base/copy-helper.hpp
index 70e8d43..ab7514b 100644
--- a/src/base/copy-helper.hpp
+++ b/src/base/copy-helper.hpp
@@ -1,40 +1,40 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
-#include <libkazv-config.hpp>
+#include "libkazv-config.hpp"
#define KAZV_DECLARE_COPYABLE(typeName) \
typeName(const typeName &that); \
typeName(typeName &&that); \
typeName &operator=(const typeName &that); \
typeName &operator=(typeName &&that);
#define KAZV_DEFINE_COPYABLE_UNIQUE_PTR(typeName, privateName) \
typeName::typeName(const typeName &that) \
: privateName(std::make_unique<decltype(privateName)::element_type>(*(that.privateName))) \
{ \
} \
typeName::typeName(typeName &&that) \
: privateName(std::move(that.privateName)) \
{ \
} \
typeName &typeName::operator=(const typeName &that) \
{ \
if (privateName != that.privateName) { \
privateName.reset(); \
privateName = std::make_unique<decltype(privateName)::element_type>(*(that.privateName)); \
} \
return *this; \
} \
typeName &typeName::operator=(typeName &&that) \
{ \
if (privateName != that.privateName) { \
privateName.reset(); \
privateName = std::move(that.privateName); \
} \
return *this; \
}
diff --git a/src/base/descendent.hpp b/src/base/descendent.hpp
deleted file mode 100644
index 960fd50..0000000
--- a/src/base/descendent.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of libkazv.
- * SPDX-FileCopyrightText: 2020 Tusooa Zhu
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-
-#pragma once
-#include "libkazv-config.hpp"
-
-#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 const T &ref() const = 0;
- virtual T &ref() = 0;
- virtual T &&rref() && = 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; }
- const T &ref() const { return instance; }
- T &ref() { return instance; }
- T &&rref() && { return std::move(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:
- Descendent() : m_d(std::make_unique<model<T>>(T())) {}
-
- 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 &ref() const { return m_d->ref(); }
- const T &constRef() const { return m_d->ref(); }
- const T &ref() { return m_d->ref(); }
- T &&rref() && { return m_d->rref(); }
-
- 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(); }
-
- template<class Derived> bool isa() const {
- return dynamic_cast<Derived *>(constData());
- }
-
- template<class Derived> Derived &cast() {
- return dynamic_cast<Derived &>(ref());
- }
- template<class Derived> const Derived &cast() const {
- return dynamic_cast<const Derived &>(ref());
- }
- template<class Derived> const Derived &constCast() const {
- return dynamic_cast<const Derived &>(ref());
- }
- template<class Derived> const Derived &rCast() && {
- return dynamic_cast<Derived &&>(rref());
- }
- };
-}
diff --git a/src/base/types.hpp b/src/base/types.hpp
index df6470c..60cb542 100644
--- a/src/base/types.hpp
+++ b/src/base/types.hpp
@@ -1,223 +1,222 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include "libkazv-config.hpp"
#include <optional>
#include <string>
#include <variant>
#include <nlohmann/json.hpp>
#include <immer/array.hpp>
#include <immer/flex_vector.hpp>
#include <immer/map.hpp>
#include <boost/hana/type.hpp>
#include <lager/util.hpp>
#include "jsonwrap.hpp"
#include "event.hpp"
-#include "descendent.hpp"
namespace Kazv
{
using Bytes = std::string;
enum Status : bool
{
FAIL,
SUCC,
};
namespace detail
{
constexpr auto hasEmptyMethod = boost::hana::is_valid(
[](auto t) -> decltype((void)std::declval<typename decltype(t)::type>().empty()) {});
template<class U>
struct AddToJsonIfNeededT
{
template<class T>
static void call(json &j, std::string name, T &&arg) {
using Type = std::decay_t<T>;
if constexpr (detail::hasEmptyMethod(boost::hana::type_c<Type>)) {
if (! arg.empty()) {
j[name] = std::forward<T>(arg);
}
} else {
j[name] = std::forward<T>(arg);
}
}
};
template<class U>
struct AddToJsonIfNeededT<std::optional<U>>
{
template<class T>
static void call(json &j, std::string name, T &&arg) {
if (arg.has_value()) {
j[name] = std::forward<T>(arg).value();
}
}
};
}
template<class T>
inline void addToJsonIfNeeded(json &j, std::string name, T &&arg)
{
detail::AddToJsonIfNeededT<std::decay_t<T>>::call(j, name, std::forward<T>(arg));
};
// Provide a non-destructive way to add the map
// to json.
template<class MapT,
// disallow json object here
std::enable_if_t<!std::is_same_v<std::decay_t<MapT>, json>
&& !std::is_same_v<std::decay_t<MapT>, JsonWrap>, int> = 0>
inline void addPropertyMapToJson(json &j, MapT &&arg)
{
for (auto kv : std::forward<MapT>(arg)) {
auto [k, v] = kv;
j[k] = v;
}
};
inline void addPropertyMapToJson(json &j, const json &arg)
{
for (auto kv : arg.items()) {
auto [k, v] = kv;
j[k] = v;
}
};
using EventList = immer::flex_vector<Event>;
using namespace std::string_literals;
struct Null {};
using Variant = std::variant<std::string, JsonWrap, Null>;
namespace detail
{
struct DefaultValT
{
template<class T>
constexpr operator T() const {
return T();
}
};
}
constexpr detail::DefaultValT DEFVAL;
enum RoomMembership
{
Invite, Join, Leave
};
namespace detail
{
// emulates declval() but returns lvalue reference
template<class T>
typename std::add_lvalue_reference<T>::type declref() noexcept;
}
}
namespace nlohmann {
template <class T, class V>
struct adl_serializer<immer::map<T, V>> {
static void to_json(json& j, immer::map<T, V> map) {
if constexpr (std::is_same_v<T, std::string>) {
j = json::object();
for (auto [k, v] : map) {
j[k] = v;
}
} else {
j = json::array();
for (auto [k, v] : map) {
j.push_back(k);
j.push_back(v);
}
}
}
static void from_json(const json& j, immer::map<T, V> &m) {
immer::map<T, V> ret;
if constexpr (std::is_same_v<T, std::string>) {
for (const auto &[k, v] : j.items()) {
ret = std::move(ret).set(k, v);
}
} else {
for (std::size_t i = 0; i < j.size(); i += 2) {
ret = std::move(ret).set(j[i], j[i+1]);
}
}
m = ret;
}
};
template <class T>
struct adl_serializer<immer::array<T>> {
static void to_json(json& j, immer::array<T> arr) {
j = json::array();
for (auto i : arr) {
j.push_back(json(i));
}
}
static void from_json(const json& j, immer::array<T> &a) {
immer::array<T> ret;
if (j.is_array()) {
for (const auto &i : j) {
ret = std::move(ret).push_back(i);
}
}
a = ret;
}
};
template <class T>
struct adl_serializer<immer::flex_vector<T>> {
static void to_json(json& j, immer::flex_vector<T> arr) {
j = json::array();
for (auto i : arr) {
j.push_back(json(i));
}
}
static void from_json(const json& j, immer::flex_vector<T> &a) {
immer::flex_vector<T> ret;
if (j.is_array()) {
for (const auto &i : j) {
ret = std::move(ret).push_back(i.get<T>());
}
}
a = ret;
}
};
template <>
struct adl_serializer<Kazv::Variant> {
static void to_json(json& j, const Kazv::Variant &var) {
std::visit(lager::visitor{
[&j](std::string i) { j = i; },
[&j](Kazv::JsonWrap i) { j = i; },
[&j](Kazv::Null) { j = nullptr; }
}, var);
}
static void from_json(const json& j, Kazv::Variant &var) {
if (j.is_string()) {
var = j.get<std::string>();
} else if (j.is_null()) {
var = Kazv::Null{};
} else { // is object
var = Kazv::Variant(Kazv::JsonWrap(j));
}
}
};
}
diff --git a/src/job/cprjobhandler.hpp b/src/job/cprjobhandler.hpp
index eba4497..07306e0 100644
--- a/src/job/cprjobhandler.hpp
+++ b/src/job/cprjobhandler.hpp
@@ -1,39 +1,38 @@
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020 Tusooa Zhu
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <libkazv-config.hpp>
#include <memory>
#include <boost/asio.hpp>
#include "jobinterface.hpp"
-#include "descendent.hpp"
namespace Kazv
{
struct CprJobHandler : public JobInterface
{
CprJobHandler(boost::asio::io_context::executor_type executor);
~CprJobHandler() override;
void async(std::function<void()> func) override;
void setTimeout(std::function<void()> func, int ms,
std::optional<std::string> timerId = std::nullopt) override;
void setInterval(std::function<void()> func, int ms,
std::optional<std::string> timerId = std::nullopt) override;
void cancel(std::string timerId) override;
void submit(BaseJob job,
std::function<void(Response)> callback) override;
void stop();
private:
struct Private;
std::unique_ptr<Private> m_d;
};
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 8:11 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55431
Default Alt Text
(29 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment