My Project 3.7.9
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#include <string>
13#include <string_view>
14#include <sstream>
15#include <bitset>
16#include <vector>
17#include <iostream>
18#include <algorithm>
19#include <functional>
20#include <memory>
21#include <chrono>
22#include <set>
23
24#ifdef OPENDHT_JSONCPP
25#include <json/json.h>
26#endif
27
28namespace dht {
29using namespace std::literals;
30
31static constexpr auto VALUE_KEY_ID("id");
32static const std::string VALUE_KEY_DAT("dat");
33static const std::string VALUE_KEY_PRIO("p");
34static const std::string VALUE_KEY_PUSHTYPE("pt");
35static const std::string VALUE_KEY_SIGNATURE("sig");
36
37static const std::string VALUE_KEY_SEQ("seq");
38static const std::string VALUE_KEY_DATA("data");
39static const std::string VALUE_KEY_OWNER("owner");
40static const std::string VALUE_KEY_TYPE("type");
41static const std::string VALUE_KEY_TO("to");
42static const std::string VALUE_KEY_BODY("body");
43static const std::string VALUE_KEY_USERTYPE("utype");
44
45struct Value;
46struct Query;
47
59 = std::function<bool(InfoHash key, std::shared_ptr<Value>& value, const InfoHash& from, const SockAddr& addr)>;
60
75using EditPolicy = std::function<bool(InfoHash key,
76 const std::shared_ptr<Value>& old_val,
77 std::shared_ptr<Value>& new_val,
78 const InfoHash& from,
79 const SockAddr& addr)>;
80
81static constexpr const size_t MAX_VALUE_SIZE {1024 * 64};
82static constexpr const duration DEFAULT_VALUE_EXPIRATION {std::chrono::minutes(10)};
84struct ValueType
85{
86 typedef uint16_t Id;
87
88 OPENDHT_PUBLIC static bool DEFAULT_STORE_POLICY(InfoHash,
89 const std::shared_ptr<Value>& v,
90 const InfoHash&,
91 const SockAddr&);
92 static inline bool DEFAULT_EDIT_POLICY(
93 InfoHash, const std::shared_ptr<Value>&, std::shared_ptr<Value>&, const InfoHash&, const SockAddr&)
94 {
95 return false;
96 }
97
98 ValueType() {}
99
100 ValueType(Id id, std::string name, duration e = DEFAULT_VALUE_EXPIRATION)
101 : id(id)
102 , name(name)
103 , expiration(e)
104 {}
105
106 ValueType(Id id, std::string name, duration e, StorePolicy sp, EditPolicy ep = DEFAULT_EDIT_POLICY)
107 : id(id)
108 , name(name)
109 , expiration(e)
110 , storePolicy(sp)
111 , editPolicy(ep)
112 {}
113
114 virtual ~ValueType() {}
115
116 bool operator==(const ValueType& o) { return id == o.id; }
117
118 // Generic value type
119 OPENDHT_PUBLIC static const ValueType USER_DATA;
120
121 Id id {0};
122 std::string name {};
123 duration expiration {DEFAULT_VALUE_EXPIRATION};
124 StorePolicy storePolicy {DEFAULT_STORE_POLICY};
125 EditPolicy editPolicy {DEFAULT_EDIT_POLICY};
126};
128class TypeStore
129{
130public:
131 void registerType(const ValueType& type) { types[type.id] = type; }
132 const ValueType& getType(ValueType::Id type_id) const
133 {
134 const auto& t_it = types.find(type_id);
135 return (t_it == types.end()) ? ValueType::USER_DATA : t_it->second;
136 }
137
138private:
139 std::map<ValueType::Id, ValueType> types {};
140};
141
150 */
151struct OPENDHT_PUBLIC Value
152{
153 enum class Field : int {
154 None = 0,
155 Id, /* Value::id */
156 ValueType, /* Value::type */
157 OwnerPk, /* Value::owner */
158 SeqNum, /* Value::seq */
159 UserType, /* Value::user_type */
160
161 COUNT /* the total number of fields */
162 };
163
164 typedef uint64_t Id;
165 static const constexpr Id INVALID_ID {0};
167 class Filter : public std::function<bool(const Value&)>
168 {
169 public:
170 Filter() {}
171
172 template<typename Functor>
173 Filter(Functor f)
174 : std::function<bool(const Value&)>::function(f)
175 {}
176
177 inline Filter chain(Filter&& f2)
178 {
179 auto f1 = *this;
180 return chain(std::move(f1), std::move(f2));
181 }
182 inline Filter chainOr(Filter&& f2)
183 {
184 auto f1 = *this;
185 return chainOr(std::move(f1), std::move(f2));
186 }
187 static inline Filter chain(Filter&& f1, Filter&& f2)
188 {
189 if (not f1)
190 return std::move(f2);
191 if (not f2)
192 return std::move(f1);
193 return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
194 return f1(v) and f2(v);
195 };
196 }
197 static inline Filter chain(const Filter& f1, const Filter& f2)
198 {
199 if (not f1)
200 return f2;
201 if (not f2)
202 return f1;
203 return [f1, f2](const Value& v) {
204 return f1(v) and f2(v);
205 };
206 }
207 static inline Filter chainAll(std::vector<Filter>&& set)
208 {
209 if (set.empty())
210 return {};
211 return [set = std::move(set)](const Value& v) {
212 for (const auto& f : set)
213 if (f and not f(v))
214 return false;
215 return true;
216 };
217 }
218 static inline Filter chain(std::initializer_list<Filter> l)
219 {
220 return chainAll(std::vector<Filter>(l.begin(), l.end()));
221 }
222 static inline Filter chainOr(Filter&& f1, Filter&& f2)
223 {
224 if (not f1 or not f2)
225 return {};
226 return [f1 = std::move(f1), f2 = std::move(f2)](const Value& v) {
227 return f1(v) or f2(v);
228 };
229 }
230 static inline Filter notFilter(Filter&& f)
231 {
232 if (not f)
233 return [](const Value&) {
234 return false;
235 };
236 return [f = std::move(f)](const Value& v) {
237 return not f(v);
238 };
239 }
240 std::vector<Sp<Value>> filter(const std::vector<Sp<Value>>& values)
241 {
242 if (not(*this))
243 return values;
244 std::vector<Sp<Value>> ret;
245 for (const auto& v : values)
246 if ((*this)(v))
247 ret.emplace_back(v);
248 return ret;
249 }
250 };
251
252 /* Sneaky functions disguised in classes */
253
254 static inline Filter AllFilter() { return {}; }
255
256 static inline Filter TypeFilter(const ValueType& t)
257 {
258 return [tid = t.id](const Value& v) {
259 return v.type == tid;
260 };
261 }
262 static inline Filter TypeFilter(const ValueType::Id& tid)
263 {
264 return [tid](const Value& v) {
265 return v.type == tid;
266 };
267 }
268
269 static inline Filter IdFilter(const Id id)
270 {
271 return [id](const Value& v) {
272 return v.id == id;
273 };
274 }
275
276 static inline Filter RecipientFilter(const InfoHash& r)
277 {
278 return [r](const Value& v) {
279 return v.recipient == r;
280 };
281 }
282
283 static inline Filter OwnerFilter(const crypto::PublicKey& pk) { return OwnerFilter(pk.getId()); }
284
285 static inline Filter OwnerFilter(const InfoHash& pkh)
286 {
287 return [pkh](const Value& v) {
288 return v.owner and v.owner->getId() == pkh;
289 };
290 }
291
292 static inline Filter SeqNumFilter(uint16_t seq_no)
293 {
294 return [seq_no](const Value& v) {
295 return v.seq == seq_no;
296 };
297 }
298
299 static inline Filter UserTypeFilter(std::string ut)
300 {
301 return [ut = std::move(ut)](const Value& v) {
302 return v.user_type == ut;
303 };
304 }
306 class SerializableBase
307 {
308 public:
309 SerializableBase() {}
310 virtual ~SerializableBase() {};
311 virtual const ValueType& getType() const = 0;
312 virtual void unpackValue(const Value& v) = 0;
313 virtual Value packValue() const = 0;
314 };
315
316 template<typename Derived, typename Base = SerializableBase>
317 class Serializable : public Base
318 {
319 public:
320 using Base::Base;
321
322 virtual const ValueType& getType() const { return Derived::TYPE; }
323
324 virtual void unpackValue(const Value& v)
325 {
326 auto msg = msgpack::unpack((const char*) v.data.data(), v.data.size());
327 msg.get().convert(*static_cast<Derived*>(this));
328 }
329
330 virtual Value packValue() const { return Value {getType(), static_cast<const Derived&>(*this)}; }
331 };
332
333 template<typename T, typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
334 static Value pack(const T& obj)
335 {
336 return obj.packValue();
337 }
338
339 template<typename T, typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
340 static Value pack(const T& obj)
341 {
342 return {ValueType::USER_DATA.id, packMsg<T>(obj)};
343 }
344
345 template<typename T, typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
346 static T unpack(const Value& v)
347 {
348 T msg;
349 msg.unpackValue(v);
350 return msg;
351 }
352
353 template<typename T, typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
354 static T unpack(const Value& v)
355 {
356 return unpackMsg<T>(v.data);
357 }
358
359 template<typename T>
360 T unpack()
361 {
362 return unpack<T>(*this);
363 }
364
365 inline bool isEncrypted() const { return not cypher.empty(); }
366 inline bool isSigned() const { return owner and not signature.empty(); }
367
373 void sign(const crypto::PrivateKey& key);
374
379 inline bool checkSignature() const { return isSigned() and owner->checkSignature(getToSign(), signature); }
380
381 inline std::shared_ptr<crypto::PublicKey> getOwner() const { return owner; }
382
386 Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to);
387
388 Value() {}
389
390 Value(Id id)
391 : id(id)
392 {}
393
394 /** Generic constructor */
395 Value(ValueType::Id t, const Blob& data, Id id = INVALID_ID)
396 : id(id)
397 , type(t)
398 , data(data)
399 {}
400 Value(ValueType::Id t, Blob&& data, Id id = INVALID_ID)
401 : id(id)
402 , type(t)
403 , data(std::move(data))
404 {}
405 Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID)
406 : id(id)
407 , type(t)
408 , data(dat_ptr, dat_ptr + dat_len)
409 {}
410
411#ifdef OPENDHT_JSONCPP
416 Value(const Json::Value& json);
417#endif
418
419 template<typename Type>
420 Value(ValueType::Id t, const Type& d, Id id = INVALID_ID)
421 : id(id)
422 , type(t)
423 , data(packMsg(d))
424 {}
425
426 template<typename Type>
427 Value(const ValueType& t, const Type& d, Id id = INVALID_ID)
428 : id(id)
429 , type(t.id)
430 , data(packMsg(d))
431 {}
432
433 /** Custom user data constructor */
434 Value(const Blob& userdata)
435 : data(userdata)
436 {}
437 Value(Blob&& userdata)
438 : data(std::move(userdata))
439 {}
440 Value(const uint8_t* dat_ptr, size_t dat_len)
441 : data(dat_ptr, dat_ptr + dat_len)
442 {}
443
444 Value(Value&& o) noexcept
445 : id(o.id)
446 , owner(std::move(o.owner))
447 , recipient(o.recipient)
448 , type(o.type)
449 , data(std::move(o.data))
450 , user_type(std::move(o.user_type))
451 , seq(o.seq)
452 , signature(std::move(o.signature))
453 , cypher(std::move(o.cypher))
454 , priority(o.priority)
455 , pushType(std::move(o.pushType))
456 {}
457
458 template<typename Type>
459 Value(const Type& vs)
460 : Value(pack<Type>(vs))
461 {}
462
466 Value(const msgpack::object& o) { msgpack_unpack(o); }
467
470 */
471 inline bool contentEquals(const Value& o) const
472 {
473 return isEncrypted() ? cypher == o.cypher
474 : ((owner == o.owner || (owner and o.owner and *owner == *o.owner)) && type == o.type
475 && data == o.data && user_type == o.user_type && signature == o.signature);
476 }
477
478 inline bool operator==(const Value& o) const { return id == o.id and contentEquals(o); }
479 inline bool operator!=(const Value& o) const { return !(*this == o); }
480
481 inline void setRecipient(const InfoHash& r) { recipient = r; }
482
483 inline void setCypher(Blob&& c) { cypher = std::move(c); }
484
487 */
488 inline Blob getToSign() const
489 {
490 msgpack::sbuffer buffer;
491 msgpack::packer<msgpack::sbuffer> pk(&buffer);
492 msgpack_pack_to_sign(pk);
493 return {buffer.data(), buffer.data() + buffer.size()};
494 }
495
498 */
499 inline Blob getToEncrypt() const
500 {
501 msgpack::sbuffer buffer;
502 msgpack::packer<msgpack::sbuffer> pk(&buffer);
503 msgpack_pack_to_encrypt(pk);
504 return {buffer.data(), buffer.data() + buffer.size()};
505 }
506
508 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const Value& v);
509
510 inline std::string toString() const
511 {
512 std::ostringstream ss;
513 ss << *this;
514 return ss.str();
515 }
516
517#ifdef OPENDHT_JSONCPP
526 Json::Value toJson() const;
527#endif
528
530 size_t size() const;
531
532 template<typename Packer>
533 void msgpack_pack_to_sign(Packer& pk) const
534 {
535 bool has_owner = owner && *owner;
536 pk.pack_map((user_type.empty() ? 0 : 1) + (has_owner ? (recipient ? 5 : 4) : 2));
537 if (has_owner) { // isSigned
538 pk.pack(VALUE_KEY_SEQ);
539 pk.pack(seq);
540 pk.pack(VALUE_KEY_OWNER);
541 owner->msgpack_pack(pk);
542 if (recipient) {
543 pk.pack(VALUE_KEY_TO);
544 pk.pack(recipient);
545 }
546 }
547 pk.pack(VALUE_KEY_TYPE);
548 pk.pack(type);
549 pk.pack(VALUE_KEY_DATA);
550 pk.pack_bin(data.size());
551 pk.pack_bin_body((const char*) data.data(), data.size());
552 if (not user_type.empty()) {
553 pk.pack(VALUE_KEY_USERTYPE);
554 pk.pack(user_type);
555 }
556 }
557
558 template<typename Packer>
559 void msgpack_pack_to_encrypt(Packer& pk) const
560 {
561 if (isEncrypted()) {
562 pk.pack_bin(cypher.size());
563 pk.pack_bin_body((const char*) cypher.data(), cypher.size());
564 } else {
565 pk.pack_map(isSigned() ? 2 : 1);
566 pk.pack(VALUE_KEY_BODY);
567 msgpack_pack_to_sign(pk);
568 if (isSigned()) {
569 pk.pack(VALUE_KEY_SIGNATURE);
570 pk.pack_bin(signature.size());
571 pk.pack_bin_body((const char*) signature.data(), signature.size());
572 }
573 }
574 }
575
576 template<typename Packer>
577 void msgpack_pack(Packer& pk) const
578 {
579 pk.pack_map(2 + (priority ? 1 : 0) + (!pushType.empty() ? 1 : 0));
580 pk.pack(VALUE_KEY_ID);
581 pk.pack(id);
582 pk.pack(VALUE_KEY_DAT);
583 msgpack_pack_to_encrypt(pk);
584 if (priority) {
585 pk.pack(VALUE_KEY_PRIO);
586 pk.pack(priority);
587 }
588 if (!pushType.empty()) {
589 pk.pack(VALUE_KEY_PUSHTYPE);
590 pk.pack(pushType);
591 }
592 }
593
594 template<typename Packer>
595 void msgpack_pack_fields(const std::set<Value::Field>& fields, Packer& pk) const
596 {
597 for (const auto& field : fields)
598 switch (field) {
599 case Value::Field::Id:
600 pk.pack(static_cast<uint64_t>(id));
601 break;
602 case Value::Field::ValueType:
603 pk.pack(static_cast<uint64_t>(type));
604 break;
605 case Value::Field::OwnerPk:
606 if (owner)
607 owner->msgpack_pack(pk);
608 else
609 InfoHash().msgpack_pack(pk);
610 break;
611 case Value::Field::SeqNum:
612 pk.pack(static_cast<uint64_t>(seq));
613 break;
614 case Value::Field::UserType:
615 pk.pack(user_type);
616 break;
617 default:
618 break;
619 }
620 }
621
622 void msgpack_unpack(const msgpack::object& o);
623 void msgpack_unpack_body(const msgpack::object& o);
624 Blob getPacked() const
625 {
626 msgpack::sbuffer buffer;
627 msgpack::packer<msgpack::sbuffer> pk(&buffer);
628 pk.pack(*this);
629 return {buffer.data(), buffer.data() + buffer.size()};
630 }
631
632 void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
633
634 Id id {INVALID_ID};
635
639 std::shared_ptr<crypto::PublicKey> owner {};
640
646 InfoHash recipient {};
647
651 ValueType::Id type {ValueType::USER_DATA.id};
652 Blob data {};
653
657 std::string user_type {};
658
662 uint16_t seq {0};
663
667 Blob signature {};
668
672 Blob cypher {};
673
679 unsigned priority {0};
680
686 std::string pushType {};
687
688 inline bool isSignatureChecked() const { return signatureChecked; }
689 inline bool isDecrypted() const { return decrypted; }
690 bool checkSignature();
691 Sp<Value> decrypt(const crypto::PrivateKey& key);
692
693private:
694 /* Cache for crypto ops */
695 bool signatureChecked {false};
696 bool signatureValid {false};
697 bool decrypted {false};
698 Sp<Value> decryptedValue {};
699};
700
701using ValuesExport = std::pair<InfoHash, Blob>;
702
709 */
710struct OPENDHT_PUBLIC FieldValue
711{
712 FieldValue() {}
713 FieldValue(Value::Field f, uint64_t int_value)
714 : field(f)
715 , intValue(int_value)
716 {}
717 FieldValue(Value::Field f, InfoHash hash_value)
718 : field(f)
719 , hashValue(hash_value)
720 {}
721 FieldValue(Value::Field f, Blob blob_value)
722 : field(f)
723 , blobValue(std::move(blob_value))
724 {}
725
726 bool operator==(const FieldValue& fd) const;
727
728 // accessors
729 Value::Field getField() const { return field; }
730 uint64_t getInt() const { return intValue; }
731 InfoHash getHash() const { return hashValue; }
732 Blob getBlob() const { return blobValue; }
733
734 template<typename Packer>
735 void msgpack_pack(Packer& p) const
736 {
737 p.pack_map(2);
738 p.pack("f"sv);
739 p.pack(static_cast<uint8_t>(field));
740
741 p.pack("v"sv);
742 switch (field) {
743 case Value::Field::Id:
744 case Value::Field::ValueType:
745 p.pack(intValue);
746 break;
747 case Value::Field::OwnerPk:
748 p.pack(hashValue);
749 break;
750 case Value::Field::UserType:
751 p.pack_bin(blobValue.size());
752 p.pack_bin_body((const char*) blobValue.data(), blobValue.size());
753 break;
754 default:
755 throw msgpack::type_error();
756 }
757 }
758
759 void msgpack_unpack(const msgpack::object& msg)
760 {
761 hashValue = {};
762 blobValue.clear();
763
764 if (auto f = findMapValue(msg, "f"sv))
765 field = (Value::Field) f->as<unsigned>();
766 else
767 throw msgpack::type_error();
768
769 auto v = findMapValue(msg, "v"sv);
770 if (not v)
771 throw msgpack::type_error();
772 else
773 switch (field) {
774 case Value::Field::Id:
775 case Value::Field::ValueType:
776 intValue = v->as<decltype(intValue)>();
777 break;
778 case Value::Field::OwnerPk:
779 hashValue = v->as<decltype(hashValue)>();
780 break;
781 case Value::Field::UserType:
782 blobValue = unpackBlob(*v);
783 break;
784 default:
785 throw msgpack::type_error();
786 }
787 }
788
789 Value::Filter getLocalFilter() const;
790
791private:
792 Value::Field field {Value::Field::None};
793 // three possible value types
794 uint64_t intValue {};
795 InfoHash hashValue {};
796 Blob blobValue {};
797};
798
805 */
806struct OPENDHT_PUBLIC Select
807{
808 Select() {}
809 Select(std::string_view q_str);
810
811 bool isSatisfiedBy(const Select& os) const;
812
819 */
820 Select& field(Value::Field field)
821 {
822 if (std::find(fieldSelection_.begin(), fieldSelection_.end(), field) == fieldSelection_.end())
823 fieldSelection_.emplace_back(field);
824 return *this;
825 }
826
832 std::set<Value::Field> getSelection() const { return {fieldSelection_.begin(), fieldSelection_.end()}; }
833
834 template<typename Packer>
835 void msgpack_pack(Packer& pk) const
836 {
837 pk.pack(fieldSelection_);
838 }
839 void msgpack_unpack(const msgpack::object& o) { fieldSelection_ = o.as<decltype(fieldSelection_)>(); }
840
841 std::string toString() const
842 {
843 std::ostringstream ss;
844 ss << *this;
845 return ss.str();
846 }
847
848 bool empty() const { return fieldSelection_.empty(); }
849
850 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Select& q);
851
852private:
853 std::vector<Value::Field> fieldSelection_ {};
854};
855
862 */
863struct OPENDHT_PUBLIC Where
864{
865 Where() {}
866 Where(std::string_view q_str);
867
868 bool isSatisfiedBy(const Where& where) const;
869
876 */
877 Where&& id(Value::Id id)
878 {
879 FieldValue fv {Value::Field::Id, id};
880 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
881 filters_.emplace_back(std::move(fv));
882 return std::move(*this);
883 }
884
891 */
892 Where&& valueType(ValueType::Id type)
893 {
894 FieldValue fv {Value::Field::ValueType, type};
895 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
896 filters_.emplace_back(std::move(fv));
897 return std::move(*this);
898 }
899
906 */
907 Where&& owner(InfoHash owner_pk_hash)
908 {
909 FieldValue fv {Value::Field::OwnerPk, owner_pk_hash};
910 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
911 filters_.emplace_back(std::move(fv));
912 return std::move(*this);
913 }
914
921 */
922 Where&& seq(uint16_t seq_no)
923 {
924 FieldValue fv {Value::Field::SeqNum, seq_no};
925 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
926 filters_.emplace_back(std::move(fv));
927 return std::move(*this);
928 }
929
936 */
937 Where&& userType(std::string_view user_type)
938 {
939 FieldValue fv {
940 Value::Field::UserType, Blob {user_type.begin(), user_type.end()}
941 };
942 if (std::find(filters_.begin(), filters_.end(), fv) == filters_.end())
943 filters_.emplace_back(std::move(fv));
944 return std::move(*this);
945 }
946
951 */
953 {
954 if (filters_.empty())
955 return {};
956 if (filters_.size() == 1)
957 return filters_[0].getLocalFilter();
958 std::vector<Value::Filter> fset;
959 fset.reserve(filters_.size());
960 for (const auto& f : filters_) {
961 if (auto lf = f.getLocalFilter())
962 fset.emplace_back(std::move(lf));
963 }
964 return Value::Filter::chainAll(std::move(fset));
965 }
966
967 template<typename Packer>
968 void msgpack_pack(Packer& pk) const
969 {
970 pk.pack(filters_);
971 }
972 void msgpack_unpack(const msgpack::object& o)
973 {
974 filters_.clear();
975 filters_ = o.as<decltype(filters_)>();
976 }
977
978 std::string toString() const
979 {
980 std::ostringstream ss;
981 ss << *this;
982 return ss.str();
983 }
984
985 bool empty() const { return filters_.empty(); }
986
987 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& s, const dht::Where& q);
988
989private:
990 std::vector<FieldValue> filters_;
991};
992
1001struct OPENDHT_PUBLIC Query
1002{
1003 static const std::string QUERY_PARSE_ERROR;
1004
1005 Query(Select s = {}, Where w = {}, bool none = false)
1006 : select(std::move(s))
1007 , where(std::move(w))
1008 , none(none) {};
1009
1023 Query(std::string_view q_str)
1024 {
1025 auto pos_W = q_str.find("WHERE");
1026 auto pos_w = q_str.find("where");
1027 auto pos = std::min(pos_W != std::string_view::npos ? pos_W : q_str.size(),
1028 pos_w != std::string_view::npos ? pos_w : q_str.size());
1029 select = q_str.substr(0, pos);
1030 where = q_str.substr(pos, q_str.size() - pos);
1031 }
1032
1036 bool isSatisfiedBy(const Query& q) const;
1037
1038 template<typename Packer>
1039 void msgpack_pack(Packer& pk) const
1040 {
1041 pk.pack_map(2);
1042 pk.pack("s"sv);
1043 pk.pack(select); /* packing field selectors */
1044 pk.pack("w"sv);
1045 pk.pack(where); /* packing filters */
1046 }
1047
1048 void msgpack_unpack(const msgpack::object& o);
1049
1050 std::string toString() const
1051 {
1052 std::ostringstream ss;
1053 ss << *this;
1054 return ss.str();
1055 }
1056
1057 friend std::ostream& operator<<(std::ostream& s, const dht::Query& q)
1058 {
1059 return s << "Query[" << q.select << " " << q.where << "]";
1060 }
1061
1062 Select select {};
1063 Where where {};
1064 bool none {false}; /* When true, any query satisfies this. */
1065};
1066
1074struct OPENDHT_PUBLIC FieldValueIndex
1075{
1076 FieldValueIndex() {}
1077 FieldValueIndex(const Value& v, const Select& s = {});
1084 bool containedIn(const FieldValueIndex& other) const;
1085
1086 OPENDHT_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FieldValueIndex& fvi);
1087
1088 void msgpack_unpack_fields(const std::set<Value::Field>& fields, const msgpack::object& o, unsigned offset);
1089
1090 std::map<Value::Field, FieldValue> index {};
1091};
1092
1093template<typename T, typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1094Value::Filter
1095getFilterSet(Value::Filter f)
1096{
1097 return Value::Filter::chain({Value::TypeFilter(T::TYPE), T::getFilter(), std::move(f)});
1098}
1099
1100template<typename T, typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1102getFilterSet(Value::Filter f)
1103{
1104 return f;
1105}
1106
1107template<typename T, typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1109getFilterSet()
1110{
1111 return Value::Filter::chain({Value::TypeFilter(T::TYPE), T::getFilter()});
1112}
1113
1114template<typename T, typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
1116getFilterSet()
1117{
1118 return {};
1119}
1120
1121template<class T>
1122std::vector<T>
1123unpackVector(const std::vector<std::shared_ptr<Value>>& vals)
1124{
1125 std::vector<T> ret;
1126 ret.reserve(vals.size());
1127 for (const auto& v : vals) {
1128 try {
1129 ret.emplace_back(Value::unpack<T>(*v));
1130 } catch (const std::exception&) {
1131 }
1132 }
1133 return ret;
1134}
1135
1136#ifdef OPENDHT_JSONCPP
1137uint64_t unpackId(const Json::Value& json, const std::string& key);
1138#endif
1139
1140} // namespace dht
1141
1142MSGPACK_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:58
OPENDHT_PUBLIC Blob unpackBlob(const msgpack::object &o)
std::vector< uint8_t > Blob
Definition utils.h:158
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:74
bool containedIn(const FieldValueIndex &other) const
Describes a value filter.
Definition value.h:710
Describes a query destined to another peer.
Definition value.h:1001
bool isSatisfiedBy(const Query &q) const
Serializable Value field selection.
Definition value.h:806
std::set< Value::Field > getSelection() const
Definition value.h:831
Select & field(Value::Field field)
Definition value.h:819
bool contentEquals(const Value &o) const
Definition value.h:470
bool checkSignature() const
Definition value.h:378
Blob cypher
Definition value.h:671
std::shared_ptr< crypto::PublicKey > owner
Definition value.h:638
uint16_t seq
Definition value.h:661
size_t size() const
std::string pushType
Definition value.h:685
InfoHash recipient
Definition value.h:645
Blob signature
Definition value.h:666
Value encrypt(const crypto::PrivateKey &from, const crypto::PublicKey &to)
Blob getToSign() const
Definition value.h:487
OPENDHT_PUBLIC friend std::ostream & operator<<(std::ostream &s, const Value &v)
Blob getToEncrypt() const
Definition value.h:498
std::string user_type
Definition value.h:656
ValueType::Id type
Definition value.h:650
void sign(const crypto::PrivateKey &key)
unsigned priority
Definition value.h:678
Serializable dht::Value filter.
Definition value.h:863
Value::Filter getFilter() const
Definition value.h:951
Where && userType(std::string_view user_type)
Definition value.h:936
Where && seq(uint16_t seq_no)
Definition value.h:921
Where && id(Value::Id id)
Definition value.h:876
Where && valueType(ValueType::Id type)
Definition value.h:891
Where && owner(InfoHash owner_pk_hash)
Definition value.h:906