Commit b7e72f8377b98b38707bac5ad60bb7dfa48368cf

Authored by Jürgen Knödlseder
1 parent 9b7e303f

Refactor code of GVOHub a bit.

ChangeLog
1 -2016-02-18 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> 1 +2016-02-23 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2
3 * Version 1.1.0 released 3 * Version 1.1.0 released
4 ========================= 4 =========================
5 5
  6 + Add GVOClient::publish() method to publish a FITS HDU (#1231)
6 Handle FITS extensions in GSkyMap load() and save() methods (#1695) 7 Handle FITS extensions in GSkyMap load() and save() methods (#1695)
7 Restrict Monte Carlo simulations in GModelSpatialDiffuseConst to simulation cone (#1674) 8 Restrict Monte Carlo simulations in GModelSpatialDiffuseConst to simulation cone (#1674)
8 Use default GTime in GModelSpectral eval() and eval_gradients() methods (#1672) 9 Use default GTime in GModelSpectral eval() and eval_gradients() methods (#1672)
@@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 1.1.0 @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 1.1.0
2 2
3 Author(s) : Juergen Knoedlseder 3 Author(s) : Juergen Knoedlseder
4 4
5 -18 February 2016 5 +23 February 2016
6 6
7 7
8 1. Introduction 8 1. Introduction
@@ -178,7 +178,9 @@ None @@ -178,7 +178,9 @@ None
178 178
179 15. VO module 179 15. VO module
180 ------------- 180 -------------
181 -None 181 +A GVOClient::publish() method was added that allows publishing of a FITS
  182 +image to the Hub. The FITS image will be saved into a temporary storage
  183 +location and the Hub will be informed that an image is available.
182 184
183 185
184 16. Xspec module 186 16. Xspec module
include/GVOClient.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GVOClient.hpp - VO client class * 2 * GVOClient.hpp - VO client class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2013-2016 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -30,9 +30,12 @@ @@ -30,9 +30,12 @@
30 /* __ Includes ___________________________________________________________ */ 30 /* __ Includes ___________________________________________________________ */
31 #include <string> 31 #include <string>
32 #include "GBase.hpp" 32 #include "GBase.hpp"
33 -#include "GXml.hpp"  
34 -#include "GXmlNode.hpp"  
35 -#include "GFits.hpp" 33 +
  34 +/* __ Forward declarations _______________________________________________ */
  35 +class GFitsHDU;
  36 +class GXml;
  37 +class GXmlNode;
  38 +
36 39
37 /***********************************************************************//** 40 /***********************************************************************//**
38 * @class GVOClient 41 * @class GVOClient
include/GVOHub.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GVOHub.hpp - VO SAMP Hub class * 2 * GVOHub.hpp - VO SAMP Hub class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2014-2015 by Thierry Louge * 4 + * copyright (C) 2014-2016 by Thierry Louge *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -34,8 +34,10 @@ @@ -34,8 +34,10 @@
34 #include <vector> 34 #include <vector>
35 #include <sys/socket.h> 35 #include <sys/socket.h>
36 #include "GBase.hpp" 36 #include "GBase.hpp"
37 -#include "GXml.hpp"  
38 -#include "GXmlNode.hpp" 37 +
  38 +/* __ Forward declarations _______________________________________________ */
  39 +class GXml;
  40 +class GXmlNode;
39 41
40 42
41 /***********************************************************************//** 43 /***********************************************************************//**
@@ -73,29 +75,31 @@ protected: @@ -73,29 +75,31 @@ protected:
73 void start_hub(void); 75 void start_hub(void);
74 void handle_request(const socklen_t& sock); 76 void handle_request(const socklen_t& sock);
75 void request_ping(const socklen_t& sock); 77 void request_ping(const socklen_t& sock);
76 - void request_register(const GXml& xml, 78 + void request_register(const GXml& xml,
77 const socklen_t& sock); 79 const socklen_t& sock);
78 - void request_unregister(const GXml& xml, 80 + void request_unregister(const GXml& xml,
79 const socklen_t& sock); 81 const socklen_t& sock);
80 - void request_declare_metadata(const GXml& xml, 82 + void request_declare_metadata(const GXml& xml,
81 const socklen_t& sock); 83 const socklen_t& sock);
82 - void request_declare_subscriptions(const GXml& xml, 84 + void request_declare_subscriptions(const GXml& xml,
83 const socklen_t& sock); 85 const socklen_t& sock);
84 - void request_set_xml_rpc_callback(const GXml& xml, 86 + void request_set_xml_rpc_callback(const GXml& xml,
85 const socklen_t& sock); 87 const socklen_t& sock);
86 - void request_get_subscriptions(const GXml& xml, 88 + void request_get_subscriptions(const GXml& xml,
87 const socklen_t& sock); 89 const socklen_t& sock);
88 - void request_get_registered_clients(const GXml& xml, 90 + void request_get_registered_clients(const GXml& xml,
89 const socklen_t& sock); 91 const socklen_t& sock);
90 - void request_get_subscribed_clients(const GXml& xml, 92 + void request_get_subscribed_clients(const GXml& xml,
91 const socklen_t& sock); 93 const socklen_t& sock);
92 - void request_get_metadata(const GXml& xml, 94 + void request_get_metadata(const GXml& xml,
93 const socklen_t& sock); 95 const socklen_t& sock);
  96 + void request_notify_all(const GXml& xml,
  97 + const socklen_t& sock);
94 void request_shutdown(const socklen_t& sock); 98 void request_shutdown(const socklen_t& sock);
95 std::string get_client_key(const GXml& xml) const; 99 std::string get_client_key(const GXml& xml) const;
96 int get_client_index(const GXml& xml) const; 100 int get_client_index(const GXml& xml) const;
97 int get_client_index(const std::string& reference) const; 101 int get_client_index(const std::string& reference) const;
98 - std::string get_response_value(const GXml& xml, 102 + std::string get_response_value(const GXmlNode* node,
99 const std::string& name) const; 103 const std::string& name) const;
100 void get_name_value_pair(const GXmlNode* node, 104 void get_name_value_pair(const GXmlNode* node,
101 std::string& name, 105 std::string& name,
@@ -103,24 +107,10 @@ protected: @@ -103,24 +107,10 @@ protected:
103 std::vector<std::string> get_subscriptions(const GXml& xml) const; 107 std::vector<std::string> get_subscriptions(const GXml& xml) const;
104 std::string get_callback_url(const GXml& xml) const; 108 std::string get_callback_url(const GXml& xml) const;
105 std::string get_hub_lockfile(void) const; 109 std::string get_hub_lockfile(void) const;
106 - void send_notifications(const std::string& method,  
107 - const std::string& client);  
108 - void send_notifications(const std::string& method,  
109 - const std::string& client,  
110 - const GXml& xml);  
111 - void broadcast(const GXml& xml, const socklen_t& sock);  
112 std::string get_mtype(const GXml& xml) const; 110 std::string get_mtype(const GXml& xml) const;
113 std::string get_destination(const GXml& xml) const; 111 std::string get_destination(const GXml& xml) const;
114 112
115 - // Low-level methods  
116 - void create_samp_file(void) const;  
117 - void post_samp_ok(const socklen_t& sock) const;  
118 - void post_samp_void(const socklen_t& sock) const;  
119 - void post_string(const std::string& content, const socklen_t& sock) const;  
120 - void notify(const std::string& url, const std::string& notification) const;  
121 - std::string random_string(const size_t& length) const;  
122 -  
123 - // Protected structure 113 + // Client structure
124 struct client { 114 struct client {
125 std::string name; 115 std::string name;
126 std::string private_key; 116 std::string private_key;
@@ -136,6 +126,24 @@ protected: @@ -136,6 +126,24 @@ protected:
136 std::vector<std::string> subscriptions; 126 std::vector<std::string> subscriptions;
137 }; 127 };
138 128
  129 + // Low-level methods
  130 + void create_samp_file(void) const;
  131 + void post_samp_ok(const socklen_t& sock) const;
  132 + void post_samp_void(const socklen_t& sock) const;
  133 + void post_string(const std::string& content,
  134 + const socklen_t& sock) const;
  135 + void notify(const std::string& url,
  136 + const std::string& notification) const;
  137 + void notify_register(const client& client,
  138 + const std::string& reference);
  139 + void notify_unregister(const client& client,
  140 + const std::string& reference);
  141 + void notify_metadata(const client& client,
  142 + const std::string& reference);
  143 + void notify_image_load(const client& client,
  144 + const GXml& xml);
  145 + std::string random_string(const size_t& length) const;
  146 +
139 // Protected members 147 // Protected members
140 std::string m_secret; //!< Secret Hub key 148 std::string m_secret; //!< Secret Hub key
141 std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub 149 std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub
src/vo/GVOClient.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GVOClient.cpp - VO client class * 2 * GVOClient.cpp - VO client class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2013-2016 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -35,10 +35,13 @@ @@ -35,10 +35,13 @@
35 #include <netdb.h> // getaddrinfo() function 35 #include <netdb.h> // getaddrinfo() function
36 #include <sys/socket.h> // socket(), connect() functions 36 #include <sys/socket.h> // socket(), connect() functions
37 #include <fstream> 37 #include <fstream>
  38 +#include "GTools.hpp"
  39 +#include "GException.hpp"
  40 +#include "GXml.hpp"
  41 +#include "GXmlNode.hpp"
  42 +#include "GFits.hpp"
38 #include "GVOClient.hpp" 43 #include "GVOClient.hpp"
39 #include "GVOHub.hpp" 44 #include "GVOHub.hpp"
40 -#include "GException.hpp"  
41 -#include "GTools.hpp"  
42 45
43 /* __ Method name definitions ____________________________________________ */ 46 /* __ Method name definitions ____________________________________________ */
44 #define G_FIND_HUB "GVOClient::find_hub()" 47 #define G_FIND_HUB "GVOClient::find_hub()"
@@ -368,33 +371,54 @@ GXml GVOClient::execute(const std::string&amp; request) const @@ -368,33 +371,54 @@ GXml GVOClient::execute(const std::string&amp; request) const
368 ***************************************************************************/ 371 ***************************************************************************/
369 void GVOClient::publish(const GFitsHDU& hdu) 372 void GVOClient::publish(const GFitsHDU& hdu)
370 { 373 {
  374 + // Signal that client should be disconnected after sending the image
  375 + // to Hub
  376 + bool disconnected = !is_connected();
  377 +
  378 + // Make sure that the client is connected to a Hub
  379 + if (disconnected) {
  380 + connect();
  381 + }
  382 +
371 // Save FITS HDU into a temporary file 383 // Save FITS HDU into a temporary file
372 std::string samp_share = std::tmpnam(NULL); 384 std::string samp_share = std::tmpnam(NULL);
373 GFits fits; 385 GFits fits;
374 fits.append(hdu); 386 fits.append(hdu);
375 fits.saveto(samp_share, true); 387 fits.saveto(samp_share, true);
376 388
  389 + // Get FITS extension name
  390 + std::string extname = hdu.extname();
  391 + if (extname.empty()) {
  392 + extname = "FITS Image";
  393 + }
  394 +
377 // Compose notification to be passed to the Hub 395 // Compose notification to be passed to the Hub
378 std::string hub_command = ""; 396 std::string hub_command = "";
379 hub_command.append("<?xml version=\"1.0\"?>\n"); 397 hub_command.append("<?xml version=\"1.0\"?>\n");
380 - hub_command.append("<methodCall>"); 398 + hub_command.append("<methodCall>\n");
381 hub_command.append(" <methodName>samp.hub.notifyAll</methodName>\n"); 399 hub_command.append(" <methodName>samp.hub.notifyAll</methodName>\n");
382 hub_command.append(" <params>\n"); 400 hub_command.append(" <params>\n");
383 hub_command.append(" <param><value>image.load.fits</value></param>\n"); 401 hub_command.append(" <param><value>image.load.fits</value></param>\n");
384 hub_command.append(" <param><value>"+m_secret+"</value></param>\n"); 402 hub_command.append(" <param><value>"+m_secret+"</value></param>\n");
385 hub_command.append(" <param><value><struct>\n"); 403 hub_command.append(" <param><value><struct>\n");
386 hub_command.append(" <member><name>samp.params</name><value><struct>\n"); 404 hub_command.append(" <member><name>samp.params</name><value><struct>\n");
387 - hub_command.append(" <member><name>name</name><value>Gammalib_FITS_FILE</value></member>\n"); 405 + hub_command.append(" <member><name>name</name><value>"+extname+"</value></member>\n");
388 hub_command.append(" <member><name>url</name><value>file://localhost"+samp_share+"</value></member>\n"); 406 hub_command.append(" <member><name>url</name><value>file://localhost"+samp_share+"</value></member>\n");
389 hub_command.append(" <member><name>image-id</name><value>Gammalib Data</value></member>\n"); 407 hub_command.append(" <member><name>image-id</name><value>Gammalib Data</value></member>\n");
390 hub_command.append(" </struct></value></member>\n"); 408 hub_command.append(" </struct></value></member>\n");
391 hub_command.append(" <member><name>samp.mtype</name><value>image.load.fits</value></member>\n"); 409 hub_command.append(" <member><name>samp.mtype</name><value>image.load.fits</value></member>\n");
392 hub_command.append(" </struct></value></param>\n"); 410 hub_command.append(" </struct></value></param>\n");
393 - hub_command.append(" </params>\n</methodCall>\n"); 411 + hub_command.append(" </params>\n");
  412 + hub_command.append("</methodCall>\n");
394 413
395 // Send notification 414 // Send notification
396 execute(hub_command); 415 execute(hub_command);
397 416
  417 + // Disconnect client from Hub
  418 + if (disconnected) {
  419 + disconnect();
  420 + }
  421 +
398 // Return 422 // Return
399 return; 423 return;
400 } 424 }
src/vo/GVOHub.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GVOHub.cpp - VO SAMP Hub class * 2 * GVOHub.cpp - VO SAMP Hub class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2014-2015 by Thierry Louge * 4 + * copyright (C) 2014-2016 by Thierry Louge *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -41,9 +41,11 @@ @@ -41,9 +41,11 @@
41 #include <sys/socket.h> // socket(), connect() functions 41 #include <sys/socket.h> // socket(), connect() functions
42 #include <sys/wait.h> // waitpid() function 42 #include <sys/wait.h> // waitpid() function
43 #include <arpa/inet.h> // inet_addr() function 43 #include <arpa/inet.h> // inet_addr() function
44 -#include "GVOHub.hpp"  
45 -#include "GException.hpp"  
46 #include "GTools.hpp" 44 #include "GTools.hpp"
  45 +#include "GException.hpp"
  46 +#include "GXml.hpp"
  47 +#include "GXmlNode.hpp"
  48 +#include "GVOHub.hpp"
47 49
48 /* __ Method name definitions ____________________________________________ */ 50 /* __ Method name definitions ____________________________________________ */
49 #define G_START_HUB "GVOHub::start_hub()" 51 #define G_START_HUB "GVOHub::start_hub()"
@@ -54,6 +56,7 @@ @@ -54,6 +56,7 @@
54 56
55 /* __ Debug definitions __________________________________________________ */ 57 /* __ Debug definitions __________________________________________________ */
56 #define G_CONSOLE_DUMP 58 #define G_CONSOLE_DUMP
  59 +#define G_CONSOLE_ERRORS
57 #define G_SHOW_MESSAGE 60 #define G_SHOW_MESSAGE
58 61
59 62
@@ -429,7 +432,7 @@ void GVOHub::handle_request(const socklen_t&amp; sock) @@ -429,7 +432,7 @@ void GVOHub::handle_request(const socklen_t&amp; sock)
429 #endif 432 #endif
430 433
431 // Extract response into an XML object 434 // Extract response into an XML object
432 - GXml xml; 435 + GXml xml;
433 436
434 size_t start = message.find("<?xml"); 437 size_t start = message.find("<?xml");
435 if (start != std::string::npos) { 438 if (start != std::string::npos) {
@@ -446,9 +449,10 @@ void GVOHub::handle_request(const socklen_t&amp; sock) @@ -446,9 +449,10 @@ void GVOHub::handle_request(const socklen_t&amp; sock)
446 } 449 }
447 } 450 }
448 451
449 - // Dump the buffer 452 + // Dump the method that is called
450 #if defined(G_CONSOLE_DUMP) 453 #if defined(G_CONSOLE_DUMP)
451 - std::cout << "Method called: " << method_called << std::endl; 454 + std::cout << "GVOHub has received the message type \"";
  455 + std::cout << method_called << "\"" << std::endl;
452 #endif 456 #endif
453 457
454 // Dispatch according to method 458 // Dispatch according to method
@@ -489,11 +493,7 @@ void GVOHub::handle_request(const socklen_t&amp; sock) @@ -489,11 +493,7 @@ void GVOHub::handle_request(const socklen_t&amp; sock)
489 request_ping(sock); 493 request_ping(sock);
490 } 494 }
491 else if (method_called.compare("samp.hub.notifyAll") == 0) { 495 else if (method_called.compare("samp.hub.notifyAll") == 0) {
492 - #if defined(G_CONSOLE_DUMP)  
493 - std::cout << "==========================================" << std::endl;  
494 - std::cout << "samp.hub.notifyAll" << std::endl;  
495 - #endif  
496 - broadcast(xml, sock); 496 + request_notify_all(xml, sock);
497 } 497 }
498 else if (method_called.compare("samp.hub.call") == 0) { 498 else if (method_called.compare("samp.hub.call") == 0) {
499 request_ping(sock); 499 request_ping(sock);
@@ -613,10 +613,17 @@ void GVOHub::request_register(const GXml&amp; xml, const socklen_t&amp; sock) @@ -613,10 +613,17 @@ void GVOHub::request_register(const GXml&amp; xml, const socklen_t&amp; sock)
613 // Post response 613 // Post response
614 post_string(response, sock); 614 post_string(response, sock);
615 615
616 - // Send notifications  
617 - send_notifications("samp.hub.event.register", voclient.reference); 616 + // Notify all clients about the registering
  617 + for (int i = 0; i < m_clients.size(); ++i) {
  618 + for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
  619 + if ("samp.hub.event.register" == m_clients[i].subscriptions[j]) {
  620 + notify_register(m_clients[i], voclient.reference);
  621 + break;
  622 + }
  623 + }
  624 + }
618 625
619 - //Return 626 + // Return
620 return; 627 return;
621 } 628 }
622 629
@@ -645,9 +652,16 @@ void GVOHub::request_unregister(const GXml&amp; xml, const socklen_t&amp; sock) @@ -645,9 +652,16 @@ void GVOHub::request_unregister(const GXml&amp; xml, const socklen_t&amp; sock)
645 // Post void message 652 // Post void message
646 post_samp_void(sock); 653 post_samp_void(sock);
647 654
648 - // Send notifications  
649 - send_notifications("samp.hub.event.unregister",  
650 - m_clients[i].reference); 655 + // Notify all clients about the registering
  656 + for (int k = 0; k < m_clients.size(); ++k) {
  657 + if (i != k) {
  658 + for (int j = 0; j < m_clients[k].subscriptions.size(); ++j) {
  659 + if ("samp.hub.event.unregister" == m_clients[k].subscriptions[j]) {
  660 + notify_unregister(m_clients[k], m_clients[i].reference);
  661 + }
  662 + }
  663 + }
  664 + }
