145 deployment_(deployment),
146 resolution_(resolution),
148 filter_(params.filter),
149 view_(deployment, resolution, filter_, params.omit_disconnected),
150 indexer_(deployment.indexer)
158 std::string node_name(
const Endpoint& at,
const std::string& thread)
const
165 void open_cluster(
const std::string& indent,
const std::string& name,
const std::string& color)
167 os_ << indent.substr(1) <<
"subgraph cluster_" << cluster_++ <<
" {\n";
168 os_ << indent <<
"label=<<b>" <<
html_escaped(name) <<
"</b>>\n";
169 os_ << indent <<
"fontcolor=\"" << color <<
"\"\n";
170 os_ << indent <<
"penwidth=2\n";
171 os_ << indent <<
"pencolor=\"" << color << box_transparency_ <<
"\"\n";
174 std::string edge(
const PubSubEntry& pub,
const std::string& pub_node,
175 const std::string& sub_node,
const std::string& color,
178 pubs_in_use_[pub_node][pub.layer].emplace(pub.publish_index, pub);
180 std::string edge_style;
184 edge_style = dynamic ?
"\"bold,dashed\"" :
"bold";
187 edge_style = dynamic ?
"dashed" :
"tapered";
190 edge_style = dynamic ?
"dashed" :
"solid";
194 edge_style =
"dotted";
196 auto label = pub.publish_index_str();
197 auto tooltip =
dot_quoted(label +
": " + pub.display_group() +
" | " + pub.scheme +
" | " +
198 pub.type + (dynamic ?
" [dynamic]" :
""));
199 return pub_node +
"->" + sub_node +
"[fontsize=7,headlabel=\"" + label +
"\",taillabel=\"" +
200 label +
"\",xlabel=<" + label +
"[" +
202 color +
"\",style=" + edge_style +
",tooltip=\"" + tooltip +
"\",labeltooltip=\"" +
203 tooltip +
"\",headtooltip=\"" + tooltip +
204 "\",penwidth=0.5,arrowhead=vee,arrowsize=0.3]\n";
207 void connection(
const std::string& indent,
const Connection& c)
210 << edge(c.pub, node_name(c.pub_at, c.pub.thread), node_name(c.sub_at, c.sub.thread),
212 c.pub.dynamic || c.sub.dynamic || c.loose);
215 void unsubscribed(
const std::string& indent,
const Unmatched& u)
218 auto node = node_name(u.at, u.entry.thread);
219 auto placeholder = node +
"_no_subscribers_" +
dot_id(color);
220 os_ << indent << placeholder <<
" [label=\"\",style=invis] \n"
225 void unpublished(
const std::string& indent,
const Unmatched& u)
229 auto node = node_name(u.at, u.entry.thread);
230 auto placeholder = node +
"_no_publishers_" +
dot_id(color);
232 node_threads_[placeholder] =
nullptr;
233 PubSubEntry fake_pub = u.entry;
235 fake_pub.publish_index = indexer_.
next(fake_pub.layer);
237 os_ << indent << placeholder <<
" \n"
238 << edge(fake_pub, placeholder, node, color, u.entry.necessity, u.entry.is_regex,
242 void connections_from(
const std::string& indent,
Layer layer,
243 const std::function<
bool(
const Endpoint&)>& at)
245 for (
const auto& c : resolution_.connections)
247 if (c.pub.layer == layer && at(c.pub_at) && view_.
drawn(c))
248 connection(indent, c);
250 for (
const auto& u : resolution_.unsubscribed)
253 unsubscribed(indent, u);
257 void unpublished_in(
const std::string& indent,
Layer layer,
258 const std::function<
bool(
const Endpoint&)>& at)
260 std::vector<const Unmatched*> subs;
261 for (
const auto& u : resolution_.unpublished)
266 std::stable_sort(subs.begin(), subs.end(),
267 [](
const Unmatched* a,
const Unmatched* b)
269 auto key = [](const Unmatched* u) {
270 return std::make_tuple(u->at.platform->name, u->at.module->name,
271 u->at.application->name);
273 if (key(a) != key(b))
274 return key(a) < key(b);
275 return a->entry < b->entry;
277 for (
const auto* u : subs) unpublished(indent, *u);
280 void write_node_labels();
283 std::string pub_key(
const std::string& node)
286 for (
const auto& layer_p : pubs_in_use_[node])
288 for (
const auto& index_pub_p : layer_p.second)
290 const auto& pub = index_pub_p.second;
292 "\" point-size=\"10\">" + pub.publish_index_str() +
293 ": </font><b><font point-size=\"10\">" +
html_escaped(pub.display_group()) +
294 "</font></b><br/><font point-size=\"6\">" +
html_escaped(pub.scheme) +
295 "</font><br/><font point-size=\"8\">" +
304 const Deployment& deployment_;
305 const Resolution& resolution_;
306 const DotParams& params_;
309 PublishIndexer indexer_;
311 const std::string box_transparency_{
"20"};
314 std::map<std::string, const Thread*> node_threads_;
316 std::map<std::string, const Application*> node_apps_;
318 std::map<std::string, std::map<Layer, std::map<int, PubSubEntry>>> pubs_in_use_;
321inline void DotWriter::write()
323 os_ <<
"digraph " <<
dot_id(deployment_.name) <<
" { \n";
324 os_ <<
"\tsplines=" << params_.splines <<
"\n";
325 os_ <<
"\tnewrank=true\n";
327 for (
const auto& platform : deployment_.platforms)
329 if (!filter_.is_node_included(platform.name))
332 platform.has_modules()
334 : view_.container_label(platform.name, platform.modules.front()),
337 for (
const auto& module : platform.modules)
339 if (platform.has_modules())
341 if (!filter_.is_node_included(module.name))
343 open_cluster(
"\t\t", view_.container_label(module.name, module),
347 for (
const auto& app_p :
module.applications)
349 const auto& app = app_p.second;
350 if (!filter_.is_node_included(app.name) || view_.folded(app))
352 if (view_.collapsed(app))
354 auto node = node_name({&platform, &module, &app,
nullptr},
"");
355 node_apps_[node] = &app;
356 os_ <<
"\t\t\t" << node <<
"\n";
363 for (
const auto& thread_p : app.threads)
365 const auto& thread = *thread_p.second;
366 if (!view_.thread_drawn(app, thread))
372 Endpoint at{&platform, &module, &app, &thread};
373 auto node = node_name(at, thread.most_derived_name());
374 node_threads_[node] = &thread;
376 << box_transparency_ <<
"\"]\n";
390 if (platform.has_modules())