1 | #pragma once |
2 | |
3 | /// @file |
4 | /// @brief Identifiers used in the Matrix API. |
5 | |
6 | #if __has_include(<nlohmann/json_fwd.hpp>) |
7 | #include <nlohmann/json_fwd.hpp> |
8 | #else |
9 | #include <nlohmann/json.hpp> |
10 | #endif |
11 | |
12 | #include <compare> |
13 | #include <stdexcept> |
14 | |
15 | namespace mtx { |
16 | namespace identifiers { |
17 | |
18 | //! Base class for all the identifiers. |
19 | // |
20 | //! Each identifier has the following format `(sigil)``(localpart)`:`(hostname)`. |
21 | class ID |
22 | { |
23 | public: |
24 | //! Returns the unique local part of the identifier. |
25 | [[nodiscard]] std::string localpart() const { return localpart_; } |
26 | //! Returns the name of the originating homeserver. |
27 | [[nodiscard]] std::string hostname() const { return hostname_; } |
28 | //! Returns the whole identifier (localpart + hostname). |
29 | [[nodiscard]] std::string to_string() const { return id_; } |
30 | |
31 | protected: |
32 | //! Local part of the identifier. |
33 | std::string localpart_; |
34 | //! The name of the originating homeserver. |
35 | std::string hostname_; |
36 | //! The whole identifier. |
37 | std::string id_; |
38 | }; |
39 | |
40 | //! An event id. |
41 | class Event : public ID |
42 | { |
43 | public: |
44 | template<typename Identifier> |
45 | friend Identifier parse(const std::string &id); |
46 | |
47 | private: |
48 | //! The `sigil` used to represent an Event. |
49 | static constexpr std::string_view sigil = "$" ; |
50 | |
51 | friend void from_json(const nlohmann::json &obj, Event &event); |
52 | friend void to_json(nlohmann::json &obj, const Event &event); |
53 | }; |
54 | |
55 | //! A room id. |
56 | class Room : public ID |
57 | { |
58 | public: |
59 | template<typename Identifier> |
60 | friend Identifier parse(const std::string &id); |
61 | |
62 | private: |
63 | static constexpr std::string_view sigil = "!" ; |
64 | |
65 | friend void from_json(const nlohmann::json &obj, Room &room); |
66 | friend void to_json(nlohmann::json &obj, const Room &room); |
67 | }; |
68 | |
69 | //! A user id. |
70 | class User : public ID |
71 | { |
72 | public: |
73 | template<typename Identifier> |
74 | friend Identifier parse(const std::string &id); |
75 | auto (User const &other) const noexcept { return id_.compare(str: other.id_) <=> 0; }; |
76 | bool operator==(User const &other) const noexcept { return id_ == other.id_; }; |
77 | |
78 | private: |
79 | static constexpr std::string_view sigil = "@" ; |
80 | |
81 | friend void from_json(const nlohmann::json &obj, User &user); |
82 | friend void to_json(nlohmann::json &obj, const User &user); |
83 | }; |
84 | |
85 | //! Parses the given string into a @p Identifier. |
86 | //! \param id String to parse. |
87 | //! \returns The parsed @p Identifier. |
88 | //! \throws std::invalid_argument in case of invalid input. |
89 | template<typename Identifier> |
90 | Identifier |
91 | parse(const std::string &id) |
92 | { |
93 | if (id.empty()) { |
94 | // FIXME: enable logging only in debug mode. |
95 | /* std::cout << "mtx::identifiers - Empty matrix identifier was given" << std::endl; |
96 | */ |
97 | return {}; |
98 | } |
99 | |
100 | if (std::string(1, id.at(n: 0)) != Identifier::sigil) |
101 | throw std::invalid_argument(id + ": missing sigil " + std::string(Identifier::sigil)); |
102 | |
103 | const auto parts = id.find_first_of(c: ':'); |
104 | |
105 | // Split into localpart and server. |
106 | if (parts != std::string::npos) { |
107 | Identifier identifier{}; |
108 | identifier.localpart_ = id.substr(pos: 1, n: parts - 1); |
109 | identifier.hostname_ = id.substr(pos: parts + 1); |
110 | identifier.id_ = id; |
111 | return identifier; |
112 | } else if (Identifier::sigil == "$" ) { |
113 | // V3 event ids don't use ':' at all, don't parse them the same way. |
114 | Identifier identifier{}; |
115 | identifier.localpart_ = id; |
116 | identifier.hostname_ = id; |
117 | identifier.id_ = id; |
118 | return identifier; |
119 | } else { |
120 | throw std::invalid_argument(id + ": invalid id" ); |
121 | } |
122 | } |
123 | |
124 | } // namespace identifiers |
125 | } // namespace mtx |
126 | |