651 665
652 // Remove client 666 // Remove client
653 m_clients.erase(m_clients.begin()+i); 667 m_clients.erase(m_clients.begin()+i);
@@ -655,9 +669,11 @@ void GVOHub::request_unregister(const GXml&amp; xml, const socklen_t&amp; sock) @@ -655,9 +669,11 @@ void GVOHub::request_unregister(const GXml&amp; xml, const socklen_t&amp; sock)
655 } // endif: valid client found 669 } // endif: valid client found
656 670
657 // Signal if the client was unknown 671 // Signal if the client was unknown
658 - #if defined(G_CONSOLE_DUMP) 672 + #if defined(G_CONSOLE_ERRORS)
659 else { 673 else {
660 - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; 674 + std::cout << "*** ERROR: GVOHub::request_unregister: ";
  675 + std::cout << "Unable to find client \"" << get_client_key(xml);
  676 + std::cout << "\"" << std::endl;
661 } 677 }
662 #endif 678 #endif
663 679
@@ -687,28 +703,41 @@ void GVOHub::request_declare_metadata(const GXml&amp; xml, const socklen_t&amp; sock) @@ -687,28 +703,41 @@ void GVOHub::request_declare_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
687 // Continue only if index is valid 703 // Continue only if index is valid
688 if (i != -1) { 704 if (i != -1) {
689 705
  706 + // Get node
  707 + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct");
  708 +
690 // Store metadata 709 // Store metadata
691 - m_clients[i].name = get_response_value(xml, "samp.name");;  
692 - m_clients[i].description = get_response_value(xml, "samp.description.text");  
693 - m_clients[i].icon = get_response_value(xml, "samp.icon.url");  
694 - m_clients[i].documentation = get_response_value(xml, "samp.documentation.url");  
695 - m_clients[i].affiliation = get_response_value(xml, "author.affiliation");  
696 - m_clients[i].email = get_response_value(xml, "author.email");  
697 - m_clients[i].author_name = get_response_value(xml, "author.name");  
698 - m_clients[i].homepage = get_response_value(xml, "home.page"); 710 + m_clients[i].name = get_response_value(node, "samp.name");;
  711 + m_clients[i].description = get_response_value(node, "samp.description.text");
  712 + m_clients[i].icon = get_response_value(node, "samp.icon.url");
  713 + m_clients[i].documentation = get_response_value(node, "samp.documentation.url");
  714 + m_clients[i].affiliation = get_response_value(node, "author.affiliation");
  715 + m_clients[i].email = get_response_value(node, "author.email");
  716 + m_clients[i].author_name = get_response_value(node, "author.name");
  717 + m_clients[i].homepage = get_response_value(node, "home.page");
699 718
700 // Post void message 719 // Post void message
701 post_samp_void(sock); 720 post_samp_void(sock);
702 -  
703 - // Send notifications  
704 - send_notifications("samp.hub.event.metadata", m_clients[i].reference); 721 +
  722 + // Notify all clients about the registering
  723 + for (int k = 0; k < m_clients.size(); ++k) {
  724 + if (i != k) {
  725 + for (int j = 0; j < m_clients[k].subscriptions.size(); ++j) {
  726 + if ("samp.hub.event.metadata" == m_clients[k].subscriptions[j]) {
  727 + notify_metadata(m_clients[k], m_clients[i].reference);
  728 + }
  729 + }
  730 + }
  731 + }
705 732
706 } // endif: client found 733 } // endif: client found
707 734
708 // Signal if the client was unknown 735 // Signal if the client was unknown
709 - #if defined(G_CONSOLE_DUMP) 736 + #if defined(G_CONSOLE_ERRORS)
710 else { 737 else {
711 - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; 738 + std::cout << "*** ERROR: GVOHub::request_declare_metadata: ";
  739 + std::cout << "Unable to find client \"" << get_client_key(xml);
  740 + std::cout << "\"" << std::endl;
712 } 741 }
713 #endif 742 #endif
714 743
@@ -752,9 +781,11 @@ void GVOHub::request_declare_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock @@ -752,9 +781,11 @@ void GVOHub::request_declare_subscriptions(const GXml&amp; xml,const socklen_t&amp; sock
752 } // endif: valid client found 781 } // endif: valid client found
753 782
754 // Signal if the client was unknown 783 // Signal if the client was unknown
755 - #if defined(G_CONSOLE_DUMP) 784 + #if defined(G_CONSOLE_ERRORS)
756 else { 785 else {
757 - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; 786 + std::cout << "*** ERROR: GVOHub::request_declare_subscriptions: ";
  787 + std::cout << "Unable to find client \"" << get_client_key(xml);
  788 + std::cout << "\"" << std::endl;
758 } 789 }
759 #endif 790 #endif
760 791
@@ -797,9 +828,11 @@ void GVOHub::request_set_xml_rpc_callback(const GXml&amp; xml, @@ -797,9 +828,11 @@ void GVOHub::request_set_xml_rpc_callback(const GXml&amp; xml,
797 } // endif: client found 828 } // endif: client found
798 829
799 // Signal if the client was unknown 830 // Signal if the client was unknown
800 - #if defined(G_CONSOLE_DUMP) 831 + #if defined(G_CONSOLE_ERRORS)
801 else { 832 else {
802 - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; 833 + std::cout << "*** ERROR: GVOHub::request_set_xml_rpc_callback: ";
  834 + std::cout << "Unable to find client \"" << get_client_key(xml);
  835 + std::cout << "\"" << std::endl;
803 } 836 }
804 #endif 837 #endif
805 838
@@ -871,9 +904,11 @@ void GVOHub::request_get_subscriptions(const GXml&amp; xml, const socklen_t&amp; sock) @@ -871,9 +904,11 @@ void GVOHub::request_get_subscriptions(const GXml&amp; xml, const socklen_t&amp; sock)
871 } 904 }
872 905
873 // Signal if the client was unknown 906 // Signal if the client was unknown
874 - #if defined(G_CONSOLE_DUMP) 907 + #if defined(G_CONSOLE_ERRORS)
875 else { 908 else {
876 - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; 909 + std::cout << "*** ERROR: GVOHub::request_get_subscriptions: ";
  910 + std::cout << "Unable to find client \"" << get_client_key(xml);
  911 + std::cout << "\"" << std::endl;
877 } 912 }
878 #endif 913 #endif
879 914
@@ -1092,6 +1127,15 @@ void GVOHub::request_get_metadata(const GXml&amp; xml, const socklen_t&amp; sock) @@ -1092,6 +1127,15 @@ void GVOHub::request_get_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
1092 response.append(" </member>\n"); 1127 response.append(" </member>\n");
1093 1128
1094 } // endif: index was valid 1129 } // endif: index was valid
  1130 +
  1131 + // Signal if the client was unknown
  1132 + #if defined(G_CONSOLE_ERRORS)
  1133 + else {
  1134 + std::cout << "*** ERROR: GVOHub::request_get_metadata: ";
  1135 + std::cout << "Unable to find client \"" << get_client_key(xml);
  1136 + std::cout << "\"" << std::endl;
  1137 + }
  1138 + #endif
