Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./modules/dds_conf.h"
25 : :
26 : : #include <map>
27 : : #include <memory>
28 : : #include <string>
29 : : #include <vector>
30 : :
31 : : #include "./base/helpers.h"
32 : : #include "./base/logger.h"
33 : : #include "./dds_client_impl.h"
34 : : #include "./dds_getter_impl.h"
35 : : #include "./dds_publisher_impl.h"
36 : : #include "./dds_server_impl.h"
37 : : #include "./dds_setter_impl.h"
38 : : #include "./dds_subscriber_impl.h"
39 : : #include "./impl/conf_plugin_interface.h"
40 : : #include "./impl/url.h"
41 : : #include "./impl/url_parser.h"
42 : :
43 : : namespace vlink {
44 : :
45 : : VLINK_DEFINE_GLOBAL_PROPERTY(DdsConf)
46 : :
47 : : std::map<std::string, Function<void*()>> DdsConf::type_support_map_;
48 : : std::map<std::string, Qos> DdsConf::qos_map_;
49 : : std::shared_mutex DdsConf::mtx_;
50 : :
51 : : // DdsConf
52 : 5 : std::vector<std::tuple<std::string, std::string>> DdsConf::get_discovered_topics(int32_t _domain) {
53 : 5 : return DdsFactory::get_discovered_topics(_domain);
54 : : }
55 : :
56 : 2 : bool DdsConf::load_global_qos_file(const std::string& filepath) { return DdsFactory::load_global_qos_file(filepath); }
57 : :
58 : 36 : void DdsConf::register_qos(const std::string& name, const Qos& qos) {
59 [ + - ]: 36 : std::lock_guard lock(mtx_);
60 : :
61 [ + - + + : 36 : if VUNLIKELY (qos_map_.find(name) != qos_map_.end() || name == "part" || name == "topic" || name == "pub" ||
- + + + -
+ + + - +
+ + - + +
+ - + + +
- + + + +
+ + + ]
62 : : name == "sub" || name == "writer" || name == "reader" || name == "depth") {
63 [ + - - + ]: 4 : VLOG_F("DdsConf: Invalid qos name: '", name, "' (reserved or already registered).");
64 : : }
65 : :
66 [ + - ]: 34 : register_qos_internal(name, qos);
67 : 36 : }
68 : :
69 : 242 : void DdsConf::register_qos_internal(const std::string& name, const Qos& qos) { qos_map_[name] = qos; }
70 : :
71 : 303 : Function<void*()> DdsConf::find_type_support(const std::string& name) {
72 [ + - ]: 303 : std::shared_lock lock(mtx_);
73 [ + - ]: 303 : auto iter = type_support_map_.find(name);
74 : :
75 [ - + ]: 303 : if (iter != type_support_map_.end()) {
76 [ # # ]: 0 : return iter->second;
77 : : }
78 : :
79 : 303 : return nullptr;
80 : 303 : }
81 : :
82 : 44 : const Qos& DdsConf::find_qos(const std::string& name) {
83 [ + - ]: 44 : std::shared_lock lock(mtx_);
84 : :
85 [ + - ]: 44 : auto iter = qos_map_.find(name);
86 : :
87 [ + + ]: 44 : if VUNLIKELY (iter == qos_map_.end()) {
88 [ + - + - ]: 2 : CLOG_E("DdsConf: Invalid qos [%s].", name.c_str());
89 : : static Qos invalid_qos;
90 : 1 : return invalid_qos;
91 : : }
92 : :
93 : 43 : return iter->second;
94 : 44 : }
95 : :
96 : 0 : std::string DdsConf::get_topic_for_url(const std::string& url) {
97 [ # # ]: 0 : UrlParser parser(url);
98 : :
99 [ # # # # ]: 0 : if VUNLIKELY (parser.get_host().empty()) {
100 [ # # ]: 0 : return "";
101 : : }
102 : :
103 [ # # # # : 0 : return parser.get_host() + (parser.get_path().empty() ? "" : "/" + parser.get_path());
# # # # #
# # # # #
# # # # ]
104 : 0 : }
105 : :
106 : 1 : void DdsConf::global_init() { DdsFactory::get(); }
107 : :
108 : 138 : bool DdsConf::parse_protocol(struct Protocol* protocol) {
109 [ - + ]: 138 : if VUNLIKELY (get_impl_type() == kUnknownImplType) {
110 [ # # # # ]: 0 : VLOG_F("DdsConf: Unknown node type, cannot parse protocol.");
111 : :
112 : 0 : return false;
113 : : }
114 : :
115 [ + + ]: 138 : if VUNLIKELY (protocol->host.empty()) {
116 : 4 : return false;
117 : : }
118 : :
119 [ + + + - : 134 : static int default_domain_id = DdsFactory::get_default_domain_id();
+ - - - ]
120 : :
121 [ + + + - : 134 : topic = protocol->host + (protocol->path.empty() ? "" : "/" + protocol->path);
+ - + - +
+ - - ]
122 [ + - + - ]: 134 : domain = Helpers::to_int(protocol->dictionary["domain"], default_domain_id);
123 [ + - + - ]: 134 : depth = Helpers::to_int(protocol->dictionary["depth"]);
124 [ + - + - : 134 : qos = protocol->dictionary["qos"];
+ - ]
125 : 134 : qos_ext = protocol->dictionary;
126 [ + - + - ]: 134 : qos_ext.erase("domain");
127 [ + - + - ]: 134 : qos_ext.erase("depth");
128 [ + - + - ]: 134 : qos_ext.erase("qos");
129 : :
130 [ + + ]: 147 : for (const auto& [key, value] : qos_ext) {
131 [ + + + + : 13 : if VUNLIKELY (key != "part" && key != "topic" && key != "pub" && key != "sub" && key != "writer" &&
+ + + + +
+ + + + +
+ + + + +
+ + + ]
132 : : key != "reader") {
133 [ + - + - ]: 2 : VLOG_W("DdsConf: Unknown qos key: ", key, ".");
134 : : }
135 : : }
136 : :
137 : 134 : return true;
138 : : }
139 : :
140 : 286 : bool DdsConf::is_valid() const {
141 [ + + + + : 286 : if VUNLIKELY (domain < 0 || topic.empty()) {
+ + ]
142 : 4 : return false;
143 : : }
144 : :
145 [ + + + + : 282 : if VUNLIKELY (!qos.empty() && !qos_ext.empty()) {
+ + ]
146 : 2 : return false;
147 : : }
148 : :
149 : 280 : return true;
150 : : }
151 : :
152 : 37 : std::unique_ptr<ServerImpl> DdsConf::create_server() const { return std::make_unique<DdsServerImpl>(*this); }
153 : :
154 : 35 : std::unique_ptr<ClientImpl> DdsConf::create_client() const { return std::make_unique<DdsClientImpl>(*this); }
155 : :
156 : 82 : std::unique_ptr<PublisherImpl> DdsConf::create_publisher() const { return std::make_unique<DdsPublisherImpl>(*this); }
157 : :
158 : 73 : std::unique_ptr<SubscriberImpl> DdsConf::create_subscriber() const {
159 : 73 : return std::make_unique<DdsSubscriberImpl>(*this);
160 : : }
161 : :
162 : 24 : std::unique_ptr<SetterImpl> DdsConf::create_setter() const { return std::make_unique<DdsSetterImpl>(*this); }
163 : :
164 : 27 : std::unique_ptr<GetterImpl> DdsConf::create_getter() const { return std::make_unique<DdsGetterImpl>(*this); }
165 : :
166 : 1 : std::ostream& operator<<(std::ostream& ostream, const Conf::PropertiesMap& qos) noexcept {
167 : 1 : std::ios_base::fmtflags f = ostream.flags();
168 : :
169 [ + + ]: 3 : for (const auto& [key, value] : qos) {
170 : 2 : ostream << "(" << key << ")" << value;
171 : : }
172 : :
173 : 1 : ostream.flags(f);
174 : :
175 : 1 : return ostream;
176 : : }
177 : :
178 : 1 : std::ostream& operator<<(std::ostream& ostream, const DdsConf& conf) noexcept {
179 : 1 : std::ios_base::fmtflags f = ostream.flags();
180 : :
181 : : ostream << "DdsConf:"
182 : 1 : << "[type]" << +conf.get_impl_type() << "[topic]" << conf.topic << "[domain]" << conf.domain << "[depth]"
183 : 1 : << conf.depth << "[qos]" << conf.qos << "[qos_ext]" << conf.qos_ext;
184 : :
185 : 1 : ostream.flags(f);
186 : :
187 : 1 : return ostream;
188 : : }
189 : :
190 : : class ConfPluginDds : public ConfPluginInterface {
191 : : protected:
192 : 0 : TransportType get_transport_type() const override { return TransportType::kDds; }
193 : :
194 : 0 : std::unique_ptr<Conf> create() const override { return std::make_unique<DdsConf>(); }
195 : : };
196 : :
197 : : #ifdef VLINK_LIBRARY
198 [ # # # # : 0 : VLINK_PLUGIN_DECLARE(ConfPluginDds, 1, 0)
# # # # #
# ]
199 : : #endif
200 : :
201 : : } // namespace vlink
|