My Project 4.4.0
C++ Distributed Hash Table
Loading...
Searching...
No Matches
value.h
1// Copyright (c) 2014-2026 Savoir-faire Linux Inc.
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "infohash.h"
6#include "crypto.h"
7#include "utils.h"
8#include "sockaddr.h"
9
10#include <msgpack.hpp>
11
12#if defined(__FreeBSD__)
13#include <sys/socket.h>
14#include <netinet/in.h>
15#endif
16
17#include <string>
18#include <string_view>
19#include <sstream>
20#include <bitset>
21#include <vector>
22#include <iostream>
23#include <algorithm>
24#include <functional>
25#include <memory>
26#include <chrono>
27#include <set>
28
29#ifdef OPENDHT_JSONCPP
30#include <json/json.h>
31#endif
32
33namespace dht {
34using namespace std::literals;
35
36static constexpr auto VALUE_KEY_ID("id");
37static const std::string VALUE_KEY_DAT("dat");
38static const std::string VALUE_KEY_PRIO("p");
39static const std::string VALUE_KEY_PUSHTYPE("pt");
40static const std::string VALUE_KEY_SIGNATURE("sig");
41
42static const std::string VALUE_KEY_SEQ("seq");
43static const std::string VALUE_KEY_DATA("data");
44static const std::string VALUE_KEY_OWNER("owner");
45static const std::string VALUE_KEY_TYPE("type");
46static const std::string VALUE_KEY_TO("to");
47static const std::string VALUE_KEY_BODY("body");
48static const std::string VALUE_KEY_USERTYPE("utype");
49
50struct Value;
51struct Query;
52
64 = std::function<bool(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr& addr)>;
65
80using EditPolicy = std::function<bool(InfoHash key,
81 const std::shared_ptr<Value>& old_val,
82 std::shared_ptr<Value>& new_val,
83 const InfoHash& from,
84 const SockAddr& addr)>;
85
86static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
87static constexpr const duration DEFAULT_VALUE_EXPIRATION {std::chrono::minutes(10)};
89struct ValueType
90{
91 typedef uint16_t Id;
92
93 OPENDHT_PUBLIC static bool DEFAULT_STORE_POLICY(InfoHash,
94 const std::shared_ptr<Value>& v,
95 const InfoHash&,
96 const SockAddr&);
97 static inline bool DEFAULT_EDIT_POLICY(
98 InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&)
99 {
100 return false;
101 }
102
103 ValueType() {}
104
105 ValueType(Id id, std::string name, duration e = DEFAULT_VALUE_EXPIRATION)
106 : id(id)
107 , name(name)
108 , expiration(e)
109 {}
110
111 ValueType(Id id, std::string name, duration e, StorePolicy sp, EditPolicy ep = DEFAULT_EDIT_POLICY)
112 : id(id)
113 , name(name)
114 , expiration(e)
115 , storePolicy(sp)
116 , editPolicy(ep)
117 {}
118
119 virtual ~ValueType() {}
120
121 bool operator==(const ValueType& o) { return id == o.id; }
122
123 // Generic value type
124 OPENDHT_PUBLIC static const ValueType USER_DATA;
125
126 Id id {0};
127 std::string name {};
128 duration expiration {DEFAULT_VALUE_EXPIRATION};
129 StorePolicy storePolicy {DEFAULT_STORE_POLICY};
130 EditPolicy editPolicy {DEFAULT_EDIT_POLICY};
131};
133class TypeStore
134{
135public:
136 void registerType(const ValueType& type) { types[type.id] = type; }
137 const ValueType& getType(ValueType::Id type_id) const
138 {
139 const auto& t_it = types.find(type_id);
140 return (t_it == types.end()) ? ValueType::USER_DATA : t_it->second;
141 }
142
143private:
144 std::map<ValueType::Id, ValueType> types {};
145};
146
155 */
156struct OPENDHT_PUBLIC Value
157{
158 enum class Field : int {
159 None = 0,
160 Id, /* Value::id */
161 ValueType, /* Value::type */
162 OwnerPk, /* Value::owner */
163 SeqNum, /* Value::seq */
164 UserType, /* Value::user_type */
165
166 COUNT /* the total number of fields */
167 };
168
169 typedef uint64_t Id;
170 static const constexpr Id INVALID_ID {0};
172 class Filter : public std::function<bool(const Value&)>
173 {
174 public:
175 Filter() {}
176
177 template<typename Functor>
178 Filter(Functor f)
179 : std::function<bool(const Value&)>::function(f)
180 {}
181
182 inline Filter chain(Filter&& f2)
183 {
184 auto f1 = *this;
185 return chain(std::move(f1), std::move(f2));
186 }
187 inline Filter chainOr(Filter&& f2)
188 {
189 auto f1 = *this;
190 return chainOr(std::move(f1), std::move(f2));
191 }
192 static inline Filter chain(Filter&& f1, Filter&& f2)
193 {
194 if (not f1)
195 return std::move(f2);
196 if (not f2)
197 return std::move(f1);
198 return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
199 return f1(v) and f2(v);
200 };
201 }
202 static inline Filter chain(const Filter& f1, const Filter& f2)
203 {
204 if (not f1)
205 return f2;
206 if (not f2)
207 return f1;
208 return [f1, f2](const Value& v) {
209 return f1(v) and f2(v);
210 };
211 }
212 static inline Filter chainAll(std::vector<Filter>&& set)
213 {
214 if (set.empty())
215 return {};
216 return [set = std::move(set)](const Value& v) {
217 for (const auto& f : set)
218 if (f and not f(v))
219 return false;
220 return true;
221 };
222 }
223 static inline Filter chain(std::initializer_list<Filter> l)
224 {
225 return chainAll(std::vector<Filter>(l.begin(), l.end()));
226 }
227 static inline Filter chainOr(Filter&& f1, Filter&& f2)
228 {
229 if (not f1 or not f2)
230 return {};
231 return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
232 return f1(v) or f2(v);
233 };
234 }
235 static inline Filter notFilter(Filter&& f)
236 {
237 if (not f)
238 return [](const Value&) {
239 return false;
240 };
241 return [f = std::move(f)](const Value& v) {
242 return not f(v);
243 };
244 }
245 std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values)
246 {
247 if (not(*this))
248 return values;
249 std::vector<Sp<Value>> ret;
250 for (const auto& v : values)
251 if ((*this)(v))
252 ret.emplace_back(v);
253 return ret;
254 }
255 };
256
257 /* Sneaky functions disguised in classes */
258
259 static inline Filter AllFilter() { return {}; }
260
261 static inline Filter TypeFilter(const ValueType& t)
262 {
263 return [tid = t.id](const Value& v) {
264 return v.type == tid;
265 };
266 }
267 static inline Filter TypeFilter(const ValueType::Id& tid)
268 {
269 return [tid](const Value& v) {
270 return v.type == tid;
271 };
272 }
273
274 static inline Filter IdFilter(const Id id)
275 {
276 return [id](const Value& v) {
277 return v.id == id;
278 };
279 }
280
281 static inline Filter RecipientFilter(const InfoHash& r)
282 {
283 return [r](const Value& v) {
284 return v.recipient == r;
285 };
286 }
287
288 static inline Filter OwnerFilter(const crypto::PublicKey& pk) { return OwnerFilter(pk.getId()); }
289
290 static inline Filter OwnerFilter(const InfoHash& pkh)
291 {
292 return [pkh](const Value& v) {
293 return v.owner and v.owner->getId() == pkh;
294 };
295 }
296
297 static inline Filter SeqNumFilter(uint16_t seq_no)
298 {
299 return [seq_no](const Value& v) {
300 return v.seq == seq_no;
301 };
302 }
303
304 static inline Filter UserTypeFilter(std::string ut)
305 {
306 return [ut = std::move(ut)](const Value& v) {
307 return v.user_type == ut;
308 };
309 }
311 class SerializableBase
312 {
313 public:
314 SerializableBase() {}
315 virtual ~SerializableBase() {};
316 virtual const ValueType& getType() const = 0;
317 virtual void unpackValue(const Value& v) = 0;
318 virtual Value packValue() const = 0;
319 };
320
321 template<typename Derived, typename Base = SerializableBase>
322 class Serializable : public Base
323 {
324 public:
325 using Base::Base;
326
327 virtual const ValueType& getType() const { return Derived::TYPE; }
328
329 virtual void unpackValue(const Value& v)
330 {
331 auto msg = msgpack::unpack((const char*) v.data.data(), v.data.size());
332 msg.get().convert(*static_cast<Derived*>(this));
333 }
334
335 virtual Value packValue() const { return Value {getType(), static_cast<const Derived&>(*this)}; }
336 };
337
338 template<typename T, typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
339 static Value pack(const T& obj)
340 {
341 return obj.packValue();
342 }
343
344 template<typename T, typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
345 static Value pack(const T& obj)
346 {
347 return {ValueType::USER_DATA.id, packMsg<T>(obj)};
348 }
349
350 template<typename T, typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
351 static T unpack(const Value& v)
352 {
353 T msg;
354 msg.unpackValue(v);
355 return msg;
356 }
357
358 template<typename T, typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
359 static T unpack(const Value& v)
360 {
361 return unpackMsg<T>(v.data);
362 }
363
364 template<typename T>
365 T unpack()
366 {
367 return unpack<T>(*this);
368 }
369
370 inline bool isEncrypted() const { return not cypher.empty(); }
371 inline bool isSigned() const { return owner and not signature.empty(); }
372
378 void sign(const crypto::PrivateKey& key);
379
384 inline bool checkSignature() const { return isSigned() and owner->checkSignature(getToSign(), signature); }
385
386 inline std::shared_ptr<crypto::PublicKey> getOwner() const { return owner; }
387
391 Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to);
392
393 Value() {}
394
395 Value(Id id)
396 : id(id)
397 {}
398
399 /** Generic constructor */
400 Value(ValueType::Id t, const Blob& data, Id id = INVALID_ID)
401 : id(id)
402 , type(t)
403 , data(data)
404 {}
405 Value(ValueType::Id t, Blob&& data, Id id = INVALID_ID)
406 : id(id)
407 , type(t)
408 , data(std::move(data))
409 {}
410 Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID)
411 : id(id)
412 , type(t)
413 , data(dat_ptr, dat_ptr + dat_len)
414 {}
415
416#ifdef OPENDHT_JSONCPP
421 Value(const Json::Value& json);
422#endif
423
424 template<typename Type>
425 Value(ValueType::Id t, const Type& d, Id id = INVALID_ID)
426 : id(id)
427 , type(t)
428 , data(packMsg(d))
429 {}
430
431 template<typename Type>
432 Value(const ValueType& t, const Type& d, Id id = INVALID_ID)
433 : id(id)
434 , type(t.id)
435 , data(packMsg(d))
436 {}
437
438 /** Custom user data constructor */
439 Value(const Blob& userdata)
440 : data(userdata)
441 {}
442 Value(Blob&& userdata)
443 : data(std::move(userdata))
444 {}
445 Value(const uint8_t* dat_ptr, size_t dat_len)
446 : data(dat_ptr, dat_ptr + dat_len)
447 {}
448
449 Value(Value&& o) noexcept
450 : id(o.id)
451 , owner(std::move(o.owner))
452 , recipient(o.recipient)
453 , type(o.type)
454 , data(std::move(o.data))
455 , user_type(std::move(o.user_type))
456 , seq(o.seq)
457 , signature(std::move(o.signature))
458 , cypher(std::move(o.cypher))
459 , priority(o.priority)
460 , pushType(std::move(o.pushType))
461 {}
462
463 template<typename Type>
464 Value(const Type& vs)
465 : Value(pack<Type>(vs))
466 {}
467
471 Value(const msgpack::object& o) { msgpack_unpack(o); }
472
475 */
476 inline bool contentEquals(const Value& o) const
477 {
478 return isEncrypted() ? cypher == o.cypher
479 : ((owner == o.owner || (owner and o.owner and *owner == *o.owner)) && type == o.type
480 && data == o.data && user_type == o.user_type && signature == o.signature);
481 }
482
483 inline bool operator==(const Value& o) const { return id == o.id and contentEquals(o); }
484 inline bool operator!=(const Value& o) const { return !(*this == o); }
485
486 inline void setRecipient(const InfoHash& r) { recipient = r; }
487
488 inline void setCypher(Blob&& c) { cypher = std::move(c); }
489
492 */
493 inline Blob getToSign() const
494 {
495 msgpack::sbuffer buffer;
496 msgpack::packer<msgpack::sbuffer> pk(&buffer);
497 msgpack_pack_to_sign(pk);
498 return {buffer.data(), buffer.data() + buffer.size()};
499 }
500
503 */
504 inline Blob getToEncrypt() const
505 {
506 msgpack::sbuffer buffer;
507 msgpack::packer<msgpack::sbuffer> pk(&buffer);
508 msgpack_pack_to_encrypt(pk);
509 return {buffer.data(), buffer.data() + buffer.size()};
510 }
511
513 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const Value& v);
514
515 inline std::string toString() const
516 {
517 std::ostringstream ss;
518 ss << *this;
519 return ss.str();
520 }
521
522#ifdef OPENDHT_JSONCPP
531 Json::Value toJson() const;
532#endif
533
535 size_t size() const;
536
537 template<typename Packer>
538 void msgpack_pack_to_sign(Packer& pk) const
539 {
540 bool has_owner = owner && *owner;
541 pk.pack_map((user_type.empty() ? 0 : 1) + (has_owner ? (recipient ? 5 : 4) : 2));
542 if (has_owner) { // isSigned
543 pk.pack(VALUE_KEY_SEQ);
544 pk.pack(seq);
545 pk.pack(VALUE_KEY_OWNER);
546 owner->msgpack_pack(pk);
547 if (recipient) {
548 pk.pack(VALUE_KEY_TO);
549 pk.pack(recipient);
550 }
551 }
552 pk.pack(VALUE_KEY_TYPE);
553 pk.pack(type);
554 pk.pack(VALUE_KEY_DATA);
555 pk.pack_bin(data.size());
556 pk.pack_bin_body((const char*) data.data(), data.size());
557 if (not user_type.empty()) {
558 pk.pack(VALUE_KEY_USERTYPE);
559 pk.pack(user_type);
560 }
561 }
562
563 template<typename Packer>
564 void msgpack_pack_to_encrypt(Packer& pk) const
565 {
566 if (isEncrypted()) {
567 pk.pack_bin(cypher.size());
568 pk.pack_bin_body((const char*) cypher.data(), cypher.size());
569 } else {
570 pk.pack_map(isSigned() ? 2 : 1);
571 pk.pack(VALUE_KEY_BODY);
572 msgpack_pack_to_sign(pk);
573 if (isSigned()) {
574 pk.pack(VALUE_KEY_SIGNATURE);
575 pk.pack_bin(signature.size());
576 pk.pack_bin_body((const char*) signature.data(), signature.size());
577 }
578 }
579 }
580
581 template<typename Packer>
582 void msgpack_pack(Packer& pk) const
583 {
584 pk.pack_map(2 + (priority ? 1 : 0) + (!pushType.empty() ? 1 : 0));
585 pk.pack(VALUE_KEY_ID);
586 pk.pack(id);
587 pk.pack(VALUE_KEY_DAT);
588 msgpack_pack_to_encrypt(pk);
589 if (priority) {
590 pk.pack(VALUE_KEY_PRIO);
591 pk.pack(priority);
592 }
593 if (!pushType.empty()) {
594 pk.pack(VALUE_KEY_PUSHTYPE);
595 pk.pack(pushType);
596 }
597 }
598
599 template<typename Packer>
600 void msgpack_pack_fields(const std::set<Value::Field>& fields, Packer& pk) const
601 {
602 for (const auto& field : fields)
603 switch (field) {
604 case Value::Field::Id:
605 pk.pack(static_cast<uint64_t>(id));
606 break;
607 case Value::Field::ValueType:
608 pk.pack(static_cast<uint64_t>(type));
609 break;
610 case Value::Field::OwnerPk:
611 if (owner)
612 owner->msgpack_pack(pk);
613 else
614 InfoHash().msgpack_pack(pk);
615 break;
616 case Value::Field::SeqNum:
617 pk.pack(static_cast<uint64_t>(seq));
618 break;
619 case Value::Field::UserType:
620 pk.pack(user_type);
621 break;
622 default:
623 break;
624 }
625 }
626
627 void msgpack_unpack(const msgpack::object& o);
628 void msgpack_unpack_body(const msgpack::object& o);
629 Blob getPacked() const
630 {
631 msgpack::sbuffer buffer;
632 msgpack::packer<msgpack::sbuffer> pk(&buffer);
633 pk.pack(*this);
634 return {buffer.data(), buffer.data() + buffer.size()};
635 }
636
637 void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
638
639 Id id {INVALID_ID};
640
644 std::shared_ptr<crypto::PublicKey> owner {};
645
651 InfoHash recipient {};
652
656 ValueType::Id type {ValueType::USER_DATA.id};
657 Blob data {};
658
662 std::string user_type {};
663
667 uint16_t seq {0};
668
672 Blob signature {};
673
677 Blob cypher {};
678
684 unsigned priority {0};
685
691 std::string pushType {};
692
693 inline bool isSignatureChecked() const { return signatureChecked; }
694 inline bool isDecrypted() const { return decrypted; }
695 bool checkSignature();
696 Sp<Value> decrypt(const crypto::PrivateKey& key);
697
698private:
699 /* Cache for crypto ops */
700 bool signatureChecked {false};
701 bool signatureValid {false};
702 bool decrypted {false};
703 Sp<Value> decryptedValue {};
704};
705
706using ValuesExport = std::pair<InfoHash, Blob>;
707
714 */
715struct OPENDHT_PUBLIC FieldValue
716{
717 FieldValue() {}
718 FieldValue(Value::Field f, uint64_t int_value)
719 : field(f)
720 , intValue(int_value)
721 {}
722 FieldValue(Value::Field f, InfoHash hash_value)
723 : field(f)
724 , hashValue(hash_value)
725 {}
726 FieldValue(Value::Field f, Blob blob_value)
727 : field(f)
728 , blobValue(std::move(blob_value))
729 {}
730
731 bool operator==(const FieldValue& fd) const;
732
733 // accessors
734 Value::Field getField() const { return field; }
735 uint64_t getInt() const { return intValue; }
736 InfoHash getHash() const { return hashValue; }
737 Blob getBlob() const { return blobValue; }
738
739 template<typename Packer>
740 void msgpack_pack(Packer& p) const
741 {
742 p.pack_map(2);
743 p.pack("f"sv);
744 p.pack(static_cast<uint8_t>(field));
745
746 p.pack("v"sv);
747 switch (field) {
748 case Value::Field::Id:
749 case Value::Field::ValueType:
750 p.pack(intValue);
751 break;
752 case Value::Field::OwnerPk:
753 p.pack(hashValue);
754 break;
755 case Value::Field::UserType:
756 p.pack_bin(blobValue.size());
757 p.pack_bin_body((const char*) blobValue.data(), blobValue.size());
758 break;
759 default:
760 throw msgpack::type_error();
761 }
762 }
763
764 void msgpack_unpack(const msgpack::object& msg)
765 {
766 hashValue = {};
767 blobValue.clear();
768
769 if (auto f = findMapValue(msg, "f"sv))
770 field = (Value::Field) f->as<unsigned>();
771 else
772 throw msgpack::type_error();
773
774 auto v = findMapValue(msg, "v"sv);
775 if (not v)
776 throw msgpack::type_error();
777 else
778 switch (field) {
779 case Value::Field::Id:
780 case Value::Field::ValueType:
781 intValue = v->as<decltype(intValue)>();
782 break;
783 case Value::Field::OwnerPk:
784 hashValue = v->as<decltype(hashValue)>();
785 break;
786 case Value::Field::UserType:
787 blobValue = unpackBlob(*v);
788 break;
789 default:
790 throw msgpack::type_error();
791 }
792 }
793
794 Value::Filter getLocalFilter() const;
795
796private:
797 Value::Field field {Value::Field::None};
798 // three possible value types
799 uint64_t intValue {};
800 InfoHash hashValue {};
801 Blob blobValue {};
802};
803
810 */
811struct OPENDHT_PUBLIC Select
812{
813 Select() {}
814 Select(std::string_view q_str);
815
816 bool isSatisfiedBy(const Select& os) const;
817
824 */
825 Select& field(Value::Field field)
826 {
827 if (std::find(fieldSelection_.begin(), fieldSelection_.end(), field) == fieldSelection_.end())
828 fieldSelection_.emplace_back(field);
829 return *this;
830 }
831
837 std::set<Value::Field> getSelection() const { return {fieldSelection_.begin(), fieldSelection_.end()}; }
838
839 template<typename Packer>
840 void msgpack_pack(Packer& pk) const
841 {
842 pk.pack(fieldSelection_);
843 }
844 void msgpack_unpack(const msgpack::object& o) { fieldSelection_ = o.as<decltype(fieldSelection_)>(); }
845
846 std::string toString() const
847 {
848 std::ostringstream ss;
849 ss << *this;
850 return ss.str();
851 }
852
853 bool empty() const { return fieldSelection_.empty(); }
854
855 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
856
857private:
858 std::vector<Value::Field> fieldSelection_ {};
859};
860
867 */
868struct OPENDHT_PUBLIC Where
869{
870 Where() {}
871 Where(std::string_view q_str);
872
873 bool isSatisfiedBy(const Where& where) const;
874
881 */
882 Where&& id(Value::Id id)
883 {
884 FieldValue fv {Value::Field::Id, id};
885 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
886 filters_.emplace_back(std::move(fv));
887 return std::move(*this);
888 }
889
896 */
897 Where&& valueType(ValueType::Id type)
898 {
899 FieldValue fv {Value::Field::ValueType, type};
900 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
901 filters_.emplace_back(std::move(fv));
902 return std::move(*this);
903 }
904
911 */
912 Where&& owner(InfoHash owner_pk_hash)
913 {
914 FieldValue fv {Value::Field::OwnerPk, owner_pk_hash};
915 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
916 filters_.emplace_back(std::move(fv));
917 return std::move(*this);
918 }
919
926 */
927 Where&& seq(uint16_t seq_no)
928 {
929 FieldValue fv {Value::Field::SeqNum, seq_no};
930 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
931 filters_.emplace_back(std::move(fv));
932 return std::move(*this);
933 }
934
941 */
942 Where&& userType(std::string_view user_type)
943 {
944 FieldValue fv {
945 Value::Field::UserType, Blob {user_type.begin(), user_type.end()}
946 };
947 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
948 filters_.emplace_back(std::move(fv));
949 return std::move(*this);
950 }
951
956 */
958 {
959 if (filters_.empty())
960 return {};
961 if (filters_.size() == 1)
962 return filters_[0].getLocalFilter();
963 std::vector<Value::Filter> fset;
964 fset.reserve(filters_.size());
965 for (const auto& f : filters_) {
966 if (auto lf = f.getLocalFilter())
967 fset.emplace_back(std::move(lf));
968 }
969 return Value::Filter::chainAll(std::move(fset));
970 }
971
972 template<typename Packer>
973 void msgpack_pack(Packer& pk) const
974 {
975 pk.pack(filters_);
976 }
977 void msgpack_unpack(const msgpack::object& o)
978 {
979 filters_.clear();
980 filters_ = o.as<decltype(filters_)>();
981 }
982
983 std::string toString() const
984 {
985 std::ostringstream ss;
986 ss << *this;
987 return ss.str();
988 }
989
990 bool empty() const { return filters_.empty(); }
991
992 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Where& q);
993
994private:
995 std::vector<FieldValue> filters_;
996};
997
1006struct OPENDHT_PUBLIC Query
1007{
1008 static const std::string QUERY_PARSE_ERROR;
1009
1010 Query(Select s = {}, Where w = {}, bool none = false)
1011 : select(std::move(s))
1012 , where(std::move(w))
1013 , none(none) {};
1014
1028 Query(std::string_view q_str)
1029 {
1030 auto pos_W = q_str.find("WHERE");
1031 auto pos_w = q_str.find("where");
1032 auto pos = std::min(pos_W != std::string_view::npos ? pos_W : q_str.size(),
1033 pos_w != std::string_view::npos ? pos_w : q_str.size());
1034 select = q_str.substr(0, pos);
1035 where = q_str.substr(pos, q_str.size() - pos);
1036 }
1037
1041 bool isSatisfiedBy(const Query& q) const;
1042
1043 template<typename Packer>
1044 void msgpack_pack(Packer& pk) const
1045 {
1046 pk.pack_map(2);
1047 pk.pack("s"sv);
1048 pk.pack(select); /* packing field selectors */
1049 pk.pack("w"sv);
1050 pk.pack(where); /* packing filters */
1051 }
1052
1053 void msgpack_unpack(const msgpack::object& o);
1054
1055 std::string toString() const
1056 {
1057 std::ostringstream ss;
1058 ss << *this;
1059 return ss.str();
1060 }
1061
1062 friend std::ostream& operator<<(std::ostream& s, const dht::Query& q)
1063 {
1064 return s << "Query[" << q.select << " " << q.where << "]";
1065 }
1066
1067 Select select {};
1068 Where where {};
1069 bool none {false}; /* When true, any query satisfies this. */
1070};
1071
1079struct OPENDHT_PUBLIC FieldValueIndex
1080{
1081 FieldValueIndex() {}
1082 FieldValueIndex(const Value& v, const Select& s = {});
1089 bool containedIn(const FieldValueIndex& other) const;
1090
1091 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi);
1092
1093 void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
1094
1095 std::map<Value::Field, FieldValue> index {};
1096};
1097
1098template<typename T, typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1099Value::Filter
1100getFilterSet(Value::Filter f)
1101{
1102 return Value::Filter::chain({Value::TypeFilter(T::TYPE), T::getFilter(), std::move(f)});
1103}
1104
1105template<typename T, typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1107getFilterSet(Value::Filter f)
1108{
1109 return f;
1110}
1111
1112template<typename T, typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1114getFilterSet()
1115{
1116 return Value::Filter::chain({Value::TypeFilter(T::TYPE), T::getFilter()});
1117}
1118
1119template<typename T, typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1121getFilterSet()
1122{
1123 return {};
1124}
1125
1126template<class T>
1127std::vector<T>
1128unpackVector(const std::vector<std::shared_ptr<Value>>& vals)
1129{
1130 std::vector<T> ret;
1131 ret.reserve(vals.size());
1132 for (const auto& v : vals) {
1133 try {
1134 ret.emplace_back(Value::unpack<T>(*v));
1135 } catch (const std::exception&) {
1136 }
1137 }
1138 return ret;
1139}
1140
1141#ifdef OPENDHT_JSONCPP
1142uint64_t unpackId(const Json::Value& json, const std::string& key);
1143#endif
1144
1145} // namespace dht
1146
1147MSGPACK_ADD_ENUM(dht::Value::Field)
std::function< bool(InfoHash key, std::shared_ptr< Value > &value, const InfoHash &from, const SockAddr &addr)> StorePolicy
Definition value.h:63
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object &o)
std::vector< uint8_t > Blob
Definition utils.h:166
std::function< bool(InfoHash key, const std::shared_ptr< Value > &old_val, std::shared_ptr< Value > &new_val, const InfoHash &from, const SockAddr &addr)> EditPolicy
Definition value.h:79
bool containedIn(const FieldValueIndex &other) const
Describes a value filter.
Definition value.h:715
Describes a query destined to another peer.
Definition value.h:1006
bool isSatisfiedBy(const Query &q) const
Serializable Value field selection.
Definition value.h:811
std::set< Value::Field > getSelection() const
Definition value.h:836
Select & field(Value::Field field)
Definition value.h:824
bool contentEquals(const Value &o) const
Definition value.h:475
bool checkSignature() const
Definition value.h:383
Blob cypher
Definition value.h:676
std::shared_ptr< crypto::PublicKey > owner
Definition value.h:643
uint16_t seq
Definition value.h:666
size_t size() const
std::string pushType
Definition value.h:690
InfoHash recipient
Definition value.h:650
Blob signature
Definition value.h:671
Value encrypt(const crypto::PrivateKey &from, const crypto::PublicKey &to)
Blob getToSign() const
Definition value.h:492
OPENDHT_PUBLIC friend std::ostream & operator<<(std::ostream &s, const Value &v)
Blob getToEncrypt() const
Definition value.h:503
std::string user_type
Definition value.h:661
ValueType::Id type
Definition value.h:655
void sign(const crypto::PrivateKey &key)
unsigned priority
Definition value.h:683
Serializable dht::Value filter.
Definition value.h:868
Value::Filter getFilter() const
Definition value.h:956
Where && userType(std::string_view user_type)
Definition value.h:941
Where && seq(uint16_t seq_no)
Definition value.h:926
Where && id(Value::Id id)
Definition value.h:881
Where && valueType(ValueType::Id type)
Definition value.h:896
Where && owner(InfoHash owner_pk_hash)
Definition value.h:911