1095 1139
1096 } // endelse: client was not the hub 1140 } // endelse: client was not the hub
1097 1141
@@ -1107,52 +1151,56 @@ void GVOHub::request_get_metadata(const GXml&amp; xml, const socklen_t&amp; sock) @@ -1107,52 +1151,56 @@ void GVOHub::request_get_metadata(const GXml&amp; xml, const socklen_t&amp; sock)
1107 return; 1151 return;
1108 } 1152 }
1109 1153
  1154 +
1110 /***********************************************************************//** 1155 /***********************************************************************//**
1111 - * @brief Broadcasts a message 1156 + * @brief Handle request to notify all clients
1112 * 1157 *
1113 * @param[in] xml XML message sent by client. 1158 * @param[in] xml XML message sent by client.
1114 * @param[in] sock Socket. 1159 * @param[in] sock Socket.
1115 * 1160 *
1116 - * Broadcasts an image to every registered client. 1161 + * Handles requests to notify all clients. The method will loop over all
  1162 + * clients to check the subscriptions of each client, and send a notification
  1163 + * to all clients that are subscribed to the requested message type.
1117 ***************************************************************************/ 1164 ***************************************************************************/
1118 -void GVOHub::broadcast(const GXml& xml, const socklen_t& sock) 1165 +void GVOHub::request_notify_all(const GXml& xml, const socklen_t& sock)
1119 { 1166 {
1120 // Header 1167 // Header
1121 -  
1122 - // Get client index  
1123 - int i = get_client_index(xml);  
1124 -  
1125 - // Get message mtype  
1126 - std::string mtype = get_mtype(xml);  
1127 #if defined(G_CONSOLE_DUMP) 1168 #if defined(G_CONSOLE_DUMP)
1128 - std::cout<<"mtype is: " +mtype + " i value: " + gammalib::str(i)<<std::endl; 1169 + std::cout << "GVOHub::request_notify_all" << std::endl;
1129 #endif 1170 #endif
  1171 +
  1172 + // Get message type
  1173 + std::string mtype = get_mtype(xml);
  1174 +
  1175 + // Post void message
1130 post_samp_void(sock); 1176 post_samp_void(sock);
1131 1177
1132 - if (mtype == "image.load.fits") {  
1133 - #if defined(G_CONSOLE_DUMP)  
1134 - std::cout<<"notifying image.load.fits"<<std::endl;  
1135 - #endif 1178 + // Loop over all clients
  1179 + for (int i = 0; i < m_clients.size(); ++i) {
  1180 +
  1181 + // Loop over all subscriptions
  1182 + for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {
1136 1183
1137 - // Send notifications  
1138 - send_notifications("image.load.fits",m_clients[i].reference,xml);  
1139 - } 1184 + // Continue only if message type matches client's subscription
  1185 + if (mtype == m_clients[i].subscriptions[j]) {
  1186 +
  1187 + // Image loading
  1188 + if (mtype == "image.load.fits") {
  1189 + notify_image_load(m_clients[i], xml);
  1190 + }
1140 1191
1141 - if (mtype == "table.load.votable") { 1192 + } // endif: message type matched client subscription
1142 1193
1143 - // Send notifications  
1144 - send_notifications("table.load.votable",m_clients[i].reference,xml);  
1145 - } 1194 + } // endfor: looped over all message types
1146 1195
1147 - #if defined(G_CONSOLE_DUMP)  
1148 - std::cout<<"Returning from broadcast function"<<std::endl;  
1149 - #endif 1196 + } // endfor: looped over all clients
1150 1197
1151 // Return 1198 // Return
1152 return; 1199 return;
1153 1200
1154 } 1201 }
1155 1202
  1203 +
1156 /***********************************************************************//** 1204 /***********************************************************************//**
1157 * @brief Handles Hub shutdown requests 1205 * @brief Handles Hub shutdown requests
1158 * 1206 *
@@ -1282,24 +1330,30 @@ int GVOHub::get_client_index(const std::string&amp; reference) const @@ -1282,24 +1330,30 @@ int GVOHub::get_client_index(const std::string&amp; reference) const
1282 1330
1283 1331
1284 /***********************************************************************//** 1332 /***********************************************************************//**
1285 - * @brief Returns value for a SAMP client query parameter 1333 + * @brief Returns value for a named parameter
1286 * 1334 *
1287 - * @param[in] xml client query XML document. 1335 + * @param[in] node XML node containing the response values.
1288 * @param[in] name Parameter name. 1336 * @param[in] name Parameter name.
1289 * @return Parameter value. 1337 * @return Parameter value.
1290 * 1338 *
1291 - * Returns value for a SAMP client query parameter. If the specified  
1292 - * parameter was not found or if the response structure is not compliant,  
1293 - * an empty string is returned. 1339 + * Returns the @p value for the parameter @p name in a list of @p member
  1340 + * XML nodes with the structure
  1341 + *
  1342 + * <member>
  1343 + * <name>name</name>
  1344 + * <value>value</value>
  1345 + * </member>
  1346 + *
  1347 + * If the specified parameter @p name was not found, or the the XML @p node
  1348 + * is NULL, an empty string is returned.
1294 ***************************************************************************/ 1349 ***************************************************************************/
1295 -std::string GVOHub::get_response_value(const GXml& xml, 1350 +std::string GVOHub::get_response_value(const GXmlNode* node,
1296 const std::string& name) const 1351 const std::string& name) const
1297 { 1352 {
1298 - // Declare value 1353 + // Declare empty value
1299 std::string value = ""; 1354 std::string value = "";
1300 1355
1301 - // Get the client's private key  
1302 - const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct"); 1356 + // Search for parameter name, and if found, return its value
1303 if (node != NULL) { 1357 if (node != NULL) {
1304 int num = node->elements("member"); 1358 int num = node->elements("member");
1305 for (int i = 0; i < num; ++i) { 1359 for (int i = 0; i < num; ++i) {
@@ -1476,322 +1530,6 @@ std::string GVOHub::get_hub_lockfile(void) const @@ -1476,322 +1530,6 @@ std::string GVOHub::get_hub_lockfile(void) const
1476 1530
1477 1531
1478 /***********************************************************************//** 1532 /***********************************************************************//**
1479 - * @brief Send notifications  
1480 - *  
1481 - * @param[in] method Name of the method  
1482 - * @param[in] client Reference of the client  
1483 - *  
1484 - * Send notifications to all registered clients that request so.  
1485 - ***************************************************************************/  
1486 -void GVOHub::send_notifications(const std::string& method,  
1487 - const std::string& client)  
1488 -{  
1489 - #if defined(G_CONSOLE_DUMP)  
1490 - std::cout << "GVOHub::send_notifications 1st form" << std::endl;  
1491 - #endif  
1492 - // Loop over all clients  
1493 - for (int i = 0; i < m_clients.size(); ++i) {  
1494 -  
1495 - // Loop over all methods  
1496 - for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {  
1497 -  
1498 - // Continue only if method matches  
1499 - if (method == m_clients[i].subscriptions[j]) {  
1500 -  
1501 - // Declare notification  
1502 - std::string msg = "";  
1503 -  
1504 - // Register  
1505 - if (method == "samp.hub.event.register") {  
1506 -  
1507 - // Set response for samp.hub.event.register  
1508 - msg.append("<?xml version=\"1.0\"?>\n");  
1509 - msg.append("<methodCall>\n");  
1510 - msg.append("<methodName>samp.client.receiveNotification</methodName>\n");  
1511 - msg.append("<params>\n");  
1512 - msg.append(" <param><value>");  
1513 - msg.append(m_clients[i].private_key);  
1514 - msg.append("</value></param>\n");  
1515 - msg.append(" <param><value>"+m_hub_id+"</value></param>\n");  
1516 - msg.append(" <param><value><struct>\n");  
1517 - msg.append(" <member>\n");  
1518 - msg.append(" <name>samp.mtype</name>\n");  
1519 - msg.append(" <value>samp.hub.event.register</value>\n");  
1520 - msg.append(" </member>\n");  
1521 - msg.append(" <member>\n");  
1522 - msg.append(" <name>samp.params</name>\n");  
1523 - msg.append(" <value><struct>\n");  
1524 - msg.append(" <member>\n");  
1525 - msg.append(" <name>id</name>\n");  
1526 - msg.append(" <value>"+client+"</value>\n");  
1527 - msg.append(" </member>\n");  
1528 - msg.append(" </struct></value>\n");  
1529 - msg.append(" </member>\n");  
1530 - msg.append(" </struct></value></param>\n");  
1531 - msg.append("</params>\n");  
1532 - msg.append("</methodCall>\n");  
1533 -  
1534 - // Post notification  
1535 - notify(m_clients[i].url, msg);  
1536 -  
1537 - }  
1538 -  
1539 - // Unregister  
1540 - else if (method == "samp.hub.event.unregister") {  
1541 -  
1542 - // Set response for samp.hub.event.unregister  
1543 - msg.append("<?xml version=\"1.0\"?>\n");  
1544 - msg.append("<methodCall>\n");  
1545 - msg.append("<methodName>samp.client.receiveNotification</methodName>\n");  
1546 - msg.append("<params>\n");  
1547 - msg.append(" <param><value>");  
1548 - msg.append(m_clients[i].private_key);  
1549 - msg.append("</value></param>\n");  
1550 - msg.append(" <param><value>");  
1551 - msg.append(m_hub_id);  
1552 - msg.append("</value></param>\n");  
1553 - msg.append(" <param><value><struct>\n");  
1554 - msg.append(" <member>\n");  
1555 - msg.append(" <name>samp.mtype</name>\n");  
1556 - msg.append(" <value>samp.hub.event.unregister</value>\n");  
1557 - msg.append(" </member>\n");  
1558 - msg.append(" <member>\n");  
1559 - msg.append(" <name>samp.params</name>\n");  
1560 - msg.append(" <value><struct>\n");  
1561 - msg.append(" <member>\n");  
1562 - msg.append(" <name>id</name>\n");  
1563 - msg.append(" <value>"+client+"</value>\n");  
1564 - msg.append(" </member>\n");  
1565 - msg.append(" </struct></value>\n");  
1566 - msg.append(" </member>\n");  
1567 - msg.append(" </struct></value></param>\n");  
1568 - msg.append("</params>\n");  
1569 - msg.append("</methodCall>\n");  
1570 -  
1571 - // Post notification  
1572 - notify(m_clients[i].url, msg);  
1573 -  
1574 - }  
1575 -  
1576 - // Metadata  
1577 - else if (method == "samp.hub.event.metadata") {  
1578 -  
1579 - // Get index of client  
1580 - int k;  
1581 - for (k = 0; k < m_clients.size(); ++k) {  
1582 - if (m_clients[k].reference == client) {  
1583 - break;  
1584 - }  
1585 - }  
1586 -  
1587 - // Fall through if client index is not valid  
1588 - if (k >= m_clients.size()) {  
1589 - continue;  
1590 - }  
1591 -  
1592 - // Set response for samp.hub.event.metadata  
1593 - msg.append("<?xml version=\"1.0\"?>\n");  
1594 - msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");  
1595 - msg.append("<params>\n");  
1596 - msg.append(" <param><value>");  
1597 - msg.append(m_clients[i].private_key);  
1598 - msg.append("</value></param>\n");  
1599 - msg.append(" <param><value>"+m_hub_id+"</value></param>\n");  
1600 - msg.append(" <param><value><struct>\n");  
1601 - msg.append(" <member>\n");  
1602 - msg.append(" <name>samp.mtype</name>\n");  
1603 - msg.append(" <value>samp.hub.event.metadata</value>\n");  
1604 - msg.append(" </member>\n");  
1605 - msg.append(" <member>\n");  
1606 - msg.append(" <name>samp.params</name>\n");  
1607 - msg.append(" <value><struct>\n");  
1608 - msg.append(" <member>\n");  
1609 - msg.append(" <name>id</name>\n");  
1610 - msg.append(" <value>"+m_clients[k].reference+"</value>\n");  
1611 - msg.append(" </member>\n");  
1612 - msg.append(" <member>\n");  
1613 - msg.append(" <name>metadata</name>\n");  
1614 - msg.append(" <value><struct>\n");  
1615 - msg.append(" <member>\n");  
1616 - msg.append(" <name>samp.name</name>\n");  
1617 - msg.append(" <value>"+m_clients[k].name+"</value>\n");  
1618 - msg.append(" </member>\n");  
1619 - msg.append(" <member>\n");  
1620 - msg.append(" <name>samp.description.text</name>\n");  
1621 - msg.append(" <value>"+m_clients[k].description+"</value>\n");  
1622 - msg.append(" </member>\n");  
1623 - msg.append(" <member>\n");  
1624 - msg.append(" <name>samp.icon.url</name>\n");  
1625 - msg.append(" <value>"+m_clients[k].icon+"</value>\n");  
1626 - msg.append(" </member>\n");  
1627 - msg.append(" <member>\n");  
1628 - msg.append(" <name>samp.documentation.url</name>\n");  
1629 - msg.append(" <value>"+m_clients[k].documentation+"</value>\n");  
1630 - msg.append(" </member>\n");  
1631 - msg.append(" <member>\n");  
1632 - msg.append(" <name>author.affiliation</name>\n");  
1633 - msg.append(" <value>"+m_clients[k].affiliation+"</value>\n");  
1634 - msg.append(" </member>\n");  
1635 - msg.append(" <member>\n");  
1636 - msg.append(" <name>author.name</name>\n");  
1637 - msg.append(" <value>"+m_clients[k].author_name+"</value>\n");  
1638 - msg.append(" </member>\n");  
1639 - msg.append(" <member>\n");  
1640 - msg.append(" <name>author.email</name>\n");  
1641 - msg.append(" <value>"+m_clients[k].email+"</value>\n");  
1642 - msg.append(" </member>\n");  
1643 - msg.append(" <member>\n");  
1644 - msg.append(" <name>home.page</name>\n");  
1645 - msg.append(" <value>"+m_clients[k].homepage+"</value>\n");  
1646 - msg.append(" </member>\n");  
1647 - msg.append(" </struct></value>\n");  
1648 - msg.append(" </member>\n");  
1649 - msg.append(" </struct></value>\n");  
1650 - msg.append(" </member>\n");  
1651 - msg.append(" </struct></value></param>\n");  
1652 - msg.append("</params>\n");  
1653 - msg.append("</methodCall>\n");  
1654 -  
1655 - // Post notification  
1656 - notify(m_clients[i].url, msg);  
1657 -  
1658 - } // endelse: metadata  
1659 -  
1660 - } // endif: method was requested one  
1661 -  
1662 - } // endfor: looped over all methods  
1663 -  
1664 - } // endfor: looped over all clients  
1665 -  
1666 - // Return  
1667 - return;  
1668 -}  
1669 -/***********************************************************************//**  
1670 - * @brief Send notifications  
1671 - *  
1672 - * @param[in] method Name of the method  
1673 - * @param[in] client Reference of the client  
1674 - * @param[in] xml message sent by the client  
1675 - *  
1676 - * Send notifications to all registered clients that request so.  
1677 - ***************************************************************************/  
1678 -void GVOHub::send_notifications(const std::string& method,  
1679 - const std::string& client,  
1680 - const GXml& xml)  
1681 -{  
1682 - // Debug: dump information to console  
1683 - #if defined(G_CONSOLE_DUMP)  
1684 - std::cout << "GVOHub::send_notifications 2nd form" << std::endl;  
1685 - std::cout << "GVOHub::send_notifications "+method << std::endl;  
1686 - #endif  
1687 -  
1688 - // Loop over all clients  
1689 - for (int i = 0; i < m_clients.size(); ++i) {  
1690 -  
1691 - // Loop over all methods  
1692 - for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) {  
1693 -  
1694 - // Continue only if method matches  
1695 - if (method == m_clients[i].subscriptions[j]) {  
1696 -  
1697 - // Declare notification  
1698 - std::string msg = "";  
1699 -  
1700 - // Image loading  
1701 - if (method == "image.load.fits") {  
1702 -  
1703 - // Debug: dump information to console  
1704 - #if defined(G_CONSOLE_DUMP)  
1705 - std::cout << "GVOHub:: Preparing broadcast message" << std::endl;  
1706 - #endif  
1707 -  
1708 - // Declare value  
1709 - std::string value = "";  
1710 -  
1711 - // Search for value of specified member  
1712 - const GXmlNode* node = xml.element("methodCall > params > param[2] > value > struct > member > value > struct");  
1713 - #if defined(G_CONSOLE_DUMP)  
1714 - std::cout << "Searching url value" << std::endl;  
1715 - #endif  
1716 - if (node != NULL) {  
1717 - #if defined(G_CONSOLE_DUMP)  
1718 - std::cout << "Node found" << std::endl;  
1719 - #endif  
1720 - int num = node->elements("member");  
1721 - for (int i = 0; i < num; ++i) {  
1722 - const GXmlNode* member = node->element("member", i);  
1723 - std::string one_name;  
1724 - std::string one_value;  
1725 - get_name_value_pair(member, one_name, one_value);  
1726 - #if defined(G_CONSOLE_DUMP)  
1727 - std::cout << "name: "+one_name << std::endl;  
1728 - #endif  
1729 - if (one_name == "url") {  
1730 - value = one_value;  
1731 - break;  
1732 - }  
1733 - }  
1734 - } else {  
1735 - #if defined(G_CONSOLE_DUMP)  
1736 - std::cout << "Node not found" << std::endl;  
1737 - #endif  
1738 - }  
1739 -  
1740 - // Set response for image.load.fits  
1741 - msg.append("<?xml version=\"1.0\"?>\n");  
1742 - msg.append("<methodCall>\n");  
1743 - msg.append("<methodName>samp.client.receiveNotification</methodName>\n");  
1744 - msg.append("<params>\n");  
1745 - msg.append(" <param><value>");  
1746 - msg.append(m_clients[i].private_key);  
1747 - msg.append("</value></param>\n");  
1748 - msg.append(" <param><value>");  
1749 - msg.append(m_hub_id);  
1750 - msg.append("</value></param>\n");  
1751 - msg.append(" <param><value><struct>\n");  
1752 - msg.append(" <member>\n");  
1753 - msg.append(" <name>samp.mtype</name>\n");  
1754 - msg.append(" <value>image.load.fits</value>\n");  
1755 - msg.append(" </member>\n");  
1756 - msg.append(" <member>\n");  
1757 - msg.append(" <name>samp.params</name>\n");  
1758 - msg.append(" <value><struct>\n");  
1759 - msg.append(" <member>\n");  
1760 - msg.append(" <name>name</name>\n");  
1761 - msg.append(" <value>Gammalib_shared_fits</value>\n");  
1762 - msg.append(" </member>\n");  
1763 - msg.append(" <member>\n");  
1764 - msg.append(" <name>image-id</name>\n");  
1765 - msg.append(" <value>Gammalib_shared_fits_id</value>\n");  
1766 - msg.append(" </member>\n");  
1767 - msg.append(" <member>\n");  
1768 - msg.append(" <name>url</name>\n");  
1769 - msg.append(" <value>"+value+"</value>\n");  
1770 - msg.append(" </member>\n");  
1771 - msg.append(" </struct></value>\n");  
1772 - msg.append(" </member>\n");  
1773 - msg.append(" </struct></value></param>\n");  
1774 - msg.append("</params>\n");  
1775 - msg.append("</methodCall>\n");  
1776 - #if defined(G_CONSOLE_DUMP)  
1777 - std::cout << msg << std::endl;  
1778 - #endif  
1779 -  
1780 - // Post notification  
1781 - notify(m_clients[i].url, msg);  
1782 -  
1783 - }  
1784 - } // endif: method was requested one  
1785 -  
1786 - } // endfor: looped over all methods  
1787 -  
1788 - } // endfor: looped over all clients  
1789 -  
1790 - // Return  
1791 - return;  
1792 -}  
1793 -  
1794 -/***********************************************************************//**  
1795 * @brief Creates the lockfile, fill it 1533 * @brief Creates the lockfile, fill it
1796 * 1534 *
1797 * Implements IVOA standard REC-SAMP-1.3-20120411. 1535 * Implements IVOA standard REC-SAMP-1.3-20120411.
@@ -2076,6 +1814,264 @@ void GVOHub::notify(const std::string&amp; url, @@ -2076,6 +1814,264 @@ void GVOHub::notify(const std::string&amp; url,
2076 1814
2077 1815
2078 /***********************************************************************//** 1816 /***********************************************************************//**
  1817 + * @brief Notify client about another client registering at Hub
  1818 + *
  1819 + * @param[in] client Client to notify.
  1820 + * @param[in] reference Reference to client which registered.
  1821 + *
  1822 + * Notify a client about another client that has registered at the Hub. The
  1823 + * method sends a "samp.hub.event.register" message to the @p client.
  1824 + ***************************************************************************/
  1825 +void GVOHub::notify_register(const GVOHub::client& client,
  1826 + const std::string& reference)
  1827 +{
  1828 + // Declare notification
  1829 + std::string msg = "";
  1830 +
  1831 + // Set response for samp.hub.event.register
  1832 + msg.append("<?xml version=\"1.0\"?>\n");
  1833 + msg.append("<methodCall>\n");
  1834 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1835 + msg.append("<params>\n");
  1836 + msg.append(" <param><value>"+client.private_key+"</value></param>\n");
  1837 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1838 + msg.append(" <param><value><struct>\n");
  1839 + msg.append(" <member>\n");
  1840 + msg.append(" <name>samp.mtype</name>\n");
  1841 + msg.append(" <value>samp.hub.event.register</value>\n");
  1842 + msg.append(" </member>\n");
  1843 + msg.append(" <member>\n");
  1844 + msg.append(" <name>samp.params</name>\n");
  1845 + msg.append(" <value><struct>\n");
  1846 + msg.append(" <member>\n");
  1847 + msg.append(" <name>id</name>\n");
  1848 + msg.append(" <value>"+reference+"</value>\n");
  1849 + msg.append(" </member>\n");
  1850 + msg.append(" </struct></value>\n");
  1851 + msg.append(" </member>\n");
  1852 + msg.append(" </struct></value></param>\n");
  1853 + msg.append("</params>\n");
  1854 + msg.append("</methodCall>\n");
  1855 +
  1856 + // Post notification
  1857 + notify(client.url, msg);
  1858 +
  1859 + // Return
  1860 + return;
  1861 +}
  1862 +
  1863 +
  1864 +/***********************************************************************//**
  1865 + * @brief Notify client about another client unregistering at Hub
  1866 + *
  1867 + * @param[in] client Client to notify.
  1868 + * @param[in] reference Reference to client who unregistered.
  1869 + *
  1870 + * Notify a client about another client that has unregistered at the Hub. The
  1871 + * method sends a "samp.hub.event.unregister" message to the @p client.
  1872 + ***************************************************************************/
  1873 +void GVOHub::notify_unregister(const GVOHub::client& client,
  1874 + const std::string& reference)
  1875 +{
  1876 + // Declare notification
  1877 + std::string msg = "";
  1878 +
  1879 + // Set response for samp.hub.event.unregister
  1880 + msg.append("<?xml version=\"1.0\"?>\n");
  1881 + msg.append("<methodCall>\n");
  1882 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  1883 + msg.append("<params>\n");
  1884 + msg.append(" <param><value>"+client.private_key+"</value></param>\n");
  1885 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1886 + msg.append(" <param><value><struct>\n");
  1887 + msg.append(" <member>\n");
  1888 + msg.append(" <name>samp.mtype</name>\n");
  1889 + msg.append(" <value>samp.hub.event.unregister</value>\n");
  1890 + msg.append(" </member>\n");
  1891 + msg.append(" <member>\n");
  1892 + msg.append(" <name>samp.params</name>\n");
  1893 + msg.append(" <value><struct>\n");
  1894 + msg.append(" <member>\n");
  1895 + msg.append(" <name>id</name>\n");
  1896 + msg.append(" <value>"+reference+"</value>\n");
  1897 + msg.append(" </member>\n");
  1898 + msg.append(" </struct></value>\n");
  1899 + msg.append(" </member>\n");
  1900 + msg.append(" </struct></value></param>\n");
  1901 + msg.append("</params>\n");
  1902 + msg.append("</methodCall>\n");
  1903 +
  1904 + // Post notification
  1905 + notify(client.url, msg);
  1906 +
  1907 + // Return
  1908 + return;
  1909 +}
  1910 +
  1911 +
  1912 +/***********************************************************************//**
  1913 + * @brief Notify client about the metadata of another client
  1914 + *
  1915 + * @param[in] client Client to notify.
  1916 + * @param[in] reference Reference of client for which metadata should be sent.
  1917 + *
  1918 + * Notify a client about another the metadata of another client. The method
  1919 + * sends a "samp.hub.event.metadata" message to the @p client.
  1920 + ***************************************************************************/
  1921 +void GVOHub::notify_metadata(const GVOHub::client& client,
  1922 + const std::string& reference)
  1923 +{
  1924 + // Get index of reference client
  1925 + int k;
  1926 + for (k = 0; k < m_clients.size(); ++k) {
  1927 + if (m_clients[k].reference == reference) {
  1928 + break;
  1929 + }
  1930 + }
  1931 +
  1932 + // Continue only if client index is valid
  1933 + if (k < m_clients.size()) {
  1934 +
  1935 + // Declare notification
  1936 + std::string msg = "";
  1937 +
  1938 + // Set response for samp.hub.event.metadata
  1939 + msg.append("<?xml version=\"1.0\"?>\n");
  1940 + msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n");
  1941 + msg.append("<params>\n");
  1942 + msg.append(" <param><value>"+client.private_key+"</value></param>\n");
  1943 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  1944 + msg.append(" <param><value><struct>\n");
  1945 + msg.append(" <member>\n");
  1946 + msg.append(" <name>samp.mtype</name>\n");
  1947 + msg.append(" <value>samp.hub.event.metadata</value>\n");
  1948 + msg.append(" </member>\n");
  1949 + msg.append(" <member>\n");
  1950 + msg.append(" <name>samp.params</name>\n");
  1951 + msg.append(" <value><struct>\n");
  1952 + msg.append(" <member>\n");
  1953 + msg.append(" <name>id</name>\n");
  1954 + msg.append(" <value>"+m_clients[k].reference+"</value>\n");
  1955 + msg.append(" </member>\n");
  1956 + msg.append(" <member>\n");
  1957 + msg.append(" <name>metadata</name>\n");
  1958 + msg.append(" <value><struct>\n");
  1959 + msg.append(" <member>\n");
  1960 + msg.append(" <name>samp.name</name>\n");
  1961 + msg.append(" <value>"+m_clients[k].name+"</value>\n");
  1962 + msg.append(" </member>\n");
  1963 + msg.append(" <member>\n");
  1964 + msg.append(" <name>samp.description.text</name>\n");
  1965 + msg.append(" <value>"+m_clients[k].description+"</value>\n");
  1966 + msg.append(" </member>\n");
  1967 + msg.append(" <member>\n");
  1968 + msg.append(" <name>samp.icon.url</name>\n");
  1969 + msg.append(" <value>"+m_clients[k].icon+"</value>\n");
  1970 + msg.append(" </member>\n");
  1971 + msg.append(" <member>\n");
  1972 + msg.append(" <name>samp.documentation.url</name>\n");
  1973 + msg.append(" <value>"+m_clients[k].documentation+"</value>\n");
  1974 + msg.append(" </member>\n");
  1975 + msg.append(" <member>\n");
  1976 + msg.append(" <name>author.affiliation</name>\n");
  1977 + msg.append(" <value>"+m_clients[k].affiliation+"</value>\n");
  1978 + msg.append(" </member>\n");
  1979 + msg.append(" <member>\n");
  1980 + msg.append(" <name>author.name</name>\n");
  1981 + msg.append(" <value>"+m_clients[k].author_name+"</value>\n");
  1982 + msg.append(" </member>\n");
  1983 + msg.append(" <member>\n");
  1984 + msg.append(" <name>author.email</name>\n");
  1985 + msg.append(" <value>"+m_clients[k].email+"</value>\n");
  1986 + msg.append(" </member>\n");
  1987 + msg.append(" <member>\n");
  1988 + msg.append(" <name>home.page</name>\n");
  1989 + msg.append(" <value>"+m_clients[k].homepage+"</value>\n");
  1990 + msg.append(" </member>\n");
  1991 + msg.append(" </struct></value>\n");
  1992 + msg.append(" </member>\n");
  1993 + msg.append(" </struct></value>\n");
  1994 + msg.append(" </member>\n");
  1995 + msg.append(" </struct></value></param>\n");
  1996 + msg.append("</params>\n");
  1997 + msg.append("</methodCall>\n");
  1998 +
  1999 + // Post notification
  2000 + notify(client.url, msg);
  2001 +
  2002 + } // endif: reference client was valid
  2003 +
  2004 + // Return
  2005 + return;
  2006 +}
  2007 +
  2008 +
  2009 +/***********************************************************************//**
  2010 + * @brief Notify client about image loading
  2011 + *
  2012 + * @param[in] client Client.
  2013 + * @param[in] xml Message from which image information is extracted.
  2014 + *
  2015 + * Notify a client that a FITS image is avialable for loading. The method
  2016 + * sends a "image.load.fits" message to the @p client. Information about the
  2017 + * image is extracted from the @p xml document.
  2018 + ***************************************************************************/
  2019 +void GVOHub::notify_image_load(const GVOHub::client& client,
  2020 + const GXml& xml)
  2021 +{
  2022 + // Get client response
  2023 + const GXmlNode* node = xml.element("methodCall > params > param[2] > value > struct > member > value > struct");
  2024 +
  2025 + // Extract image information from client response
  2026 + std::string name = get_response_value(node, "name");
  2027 + std::string url = get_response_value(node, "url");
  2028 + std::string id = get_response_value(node, "image-id");
  2029 +
  2030 + // Declare notification
  2031 + std::string msg = "";
  2032 +
  2033 + // Set notification for image.load.fits
  2034 + msg.append("<?xml version=\"1.0\"?>\n");
  2035 + msg.append("<methodCall>\n");
  2036 + msg.append("<methodName>samp.client.receiveNotification</methodName>\n");
  2037 + msg.append("<params>\n");
  2038 + msg.append(" <param><value>"+client.private_key+"</value></param>\n");
  2039 + msg.append(" <param><value>"+m_hub_id+"</value></param>\n");
  2040 + msg.append(" <param><value><struct>\n");
  2041 + msg.append(" <member>\n");
  2042 + msg.append(" <name>samp.mtype</name>\n");
  2043 + msg.append(" <value>image.load.fits</value>\n");
  2044 + msg.append(" </member>\n");
  2045 + msg.append(" <member>\n");
  2046 + msg.append(" <name>samp.params</name>\n");
  2047 + msg.append(" <value><struct>\n");
  2048 + msg.append(" <member>\n");
  2049 + msg.append(" <name>name</name>\n");
  2050 + msg.append(" <value>"+name+"</value>\n");
  2051 + msg.append(" </member>\n");
  2052 + msg.append(" <member>\n");
  2053 + msg.append(" <name>image-id</name>\n");
  2054 + msg.append(" <value>"+id+"</value>\n");
  2055 + msg.append(" </member>\n");
  2056 + msg.append(" <member>\n");
  2057 + msg.append(" <name>url</name>\n");
  2058 + msg.append(" <value>"+url+"</value>\n");
  2059 + msg.append(" </member>\n");
  2060 + msg.append(" </struct></value>\n");
  2061 + msg.append(" </member>\n");
  2062 + msg.append(" </struct></value></param>\n");
  2063 + msg.append("</params>\n");
  2064 + msg.append("</methodCall>\n");
  2065 +
  2066 + // Post notification
  2067 + notify(client.url, msg);
  2068 +
  2069 + // Return
  2070 + return;
  2071 +}
  2072 +
  2073 +
  2074 +/***********************************************************************//**
2079 * @brief Generates random string of characters 2075 * @brief Generates random string of characters
2080 * 2076 *
2081 * @param[in] length Length of random string 2077 * @param[in] length Length of random string
@@ -2093,6 +2089,8 @@ std::string GVOHub::random_string(const size_t&amp; length) const @@ -2093,6 +2089,8 @@ std::string GVOHub::random_string(const size_t&amp; length) const
2093 // Return string 2089 // Return string
2094 return str; 2090 return str;
2095 } 2091 }
  2092 +
  2093 +
2096 /***********************************************************************//** 2094 /***********************************************************************//**
2097 * @brief Extract mtype from XML request 2095 * @brief Extract mtype from XML request
2098 * 2096 *
@@ -2122,6 +2120,8 @@ std::string GVOHub::get_mtype(const GXml&amp; xml) const @@ -2122,6 +2120,8 @@ std::string GVOHub::get_mtype(const GXml&amp; xml) const
2122 // Return key 2120 // Return key
2123 return client_key; 2121 return client_key;
2124 } 2122 }
  2123 +
  2124 +
2125 /***********************************************************************//** 2125 /***********************************************************************//**
2126 * @brief Extract client destination from XML request 2126 * @brief Extract client destination from XML request
2127 * 2127 *
@@ -2133,7 +2133,7 @@ std::string GVOHub::get_destination(const GXml&amp; xml) const @@ -2133,7 +2133,7 @@ std::string GVOHub::get_destination(const GXml&amp; xml) const
2133 { 2133 {
2134 // Header 2134 // Header
2135 #if defined(G_CONSOLE_DUMP) 2135 #if defined(G_CONSOLE_DUMP)
2136 - std::cout << "GVOHub::get_mtype" << std::endl; 2136 + std::cout << "GVOHub::get_destination" << std::endl;
2137 #endif 2137 #endif
2138 2138
2139 // Initialise response 2139 // Initialise response