mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-10 13:27:12 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1751cb02cb | ||
|
|
c8cc0e9750 | ||
|
|
6f05112970 | ||
|
|
a1d62fd062 | ||
|
|
69f8969883 | ||
|
|
bc200cd76d | ||
|
|
187c7dbce3 | ||
|
|
81131f1c4e | ||
|
|
ce9445a93f | ||
|
|
16372cba0c | ||
|
|
a2cbef315a | ||
|
|
bc7c43dfd1 | ||
|
|
771b300622 | ||
|
|
5ffb5c628d |
No files matched your search
@@ -14,8 +14,8 @@ Values are distributed over the network, with redundancy.
|
||||
* High resilience to network disruption
|
||||
* Public key cryptography layer providing optional data signature and encryption (using GnuTLS)
|
||||
* IPv4 and IPv6 support
|
||||
* Clean and powerful C++14 map API
|
||||
* Python 3 bindings
|
||||
* Clean and powerful **C++14** map API
|
||||
* Bindings for **C, Rust & Python 3**
|
||||
* REST API with optional HTTP client+server with push notification support
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -58,6 +58,8 @@ struct OPENDHT_PUBLIC NodeStats {
|
||||
cached_nodes {0},
|
||||
incoming_nodes {0};
|
||||
unsigned table_depth {0};
|
||||
unsigned cachedNodes {0};
|
||||
unsigned searches {0};
|
||||
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
|
||||
unsigned long getNetworkSizeEstimation() const { return 8 * std::exp2(table_depth); }
|
||||
std::string toString() const;
|
||||
@@ -71,7 +73,25 @@ struct OPENDHT_PUBLIC NodeStats {
|
||||
explicit NodeStats(const Json::Value& v);
|
||||
#endif
|
||||
|
||||
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth)
|
||||
MSGPACK_DEFINE_MAP(good_nodes, dubious_nodes, cached_nodes, incoming_nodes, table_depth, searches)
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC NodeMetrics {
|
||||
size_t scheduler_size {0};
|
||||
size_t node_cache_size {0};
|
||||
size_t request_count {0};
|
||||
size_t rate_limiter_size {0};
|
||||
size_t reported_addr_num {0};
|
||||
size_t store_size {0};
|
||||
size_t store_values {0};
|
||||
size_t store_quota_size {0};
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
/**
|
||||
* Build a json object from a NodeStats
|
||||
*/
|
||||
Json::Value toJson() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct OPENDHT_PUBLIC NodeInfo {
|
||||
@@ -80,6 +100,7 @@ struct OPENDHT_PUBLIC NodeInfo {
|
||||
NodeStats ipv4 {};
|
||||
NodeStats ipv6 {};
|
||||
size_t ongoing_ops {0};
|
||||
NodeMetrics metrics {};
|
||||
|
||||
#ifdef OPENDHT_JSONCPP
|
||||
/**
|
||||
|
||||
@@ -273,6 +273,7 @@ public:
|
||||
void loadState(const std::string& path);
|
||||
|
||||
NodeStats getNodesStats(sa_family_t af) const override;
|
||||
NodeMetrics getNodeMetrics() const override;
|
||||
|
||||
std::string getStorageLog() const override;
|
||||
std::string getStorageLog(const InfoHash&) const override;
|
||||
|
||||
@@ -194,6 +194,7 @@ public:
|
||||
virtual void importValues(const std::vector<ValuesExport>&) = 0;
|
||||
|
||||
virtual NodeStats getNodesStats(sa_family_t af) const = 0;
|
||||
virtual NodeMetrics getNodeMetrics() const { return {}; }
|
||||
|
||||
virtual std::string getStorageLog() const = 0;
|
||||
virtual std::string getStorageLog(const InfoHash&) const = 0;
|
||||
|
||||
@@ -432,6 +432,21 @@ public:
|
||||
return cache.getCachedNodes(id, sa_f, count);
|
||||
}
|
||||
|
||||
size_t getNodeCacheSize() const {
|
||||
return cache.size();
|
||||
}
|
||||
size_t getNodeCacheSize(sa_family_t af) const {
|
||||
return cache.size(af);
|
||||
}
|
||||
|
||||
size_t getRateLimiterSize() const {
|
||||
return address_rate_limiter.size();
|
||||
}
|
||||
|
||||
size_t getPartialCount() const {
|
||||
return partial_messages.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct PartialMessage;
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
namespace dht {
|
||||
|
||||
struct NodeCache {
|
||||
size_t size(sa_family_t family) const {
|
||||
return cache(family).count();
|
||||
}
|
||||
size_t size() const {
|
||||
return size(AF_INET) + size(AF_INET6);
|
||||
}
|
||||
|
||||
Sp<Node> getNode(const InfoHash& id, sa_family_t family);
|
||||
Sp<Node> getNode(const InfoHash& id, const SockAddr&, time_point now, bool confirmed, bool client=false);
|
||||
std::vector<Sp<Node>> getCachedNodes(const InfoHash& id, sa_family_t sa_f, size_t count) const;
|
||||
@@ -49,6 +56,7 @@ private:
|
||||
void clearBadNodes();
|
||||
void setExpired();
|
||||
void cleanup();
|
||||
size_t count() const { return size(); }
|
||||
private:
|
||||
size_t cleanup_counter {0};
|
||||
};
|
||||
|
||||
@@ -115,6 +115,8 @@ public:
|
||||
inline time_point syncTime() { return (now = clock::now()); }
|
||||
inline void syncTime(const time_point& n) { now = n; }
|
||||
|
||||
inline size_t size() const { return timers.size(); }
|
||||
|
||||
private:
|
||||
time_point now {clock::now()};
|
||||
std::multimap<time_point, Sp<Job>> timers {}; /* the jobs ordered by time */
|
||||
|
||||
@@ -180,6 +180,9 @@ public:
|
||||
NodeStats getNodesStats(sa_family_t af) const override {
|
||||
return dht_->getNodesStats(af);
|
||||
}
|
||||
NodeMetrics getNodeMetrics() const override {
|
||||
return dht_->getNodeMetrics();
|
||||
}
|
||||
std::vector<unsigned> getNodeMessageStats(bool in = false) override {
|
||||
return dht_->getNodeMessageStats(in);
|
||||
}
|
||||
|
||||
@@ -110,8 +110,12 @@ print_duration(DT d) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::micro>>(d).count()) + " us";
|
||||
} else if (d < std::chrono::seconds(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(d).count()) + " ms";
|
||||
} else if (d < std::chrono::minutes(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double>>(d).count()) + " s";
|
||||
} else if (d < std::chrono::hours(1)) {
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<60>>>(d).count()) + " min";
|
||||
} else {
|
||||
return to_str(print_dt(d)) + " s";
|
||||
return to_str(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<3600>>>(d).count()) + " h";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ NodeInfo::toJson() const
|
||||
val["ipv4"] = ipv4.toJson();
|
||||
val["ipv6"] = ipv6.toJson();
|
||||
val["ops"] = Json::Value::LargestUInt(ongoing_ops);
|
||||
val["metrics"] = metrics.toJson();
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -157,6 +158,21 @@ NodeInfo::NodeInfo(const Json::Value& v)
|
||||
ongoing_ops = v["ops"].asLargestUInt();
|
||||
}
|
||||
|
||||
Json::Value
|
||||
NodeMetrics::toJson() const
|
||||
{
|
||||
Json::Value val;
|
||||
val["scheduler_size"] = Json::Value::LargestUInt(scheduler_size);
|
||||
val["node_cache_size"] = Json::Value::LargestUInt(node_cache_size);
|
||||
val["request_count"] = Json::Value::LargestUInt(request_count);
|
||||
val["rate_limiter_size"] = Json::Value::LargestUInt(rate_limiter_size);
|
||||
val["reported_addr_num"] = Json::Value::LargestUInt(reported_addr_num);
|
||||
val["store_size"] = Json::Value::LargestUInt(store_size);
|
||||
val["store_values"] = Json::Value::LargestUInt(store_values);
|
||||
val["store_quota_size"] = Json::Value::LargestUInt(store_quota_size);
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+35
-33
@@ -518,19 +518,17 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
|
||||
}
|
||||
|
||||
if (sendQuery) {
|
||||
if (gs == n.getStatus.cend()) {
|
||||
n.probe_query = PROBE_QUERY;
|
||||
gs = n.getStatus.emplace(n.probe_query, Sp<net::Request>()).first;
|
||||
}
|
||||
n.probe_query = PROBE_QUERY;
|
||||
if (logger_)
|
||||
logger_->d(sr->id, n.node->id, "[search %s] [node %s] sending %s",
|
||||
sr->id.toString().c_str(), n.node->toString().c_str(), n.probe_query->toString().c_str());
|
||||
gs->second = network_engine.sendGetValues(n.node,
|
||||
auto req = network_engine.sendGetValues(n.node,
|
||||
sr->id,
|
||||
*PROBE_QUERY,
|
||||
-1,
|
||||
onSelectDone,
|
||||
std::bind(&Dht::searchNodeGetExpired, this, _1, _2, ws, PROBE_QUERY));
|
||||
n.getStatus[PROBE_QUERY] = std::move(req);
|
||||
}
|
||||
if (not n.candidate and ++i == TARGET_NODES)
|
||||
break;
|
||||
@@ -1479,9 +1477,25 @@ Dht::getNodesStats(sa_family_t af) const
|
||||
stats.cached_nodes++;
|
||||
}
|
||||
stats.table_depth = bcks.depth(bcks.findBucket(myid));
|
||||
stats.searches = searches(af).size();
|
||||
stats.cached_nodes = network_engine.getNodeCacheSize(af);
|
||||
return stats;
|
||||
}
|
||||
|
||||
NodeMetrics
|
||||
Dht::getNodeMetrics() const
|
||||
{
|
||||
NodeMetrics metrics;
|
||||
metrics.scheduler_size = scheduler.size();
|
||||
metrics.node_cache_size = network_engine.getNodeCacheSize();
|
||||
metrics.rate_limiter_size = network_engine.getRateLimiterSize();
|
||||
metrics.store_size = store.size();
|
||||
metrics.store_quota_size = store_quota.size();
|
||||
metrics.reported_addr_num = reported_addr.size();
|
||||
metrics.request_count = net::REQ_COUNT.load();
|
||||
return metrics;
|
||||
}
|
||||
|
||||
void
|
||||
Dht::dumpBucket(const Bucket& b, std::ostream& out) const
|
||||
{
|
||||
@@ -1914,37 +1928,25 @@ Dht::maintainStorage(decltype(store)::value_type& storage, bool force, const Don
|
||||
const auto& now = scheduler.time();
|
||||
size_t announce_per_af = 0;
|
||||
|
||||
bool want4 = true, want6 = true;
|
||||
|
||||
auto nodes = buckets4.findClosestNodes(storage.first, now);
|
||||
if (!nodes.empty()) {
|
||||
if (force || storage.first.xorCmp(nodes.back()->id, myid) < 0) {
|
||||
for (auto &value : storage.second.getValues()) {
|
||||
const auto& vt = getType(value.data->type);
|
||||
if (force || value.created + vt.expiration > now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME) {
|
||||
// gotta put that value there
|
||||
announce(storage.first, AF_INET, value.data, donecb, value.created);
|
||||
++announce_per_af;
|
||||
auto maintain = [&](sa_family_t af){
|
||||
bool want = true;
|
||||
auto nodes = buckets(af).findClosestNodes(storage.first, now);
|
||||
if (!nodes.empty()) {
|
||||
if (force || storage.first.xorCmp(nodes.back()->id, myid) < 0) {
|
||||
for (auto &value : storage.second.getValues()) {
|
||||
const auto& vt = getType(value.data->type);
|
||||
if (force || value.created + vt.expiration > now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME) {
|
||||
// gotta put that value there
|
||||
announce(storage.first, af, value.data, donecb, value.created);
|
||||
++announce_per_af;
|
||||
}
|
||||
}
|
||||
want = false;
|
||||
}
|
||||
want4 = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto nodes6 = buckets6.findClosestNodes(storage.first, now);
|
||||
if (!nodes6.empty()) {
|
||||
if (force || storage.first.xorCmp(nodes6.back()->id, myid) < 0) {
|
||||
for (auto &value : storage.second.getValues()) {
|
||||
const auto& vt = getType(value.data->type);
|
||||
if (force || value.created + vt.expiration > now + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME) {
|
||||
// gotta put that value there
|
||||
announce(storage.first, AF_INET6, value.data, donecb, value.created);
|
||||
++announce_per_af;
|
||||
}
|
||||
}
|
||||
want6 = false;
|
||||
}
|
||||
}
|
||||
return want;
|
||||
};
|
||||
bool want4 = maintain(AF_INET), want6 = maintain(AF_INET6);
|
||||
|
||||
if (not want4 and not want6) {
|
||||
if (logger_)
|
||||
|
||||
@@ -479,6 +479,8 @@ DhtRunner::getNodeInfo() const {
|
||||
info.node_id = dht->getNodeId();
|
||||
info.ipv4 = dht->getNodesStats(AF_INET);
|
||||
info.ipv6 = dht->getNodesStats(AF_INET6);
|
||||
info.metrics = dht->getNodeMetrics();
|
||||
info.ongoing_ops = ongoing_ops;
|
||||
}
|
||||
info.ongoing_ops = ongoing_ops;
|
||||
return info;
|
||||
@@ -496,6 +498,7 @@ DhtRunner::getNodeInfo(std::function<void(std::shared_ptr<NodeInfo>)> cb)
|
||||
info.node_id = dht.getNodeId();
|
||||
info.ipv4 = dht.getNodesStats(AF_INET);
|
||||
info.ipv6 = dht.getNodesStats(AF_INET6);
|
||||
info.metrics = dht.getNodeMetrics();
|
||||
info.ongoing_ops = ongoing_ops;
|
||||
cb(std::move(sinfo));
|
||||
opEnded();
|
||||
|
||||
+5
-3
@@ -977,7 +977,6 @@ void
|
||||
Request::onHeadersComplete() {
|
||||
notify_state_change(State::HEADER_RECEIVED);
|
||||
|
||||
|
||||
if (response_.status_code == restinio::status_code::moved_permanently.raw_code() or
|
||||
response_.status_code == restinio::status_code::found.raw_code())
|
||||
{
|
||||
@@ -985,11 +984,14 @@ Request::onHeadersComplete() {
|
||||
if (location_it == response_.headers.end()){
|
||||
if (logger_)
|
||||
logger_->e("[http:client] [request:%i] got redirect without location", id_);
|
||||
terminate(asio::error::connection_aborted);
|
||||
terminate(asio::error::connection_aborted);
|
||||
}
|
||||
|
||||
if (follow_redirect and num_redirect < MAX_REDIRECTS) {
|
||||
auto next = std::make_shared<Request>(ctx_, location_it->second, logger_);
|
||||
next->set_method(header_.method());
|
||||
next->headers_ = std::move(headers_);
|
||||
next->body_ = std::move(body_);
|
||||
next->cbs_ = std::move(cbs_);
|
||||
next->num_redirect = num_redirect + 1;
|
||||
next_ = next;
|
||||
@@ -998,7 +1000,7 @@ Request::onHeadersComplete() {
|
||||
} else {
|
||||
if (logger_)
|
||||
logger_->e("[http:client] [request:%i] got redirect without location", id_);
|
||||
terminate(asio::error::connection_aborted);
|
||||
terminate(asio::error::connection_aborted);
|
||||
}
|
||||
} else {
|
||||
auto expect_it = headers_.find(restinio::http_field_t::expect);
|
||||
|
||||
+12
-2
@@ -29,6 +29,8 @@ namespace net {
|
||||
class NetworkEngine;
|
||||
struct ParsedMessage;
|
||||
|
||||
extern std::atomic<size_t> REQ_COUNT;
|
||||
|
||||
/*!
|
||||
* @class Request
|
||||
* @brief An atomic request destined to a node.
|
||||
@@ -67,14 +69,22 @@ struct Request {
|
||||
}
|
||||
}
|
||||
|
||||
Request(State state = State::PENDING) : state_(state) {}
|
||||
Request(State state = State::PENDING) : state_(state) {
|
||||
REQ_COUNT++;
|
||||
}
|
||||
Request(MessageType type, Tid tid,
|
||||
Sp<Node> node,
|
||||
Blob&& msg,
|
||||
std::function<void(const Request&, ParsedMessage&&)> on_done,
|
||||
std::function<void(const Request&, bool)> on_expired,
|
||||
Tid socket = 0) :
|
||||
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) { }
|
||||
node(node), tid(tid), type(type), on_done(on_done), on_expired(on_expired), msg(std::move(msg)), socket(socket) {
|
||||
REQ_COUNT++;
|
||||
}
|
||||
|
||||
~Request() {
|
||||
REQ_COUNT--;
|
||||
}
|
||||
|
||||
Tid getTid() const { return tid; }
|
||||
MessageType getType() const { return type; }
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ namespace dht {
|
||||
namespace crypto {
|
||||
|
||||
random_device::random_device() :
|
||||
gen(std::chrono::system_clock::now().time_since_epoch().count())
|
||||
gen(std::chrono::system_clock::now().time_since_epoch().count() ^ std::chrono::high_resolution_clock::now().count())
|
||||
{}
|
||||
|
||||
random_device::result_type
|
||||
|
||||
+19
-6
@@ -34,6 +34,9 @@
|
||||
#endif
|
||||
|
||||
namespace dht {
|
||||
namespace net {
|
||||
std::atomic<size_t> REQ_COUNT {0};
|
||||
}
|
||||
|
||||
static constexpr std::array<uint8_t, 12> MAPPED_IPV4_PREFIX {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}};
|
||||
|
||||
@@ -236,13 +239,23 @@ bool operator==(const SockAddr& a, const SockAddr& b) {
|
||||
}
|
||||
|
||||
time_point from_time_t(std::time_t t) {
|
||||
return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now());
|
||||
auto dt = system_clock::from_time_t(t) - system_clock::now();
|
||||
auto now = clock::now();
|
||||
if (dt > system_clock::duration(0) and now > time_point::max() - dt)
|
||||
return time_point::max();
|
||||
else if (dt < system_clock::duration(0) and now < time_point::min() - dt)
|
||||
return time_point::min();
|
||||
return now + dt;
|
||||
}
|
||||
|
||||
std::time_t to_time_t(time_point t) {
|
||||
return std::chrono::system_clock::to_time_t(
|
||||
std::chrono::system_clock::now() +
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(t - clock::now()));
|
||||
auto dt = t - clock::now();
|
||||
auto now = system_clock::now();
|
||||
if (dt > duration(0) and now >= system_clock::time_point::max() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::max());
|
||||
else if (dt < duration(0) and now <= system_clock::time_point::min() - dt)
|
||||
return system_clock::to_time_t(system_clock::time_point::min());
|
||||
return system_clock::to_time_t(now + std::chrono::duration_cast<system_clock::duration>(dt));
|
||||
}
|
||||
|
||||
Blob
|
||||
@@ -274,7 +287,7 @@ findMapValue(const msgpack::object& map, const char* key) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if (o.key.type == msgpack::type::STR
|
||||
if (o.key.type == msgpack::type::STR
|
||||
&& std::strncmp(o.key.via.str.ptr, key, o.key.via.str.size) == 0)
|
||||
return &o.val;
|
||||
}
|
||||
@@ -286,7 +299,7 @@ findMapValue(const msgpack::object& map, const std::string& key) {
|
||||
if (map.type != msgpack::type::MAP) throw msgpack::type_error();
|
||||
for (unsigned i = 0; i < map.via.map.size; i++) {
|
||||
auto& o = map.via.map.ptr[i];
|
||||
if (o.key.type == msgpack::type::STR
|
||||
if (o.key.type == msgpack::type::STR
|
||||
&& key.size() == o.key.via.str.size
|
||||
&& std::strncmp(o.key.via.str.ptr, key.data(), o.key.via.str.size) == 0)
|
||||
return &o.val;
|
||||
|
||||
+104
-100
@@ -261,18 +261,18 @@ FieldValue::operator==(const FieldValue& vfd) const
|
||||
if (field != vfd.field)
|
||||
return false;
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
return intValue == vfd.intValue;
|
||||
case Value::Field::OwnerPk:
|
||||
return hashValue == vfd.hashValue;
|
||||
case Value::Field::UserType:
|
||||
return blobValue == vfd.blobValue;
|
||||
case Value::Field::None:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
return intValue == vfd.intValue;
|
||||
case Value::Field::OwnerPk:
|
||||
return hashValue == vfd.hashValue;
|
||||
case Value::Field::UserType:
|
||||
return blobValue == vfd.blobValue;
|
||||
case Value::Field::None:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,18 +280,18 @@ Value::Filter
|
||||
FieldValue::getLocalFilter() const
|
||||
{
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
return Value::IdFilter(intValue);
|
||||
case Value::Field::ValueType:
|
||||
return Value::TypeFilter(intValue);
|
||||
case Value::Field::OwnerPk:
|
||||
return Value::OwnerFilter(hashValue);
|
||||
case Value::Field::SeqNum:
|
||||
return Value::SeqNumFilter(intValue);
|
||||
case Value::Field::UserType:
|
||||
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
|
||||
default:
|
||||
return {};
|
||||
case Value::Field::Id:
|
||||
return Value::IdFilter(intValue);
|
||||
case Value::Field::ValueType:
|
||||
return Value::TypeFilter(intValue);
|
||||
case Value::Field::OwnerPk:
|
||||
return Value::OwnerFilter(hashValue);
|
||||
case Value::Field::SeqNum:
|
||||
return Value::SeqNumFilter(intValue);
|
||||
case Value::Field::UserType:
|
||||
return Value::UserTypeFilter(std::string {blobValue.begin(), blobValue.end()});
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,23 +311,23 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s)
|
||||
for (const auto& fvp : index) {
|
||||
const auto& f = fvp.first;
|
||||
switch (f) {
|
||||
case Value::Field::Id:
|
||||
index[f] = {f, v.id};
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
index[f] = {f, v.type};
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
index[f] = {f, v.seq};
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id:
|
||||
index[f] = {f, v.id};
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
index[f] = {f, v.type};
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[f] = {f, v.owner ? v.owner->getId() : InfoHash() };
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
index[f] = {f, v.seq};
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[f] = {f, Blob {v.user_type.begin(), v.user_type.end()}};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,28 +347,28 @@ std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi) {
|
||||
os << "Index[";
|
||||
for (auto v = fvi.index.begin(); v != fvi.index.end(); ++v) {
|
||||
switch (v->first) {
|
||||
case Value::Field::Id: {
|
||||
auto flags(os.flags());
|
||||
os << "Id:" << std::hex << v->second.getInt();
|
||||
os.flags(flags);
|
||||
break;
|
||||
}
|
||||
case Value::Field::ValueType:
|
||||
os << "ValueType:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
os << "Owner:" << v->second.getHash().toString();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
os << "Seq:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto ut = v->second.getBlob();
|
||||
os << "UserType:" << std::string(ut.begin(), ut.end());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id: {
|
||||
auto flags(os.flags());
|
||||
os << "Id:" << std::hex << v->second.getInt();
|
||||
os.flags(flags);
|
||||
break;
|
||||
}
|
||||
case Value::Field::ValueType:
|
||||
os << "ValueType:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
os << "Owner:" << v->second.getHash();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
os << "Seq:" << v->second.getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto ut = v->second.getBlob();
|
||||
os << "UserType:" << std::string(ut.begin(), ut.end());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
os << (std::next(v) != fvi.index.end() ? "," : "");
|
||||
}
|
||||
@@ -384,19 +384,19 @@ FieldValueIndex::msgpack_unpack_fields(const std::set<Value::Field>& fields, con
|
||||
for (const auto& field : fields) {
|
||||
auto& field_value = o.via.array.ptr[offset+(j++)];
|
||||
switch (field) {
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
index[field] = FieldValue(field, field_value.as<uint64_t>());
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[field] = FieldValue(field, field_value.as<InfoHash>());
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[field] = FieldValue(field, field_value.as<Blob>());
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
case Value::Field::Id:
|
||||
case Value::Field::ValueType:
|
||||
case Value::Field::SeqNum:
|
||||
index[field] = FieldValue(field, field_value.as<uint64_t>());
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
index[field] = FieldValue(field, field_value.as<InfoHash>());
|
||||
break;
|
||||
case Value::Field::UserType:
|
||||
index[field] = FieldValue(field, field_value.as<Blob>());
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -522,9 +522,12 @@ bool Query::isSatisfiedBy(const Query& q) const {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
s << "SELECT " << (select.fieldSelection_.empty() ? "*" : "");
|
||||
for (auto fs = select.fieldSelection_.begin() ; fs != select.fieldSelection_.end() ; ++fs) {
|
||||
switch (*fs) {
|
||||
s << "SELECT ";
|
||||
if (select.fieldSelection_.empty())
|
||||
s << '*';
|
||||
else
|
||||
for (auto fs = select.fieldSelection_.begin(); fs != select.fieldSelection_.end();) {
|
||||
switch (*fs) {
|
||||
case Value::Field::Id:
|
||||
s << VALUE_KEY_ID;
|
||||
break;
|
||||
@@ -542,9 +545,10 @@ std::ostream& operator<<(std::ostream& s, const dht::Select& select) {
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (++fs != select.fieldSelection_.end())
|
||||
s << ',';
|
||||
}
|
||||
s << (std::next(fs) != select.fieldSelection_.end() ? "," : "");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -553,25 +557,25 @@ std::ostream& operator<<(std::ostream& s, const dht::Where& where) {
|
||||
s << "WHERE ";
|
||||
for (auto f = where.filters_.begin() ; f != where.filters_.end() ; ++f) {
|
||||
switch (f->getField()) {
|
||||
case Value::Field::Id:
|
||||
s << "id=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
s << "value_type=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
s << "owner_pk_hash=" << f->getHash().toString();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
s << "seq=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto b = f->getBlob();
|
||||
s << "user_type=" << std::string {b.begin(), b.end()};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case Value::Field::Id:
|
||||
s << VALUE_KEY_ID << '=' << f->getInt();
|
||||
break;
|
||||
case Value::Field::ValueType:
|
||||
s << "value_type=" << f->getInt();
|
||||
break;
|
||||
case Value::Field::OwnerPk:
|
||||
s << "owner_pk_hash=" << f->getHash();
|
||||
break;
|
||||
case Value::Field::SeqNum:
|
||||
s << VALUE_KEY_SEQ << '=' << f->getInt();
|
||||
break;
|
||||
case Value::Field::UserType: {
|
||||
auto b = f->getBlob();
|
||||
s << "user_type=" << std::string {b.begin(), b.end()};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s << (std::next(f) != where.filters_.end() ? "," : "");
|
||||
}
|
||||
|
||||
@@ -145,6 +145,14 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
|
||||
} else if (op == "ll") {
|
||||
auto nodeInfo = node->getNodeInfo();
|
||||
print_node_info(*node, params);
|
||||
std::cout << "Scheduler size:" << nodeInfo.metrics.scheduler_size << std::endl;
|
||||
std::cout << "RateLimiter size:" << nodeInfo.metrics.rate_limiter_size << std::endl;
|
||||
std::cout << "ReportedAddr count:" << nodeInfo.metrics.reported_addr_num << std::endl;
|
||||
std::cout << "Node cache size:" << nodeInfo.metrics.node_cache_size << std::endl;
|
||||
std::cout << "Store size:" << nodeInfo.metrics.store_size << std::endl;
|
||||
std::cout << "Store quota size:" << nodeInfo.metrics.store_quota_size << std::endl;
|
||||
std::cout << "Global request count:" << nodeInfo.metrics.request_count << std::endl;
|
||||
|
||||
std::cout << nodeInfo.ongoing_ops << " ongoing operations" << std::endl;
|
||||
std::cout << "IPv4 stats:" << std::endl;
|
||||
std::cout << nodeInfo.ipv4.toString() << std::endl;
|
||||
|
||||
+4
-6
@@ -16,10 +16,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <opendht/http.h>
|
||||
#include <opendht/log.h>
|
||||
|
||||
@@ -108,15 +104,17 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
asio::io_context ctx;
|
||||
auto request = std::make_shared<dht::http::Request>(ctx, params.url, [headers=params.headers](const dht::http::Response& response){
|
||||
if (headers) {
|
||||
auto request = std::make_shared<dht::http::Request>(ctx, params.url, [&](const dht::http::Response& response){
|
||||
if (params.headers) {
|
||||
for (const auto& header : response.headers)
|
||||
std::cout << header.first << ": " << header.second << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << response.body << std::endl;
|
||||
ctx.stop();
|
||||
}, logger);
|
||||
request->send();
|
||||
auto work = asio::make_work_guard(ctx);
|
||||
ctx.run();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user