23 #include "blackboard_processor.h" 24 #include <webview/page_reply.h> 25 #include <webview/file_reply.h> 26 #include <webview/error_reply.h> 28 #include <blackboard/blackboard.h> 29 #include <interface/interface.h> 30 #include <interface/field_iterator.h> 31 #include <interface/interface_info.h> 32 #include <utils/time/time.h> 33 #include <utils/misc/string_split.h> 63 __baseurl = strdup(baseurl);
64 __baseurl_len = strlen(__baseurl);
65 __blackboard = blackboard;
73 for (__ifi = __interfaces.begin(); __ifi != __interfaces.end(); ++__ifi) {
74 __blackboard->close(__ifi->second);
83 if ( strncmp(__baseurl, request->
url().c_str(), __baseurl_len) == 0 ) {
85 std::string subpath = request->
url().substr(__baseurl_len);
87 if (subpath.find(
"/graph/graph.png") == 0) {
88 #if defined(HAVE_GRAPHVIZ) && ((defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) || defined(__clang__)) 89 std::string graph_node = request->
get_value(
"for");
90 std::string graph = generate_graph(graph_node);
95 "Cannot open temp file: %s", strerror(errno));
98 GVC_t* gvc = gvContext();
99 Agraph_t* G = agmemread((
char *)graph.c_str());
100 gvLayout(gvc, G, (
char *)
"dot");
101 gvRender(gvc, G, (
char *)
"png", f);
102 gvFreeLayout(gvc, G);
114 "BlackBoard processor was not built with Graphviz support");
120 "/static/css/jqtheme/jquery-ui.custom.css\" rel=\"stylesheet\" />\n" 121 " <link type=\"text/css\" href=\"" 122 "/static/css/blackboard.css\" rel=\"stylesheet\" />\n");
125 if (subpath.find(
"/view/") != 0 && subpath.find(
"/graph") != 0) {
126 *r +=
"\n\n<h2>Select Interface</h2>\n" 127 "<div id=\"blackboard-interfaces-mainpart\">\n";
129 *r +=
"\n\n <div id=\"blackboard-interfaces\">\n";
132 bool found_some =
false;
135 for (InterfaceInfoList::iterator i = iil->begin(); i != iil->end(); ++i) {
138 *r +=
"<tr><th>Interface</th><th>Reader(s)</th><th>Writer</th></tr>\n";
141 r->
append_body(
"<tr><td><a href=\"%s/view/%s::%s\">%s::%s</a></td><td>%u</td><td style=\"color:%s\">%s</td></tr>\n",
142 __baseurl, i->type(), i->id(), i->type(), i->id(),
143 i->num_readers(), i->has_writer() ?
"green" :
"red", i->has_writer() ? i->writer().c_str() :
"no");
152 if (subpath.find(
"/graph") != 0) {
153 r->
append_body(
" <div class=\"blackboard-graph-div\">" 154 "<a href=\"%s/graph\" class=\"blackboard-graph-link\">Graph</a></div>\n", __baseurl);
161 *r +=
"<p><b>No interfaces found.</b></p>\n";
164 if (subpath.find(
"/view/") == 0) {
165 std::string iuid = subpath.substr(subpath.find_first_not_of(
"/", std::string(
"/view/").length()));
166 std::string iftype = iuid.substr(0, iuid.find(
"::"));
167 std::string ifname = iuid.substr(iuid.find(
"::") + 2);
169 r->
append_body(
"<h2>Showing %s</h2>\n", iuid.c_str());
170 if (__interfaces.find(iuid) == __interfaces.end()) {
172 Interface *iface = __blackboard->open_for_reading(iftype.c_str(), ifname.c_str());
173 __interfaces[iuid] = iface;
178 if (__interfaces.find(iuid) != __interfaces.end()) {
220 " <tr><td><b>Type:</b></td><td>%s</td></tr>\n" 221 " <tr><td><b>ID:</b></td><td>%s</td></tr>\n" 222 " <tr><td><b>Writer:</b></td><td><span class=\"blackboard-writer-%s\">%s</span></td></tr>\n" 223 " <tr><td><b>Readers:</b></td><td>%s (%u)</td></tr>\n" 224 " <tr><td><b>Serial:</b></td><td>%u</td></tr>\n" 225 " <tr><td><b>Data size:</b></td><td>%u</td></tr>\n" 226 " <tr><td><b>Hash:</b></td><td>%s</td></tr>\n" 227 " <tr><td><b>Data changed:</b></td>" 228 "<td>%s (last at %s)</td></tr>\n" 230 iface->
type(), iface->
id(),
232 iface->
has_writer() ? writer.c_str() :
"none",
233 iface->
num_readers() > 0 ? readers.c_str() :
"none",
246 " <th>Name</th><th>Type</th><th>Value</th>\n" 249 bool is_string = (fi.get_type() ==
IFT_STRING);
251 if ( fi.get_length() > 1 ) {
252 r->
append_body(
" <td>%s</td><td>%s [%zu]</td><td>%s%s%s</td>\n",
253 fi.get_name(), fi.get_typename(),
254 fi.get_length(), is_string ?
"<pre>" :
"",
255 fi.get_value_string(), is_string ?
"</pre>" :
"");
257 r->
append_body(
" <td>%s</td><td>%s</td><td>%s%s%s</td>\n",
258 fi.get_name(), fi.get_typename(), is_string ?
"<pre>" :
"",
259 fi.get_value_string(), is_string ?
"</pre>" :
"");
264 r->
append_body(
"<p><a href=\"%s\">Clear detailed</a></p>\n", __baseurl);
266 }
else if (subpath.find(
"/graph") == 0) {
267 std::string graph_baseurl(
"/graph/");
268 std::string graph_node =
269 subpath.length() > graph_baseurl.length() ? subpath.substr(graph_baseurl.length()) :
"";
270 #if defined(HAVE_GRAPHVIZ) && ((defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) || defined(__clang__)) 271 std::string graph = generate_graph(graph_node);
273 unsigned int map_length;
275 GVC_t* gvc = gvContext();
276 Agraph_t* G = agmemread((
char *)graph.c_str());
277 gvLayout(gvc, G, (
char *)
"dot");
278 gvRenderData(gvc, G, (
char *)
"cmapx", &map, &map_length);
280 #if GRAPHVIZ_VERSION >= 23200 281 gvFreeRenderData(map);
285 gvFreeLayout(gvc, G);
289 r->
append_body(
"<p><img src=\"%s/graph/graph.png%s%s\" usemap=\"#bbmap\" /></p>\n",
291 graph_node.empty() ?
"" :
"?for=",
292 graph_node.empty() ?
"" : graph_node.c_str());
293 r->
append_body(
"<!-- DOT Graph:\n\n%s\n\n-->\n\n", graph.c_str());
295 r->
append_body(
"<p>No graphviz support at compile time</p>\n");
297 if (! graph_node.empty()) {
298 r->
append_body(
"<p><a href=\"%s/graph\">Full Graph</a></p>\n\n", __baseurl);
309 #if defined(HAVE_GRAPHVIZ) && ((defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) || defined(__clang__)) 311 WebviewBlackBoardRequestProcessor::generate_graph(std::string for_owner)
316 std::stringstream mstream;
317 mstream <<
"digraph bbmap {" << std::endl
318 <<
" graph [fontsize=12,rankdir=LR];" << std::endl;
320 std::set<std::string> owners;
322 InterfaceInfoList::iterator ii;
323 for (ii = iil->begin(); ii != iil->end(); ++ii) {
324 const std::list<std::string> readers = ii->readers();
326 if (for_owner ==
"" ||
327 ii->writer() == for_owner ||
328 std::find_if(readers.begin(), readers.end(),
329 [&for_owner](
const std::string &o)->
bool {
return for_owner == o; })
332 if (ii->has_writer()) {
333 const std::string writer = ii->writer();
334 if (! writer.empty()) owners.insert(writer);
336 std::list<std::string>::const_iterator r;
337 for (r = readers.begin(); r != readers.end(); ++r) {
343 mstream <<
" node [fontsize=12 shape=box width=4 margin=0.05];" << std::endl
344 <<
" { rank=same; " << std::endl;
345 std::set<std::string>::iterator i;
346 for (ii = iil->begin(); ii != iil->end(); ++ii) {
347 const std::list<std::string> readers = ii->readers();
348 if (for_owner ==
"" ||
349 ii->writer() == for_owner ||
350 std::find_if(readers.begin(), readers.end(),
351 [&for_owner](
const std::string &o)->
bool {
return for_owner == o; })
354 mstream <<
" \"" << ii->type() <<
"::" << ii->id() <<
"\"" 355 <<
" [href=\"" << __baseurl <<
"/view/" << ii->type() <<
"::" << ii->id() <<
"\"";
358 if (! ii->has_writer()) {
359 mstream <<
" color=red";
360 }
else if (ii->writer().empty()) {
361 mstream <<
" color=purple";
363 mstream <<
"];" << std::endl;
366 mstream <<
" }" << std::endl;
368 mstream <<
" node [fontsize=12 shape=octagon width=3];" << std::endl;
369 for (i = owners.begin(); i != owners.end(); ++i) {
370 mstream <<
" \"" << *i <<
"\"" 371 <<
" [href=\"" << __baseurl <<
"/graph/" << *i <<
"\"];" 375 for (ii = iil->begin(); ii != iil->end(); ++ii) {
376 const std::list<std::string> readers = ii->readers();
377 if (for_owner ==
"" ||
378 ii->writer() == for_owner ||
379 std::find_if(readers.begin(), readers.end(),
380 [&for_owner](
const std::string &o)->
bool {
return for_owner == o; })
383 std::list<std::string> quoted_readers;
384 std::for_each(readers.begin(), readers.end(),
385 ["ed_readers](
const std::string &r) {
386 quoted_readers.push_back(std::string(
"\"")+r+
"\"");
388 std::string quoted_readers_s =
str_join(quoted_readers,
' ');
389 mstream <<
" \"" << ii->type() <<
"::" << ii->id() <<
"\" -> { " 390 << quoted_readers_s <<
" } [style=dashed arrowhead=dot arrowsize=0.5 dir=both];" << std::endl;
392 if (ii->has_writer()) {
393 mstream <<
" \"" << (ii->writer().empty() ?
"???" : ii->writer()) <<
"\" -> \"" 394 << ii->type() <<
"::" << ii->id() <<
"\"" 395 << (ii->writer().empty() ?
" [color=purple]" :
" [color=\"#008800\"]")
404 return mstream.str();
Interface field iterator.
std::string writer() const
Get owner name of writing interface instance.
unsigned int datasize() const
Get data size.
const char * str(bool utc=false) const
Output function.
Dynamic raw file transfer reply.
virtual ~WebviewBlackBoardRequestProcessor()
Destructor.
Fawkes library namespace.
WebviewBlackBoardRequestProcessor(const char *baseurl, fawkes::BlackBoard *blackboard)
Constructor.
const char * id() const
Get identifier of interface.
virtual const char * what() const
Get primary string.
Base class for all Fawkes BlackBoard interfaces.
virtual fawkes::WebReply * process_request(const fawkes::WebRequest *request)
Process a request.
Interface information list.
const char * type() const
Get type of interface.
Base class for exceptions in Fawkes.
unsigned short serial() const
Get instance serial of interface.
void read()
Read from BlackBoard into local copy.
std::string get_value(std::string &key) const
Get specific GET value.
static std::string str_join(const std::vector< std::string > &v, char delim='/')
Join vector of strings string using given delimiter.
bool has_writer() const
Check if there is a writer for the interface.
iterator begin()
Get iterator for messages.
Web request meta data carrier.
const Time * timestamp() const
Get timestamp of last write.
bool changed() const
Check if data has been changed.
InterfaceFieldIterator fields_end()
Invalid iterator.
void append_body(const char *format,...)
Append to body.
const std::string & url() const
Get URL.
unsigned int num_readers() const
Get the number of readers.
The BlackBoard abstract class.
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
std::list< std::string > readers() const
Get owner names of reading interface instances.
const char * hash_printable() const
Get printable interface hash.