Commit d1b9693dcc49ef4b68f0ce1fb9dc65265d8a5e59
1 parent
6afd29a0
GVOTable skeleton and use through GSkymap on the way
Showing
12 changed files
with
6503 additions
and
7 deletions
include/GSkymap.hpp
| @@ -41,7 +41,8 @@ | @@ -41,7 +41,8 @@ | ||
| 41 | #include "GMatrix.hpp" | 41 | #include "GMatrix.hpp" |
| 42 | #include "GVector.hpp" | 42 | #include "GVector.hpp" |
| 43 | #include "GBilinear.hpp" | 43 | #include "GBilinear.hpp" |
| 44 | - | 44 | +#include "GVOTable.hpp" |
| 45 | +#include "GVOClient.hpp" | ||
| 45 | 46 | ||
| 46 | /***********************************************************************//** | 47 | /***********************************************************************//** |
| 47 | * @class GSkymap | 48 | * @class GSkymap |
| @@ -164,6 +165,8 @@ private: | @@ -164,6 +165,8 @@ private: | ||
| 164 | void alloc_wcs(const GFitsImage& image); | 165 | void alloc_wcs(const GFitsImage& image); |
| 165 | GFitsBinTable* create_healpix_hdu(void) const; | 166 | GFitsBinTable* create_healpix_hdu(void) const; |
| 166 | GFitsImageDouble* create_wcs_hdu(void) const; | 167 | GFitsImageDouble* create_wcs_hdu(void) const; |
| 168 | + void publish(void); | ||
| 169 | + void make_votable(void); | ||
| 167 | 170 | ||
| 168 | // Private data area | 171 | // Private data area |
| 169 | int m_num_pixels; //!< Number of pixels (used for pixel allocation) | 172 | int m_num_pixels; //!< Number of pixels (used for pixel allocation) |
| @@ -172,6 +175,8 @@ private: | @@ -172,6 +175,8 @@ private: | ||
| 172 | int m_num_y; //!< Number of pixels in y direction (only 2D) | 175 | int m_num_y; //!< Number of pixels in y direction (only 2D) |
| 173 | GSkyProjection* m_proj; //!< Pointer to sky projection | 176 | GSkyProjection* m_proj; //!< Pointer to sky projection |
| 174 | double* m_pixels; //!< Pointer to skymap pixels | 177 | double* m_pixels; //!< Pointer to skymap pixels |
| 178 | + GVOTable* m_skytable; //!< Pointer to skymap VOTable | ||
| 179 | + GVOClient* m_skyclient; //!< Pointer to VOClient opened | ||
| 175 | 180 | ||
| 176 | // Computation cache | 181 | // Computation cache |
| 177 | mutable bool m_hascache; //!< Cache is valid | 182 | mutable bool m_hascache; //!< Cache is valid |
include/GVOHub.hpp
| @@ -105,6 +105,10 @@ protected: | @@ -105,6 +105,10 @@ protected: | ||
| 105 | std::string get_hub_lockfile(void) const; | 105 | std::string get_hub_lockfile(void) const; |
| 106 | void send_notifications(const std::string& method, | 106 | void send_notifications(const std::string& method, |
| 107 | const std::string& client); | 107 | const std::string& client); |
| 108 | + void request_call(const GXml& xml, | ||
| 109 | + const socklen_t& sock); | ||
| 110 | + std::string get_mtype(const GXml& xml) const; | ||
| 111 | + std::string get_destination(const GXml& xml) const; | ||
| 108 | 112 | ||
| 109 | // Low-level methods | 113 | // Low-level methods |
| 110 | void create_samp_file(void) const; | 114 | void create_samp_file(void) const; |
include/GVOTable.hpp
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOTable.hpp - VOTable class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2014-2015 by Thierry Louge * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOTable.hpp | ||
| 23 | + * @brief VOTable class definition | ||
| 24 | + * @author Thierry Louge | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +#ifndef GVOTable_HPP | ||
| 28 | +#define GVOTable_HPP | ||
| 29 | + | ||
| 30 | +/* __ Definitions ________________________________________________________ */ | ||
| 31 | + | ||
| 32 | +/* __ Includes ___________________________________________________________ */ | ||
| 33 | +#include <string> | ||
| 34 | +#include <vector> | ||
| 35 | +#include <sys/socket.h> | ||
| 36 | +#include "GBase.hpp" | ||
| 37 | +#include "GXml.hpp" | ||
| 38 | +#include "GXmlNode.hpp" | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +/***********************************************************************//** | ||
| 42 | + * @class GVOTable | ||
| 43 | + * | ||
| 44 | + * @brief VOTable class | ||
| 45 | + * | ||
| 46 | + * This class implements a VOTable for exchanges through VO-compatible | ||
| 47 | + * applications. | ||
| 48 | + ***************************************************************************/ | ||
| 49 | +class GVOTable : public GBase { | ||
| 50 | + | ||
| 51 | +public: | ||
| 52 | + // Constructors and destructors | ||
| 53 | + GVOTable(void); | ||
| 54 | + GVOTable(const GVOTable& hub); | ||
| 55 | + virtual ~GVOTable(void); | ||
| 56 | + | ||
| 57 | + // Operators | ||
| 58 | + GVOTable& operator=(const GVOTable& hub); | ||
| 59 | + | ||
| 60 | + // Methods | ||
| 61 | + void clear(void); | ||
| 62 | + GVOTable* clone(void) const; | ||
| 63 | + std::string classname(void) const; | ||
| 64 | + std::string print(const GChatter& chatter = NORMAL) const; | ||
| 65 | + void create_votable(void); | ||
| 66 | + void fill_content(const std::string& data) const; | ||
| 67 | + | ||
| 68 | +protected: | ||
| 69 | + // Protected methods | ||
| 70 | + void init_members(void); | ||
| 71 | + void copy_members(const GVOTable& client); | ||
| 72 | + void free_members(void); | ||
| 73 | + | ||
| 74 | + // Low-level methods | ||
| 75 | +private: | ||
| 76 | + // Private data area | ||
| 77 | + GXml m_tablexml; //!< GXml containing the VOTable | ||
| 78 | +}; | ||
| 79 | + | ||
| 80 | + | ||
| 81 | +/***********************************************************************//** | ||
| 82 | + * @brief Return class name | ||
| 83 | + * | ||
| 84 | + * @return String containing the class name ("GVOTable"). | ||
| 85 | + ***************************************************************************/ | ||
| 86 | +inline | ||
| 87 | +std::string GVOTable::classname(void) const | ||
| 88 | +{ | ||
| 89 | + return ("GVOTable"); | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +#endif /* GVOTable_HPP */ |
src/sky/GSkymap.cpp
| @@ -2261,7 +2261,38 @@ GFitsImageDouble* GSkymap::create_wcs_hdu(void) const | @@ -2261,7 +2261,38 @@ GFitsImageDouble* GSkymap::create_wcs_hdu(void) const | ||
| 2261 | return hdu; | 2261 | return hdu; |
| 2262 | } | 2262 | } |
| 2263 | 2263 | ||
| 2264 | +/***********************************************************************//** | ||
| 2265 | + * @brief publishes the skymap in a VO Hub | ||
| 2266 | + * | ||
| 2267 | + * @param[in] | ||
| 2268 | + * | ||
| 2269 | + * @exception GException:: | ||
| 2270 | + * | ||
| 2271 | + ***************************************************************************/ | ||
| 2272 | +void GSkymap::publish(void) | ||
| 2273 | +{ | ||
| 2274 | + make_votable(); | ||
| 2275 | + // Return | ||
| 2276 | + return; | ||
| 2277 | +} | ||
| 2264 | 2278 | ||
| 2279 | +/***********************************************************************//** | ||
| 2280 | + * @brief makes GVOTable object and fills ot with current skymap(s) | ||
| 2281 | + * | ||
| 2282 | + * @param[in] | ||
| 2283 | + * | ||
| 2284 | + * @exception GException:: | ||
| 2285 | + * | ||
| 2286 | + ***************************************************************************/ | ||
| 2287 | +void GSkymap::make_votable(void) | ||
| 2288 | +{ | ||
| 2289 | + GVOTable* m_skytable; | ||
| 2290 | + m_skytable->create_votable(); | ||
| 2291 | + //For each pixel set the value of the pixel inside the data part | ||
| 2292 | + //m_skytable->fill_content(); | ||
| 2293 | + // Return | ||
| 2294 | + return; | ||
| 2295 | +} | ||
| 2265 | /*========================================================================== | 2296 | /*========================================================================== |
| 2266 | = = | 2297 | = = |
| 2267 | = Friends = | 2298 | = Friends = |
src/sky/GSkymap.cpp~
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GSkymap.cpp - Sky map class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2010-2015 by Juergen Knoedlseder * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GSkymap.cpp | ||
| 23 | + * @brief Sky map class implementation | ||
| 24 | + * @author Juergen Knoedlseder | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#endif | ||
| 31 | +#include "GException.hpp" | ||
| 32 | +#include "GTools.hpp" | ||
| 33 | +#include "GSkymap.hpp" | ||
| 34 | +#include "GHealpix.hpp" | ||
| 35 | +#include "GWcsRegistry.hpp" | ||
| 36 | +#include "GWcs.hpp" | ||
| 37 | +#include "GFits.hpp" | ||
| 38 | +#include "GFitsTableDoubleCol.hpp" | ||
| 39 | +#include "GFitsImageDouble.hpp" | ||
| 40 | + | ||
| 41 | +/* __ Method name definitions ____________________________________________ */ | ||
| 42 | +#define G_CONSTRUCT_HPX "GSkymap::GSkymap(std::string&, int&,"\ | ||
| 43 | + " std::string&, int&)" | ||
| 44 | +#define G_CONSTRUCT_MAP "GSkymap::GSkymap(std::string&, std::string&,"\ | ||
| 45 | + " double&, double&, double& double&, int&, int&, int&)" | ||
| 46 | +#define G_NMAPS "GSkymap::nmaps(int&)" | ||
| 47 | +#define G_OP_UNARY_ADD "GSkymap::operator+=(GSkymap&)" | ||
| 48 | +#define G_OP_UNARY_SUB "GSkymap::operator-=(GSkymap&)" | ||
| 49 | +#define G_OP_UNARY_MUL "GSkymap::operator-=(GSkymap&)" | ||
| 50 | +#define G_OP_UNARY_DIV "GSkymap::operator-=(GSkymap&)" | ||
| 51 | +#define G_OP_ACCESS_1D "GSkymap::operator(int&, int&)" | ||
| 52 | +#define G_OP_ACCESS_2D "GSkymap::operator(GSkyPixel&, int&)" | ||
| 53 | +#define G_OP_VALUE "GSkymap::operator(GSkyDir&, int&)" | ||
| 54 | +#define G_INX2DIR "GSkymap::inx2dir(int&)" | ||
| 55 | +#define G_PIX2DIR "GSkymap::pix2dir(GSkyPixel&)" | ||
| 56 | +#define G_DIR2INX "GSkymap::dir2inx(GSkyDir&)" | ||
| 57 | +#define G_DIR2PIX "GSkymap::dir2pix(GSkyDir&)" | ||
| 58 | +#define G_SOLIDANGLE1 "GSkymap::solidangle(int&)" | ||
| 59 | +#define G_SOLIDANGLE2 "GSkymap::solidangle(GSkyPixel&)" | ||
| 60 | +#define G_EXTRACT "GSkymap::extract(int&, int&)" | ||
| 61 | +#define G_READ "GSkymap::read(const GFitsHDU&)" | ||
| 62 | +#define G_SET_WCS "GSkymap::set_wcs(std::string&, std::string&, double&,"\ | ||
| 63 | + " double&, double&, double&, double&, double&,"\ | ||
| 64 | + " GMatrix&, GVector&)" | ||
| 65 | +#define G_READ_HEALPIX "GSkymap::read_healpix(GFitsTable*)" | ||
| 66 | +#define G_READ_WCS "GSkymap::read_wcs(GFitsImage*)" | ||
| 67 | +#define G_ALLOC_WCS "GSkymap::alloc_wcs(GFitsImage*)" | ||
| 68 | + | ||
| 69 | +/* __ Macros _____________________________________________________________ */ | ||
| 70 | + | ||
| 71 | +/* __ Coding definitions _________________________________________________ */ | ||
| 72 | + | ||
| 73 | +/* __ Debug definitions __________________________________________________ */ | ||
| 74 | +//#define G_READ_HEALPIX_DEBUG // Debug read_healpix | ||
| 75 | +//#define G_READ_WCS_DEBUG // Debug read_wcs | ||
| 76 | + | ||
| 77 | +/* __ Prototype __________________________________________________________ */ | ||
| 78 | + | ||
| 79 | + | ||
| 80 | +/*========================================================================== | ||
| 81 | + = = | ||
| 82 | + = Constructors/destructors = | ||
| 83 | + = = | ||
| 84 | + ==========================================================================*/ | ||
| 85 | + | ||
| 86 | +/***********************************************************************//** | ||
| 87 | + * @brief Void constructor | ||
| 88 | + ***************************************************************************/ | ||
| 89 | +GSkymap::GSkymap(void) | ||
| 90 | +{ | ||
| 91 | + // Initialise class members for clean destruction | ||
| 92 | + init_members(); | ||
| 93 | + | ||
| 94 | + // Return | ||
| 95 | + return; | ||
| 96 | +} | ||
| 97 | + | ||
| 98 | + | ||
| 99 | +/***********************************************************************//** | ||
| 100 | + * @brief FITS file constructor | ||
| 101 | + * | ||
| 102 | + * @param[in] filename FITS file name. | ||
| 103 | + ***************************************************************************/ | ||
| 104 | +GSkymap::GSkymap(const std::string& filename) | ||
| 105 | +{ | ||
| 106 | + // Initialise class members for clean destruction | ||
| 107 | + init_members(); | ||
| 108 | + | ||
| 109 | + // Load skymap | ||
| 110 | + load(filename); | ||
| 111 | + | ||
| 112 | + // Return | ||
| 113 | + return; | ||
| 114 | +} | ||
| 115 | + | ||
| 116 | + | ||
| 117 | +/***********************************************************************//** | ||
| 118 | + * @brief Healpix sky map constructor | ||
| 119 | + * | ||
| 120 | + * @param[in] coords Coordinate System (CEL or GAL). | ||
| 121 | + * @param[in] nside Nside parameter. | ||
| 122 | + * @param[in] order Pixel ordering (RING or NEST). | ||
| 123 | + * @param[in] nmaps Number of maps in set (default=1). | ||
| 124 | + * | ||
| 125 | + * @exception GException::skymap_bad_par | ||
| 126 | + * Invalid sky map parameter. | ||
| 127 | + * | ||
| 128 | + * Constructs sky map in Healpix pixelisation. | ||
| 129 | + ***************************************************************************/ | ||
| 130 | +GSkymap::GSkymap(const std::string& coords, | ||
| 131 | + const int& nside, | ||
| 132 | + const std::string& order, | ||
| 133 | + const int& nmaps) | ||
| 134 | +{ | ||
| 135 | + // Initialise class members for clean destruction | ||
| 136 | + init_members(); | ||
| 137 | + | ||
| 138 | + // Check if nmaps parameter is >0 | ||
| 139 | + if (nmaps < 1) { | ||
| 140 | + throw GException::skymap_bad_par(G_CONSTRUCT_HPX, nmaps, | ||
| 141 | + "nmaps parameter must be >0."); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + // Allocate Healpix projection | ||
| 145 | + GHealpix* projection = new GHealpix(nside, order, coords); | ||
| 146 | + m_proj = projection; | ||
| 147 | + | ||
| 148 | + // Set number of pixels and number of maps | ||
| 149 | + m_num_pixels = projection->npix(); | ||
| 150 | + m_num_maps = nmaps; | ||
| 151 | + | ||
| 152 | + // Allocate pixels | ||
| 153 | + alloc_pixels(); | ||
| 154 | + | ||
| 155 | + // Return | ||
| 156 | + return; | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | + | ||
| 160 | +/***********************************************************************//** | ||
| 161 | + * @brief WCS sky map constructor | ||
| 162 | + * | ||
| 163 | + * @param[in] wcs World Coordinate System. | ||
| 164 | + * @param[in] coords Coordinate System (CEL or GAL). | ||
| 165 | + * @param[in] x X coordinate of sky map centre (deg). | ||
| 166 | + * @param[in] y Y coordinate of sky map centre (deg). | ||
| 167 | + * @param[in] dx Pixel size in x direction at centre (deg/pixel). | ||
| 168 | + * @param[in] dy Pixel size in y direction at centre (deg/pixel). | ||
| 169 | + * @param[in] nx Number of pixels in x direction. | ||
| 170 | + * @param[in] ny Number of pixels in y direction. | ||
| 171 | + * @param[in] nmaps Number of maps in set (default=1). | ||
| 172 | + * | ||
| 173 | + * @exception GException::skymap_bad_par | ||
| 174 | + * Invalid sky map parameter. | ||
| 175 | + * | ||
| 176 | + * Constructs sky map in World Coordinate System projection. | ||
| 177 | + ***************************************************************************/ | ||
| 178 | +GSkymap::GSkymap(const std::string& wcs, | ||
| 179 | + const std::string& coords, | ||
| 180 | + const double& x, | ||
| 181 | + const double& y, | ||
| 182 | + const double& dx, | ||
| 183 | + const double& dy, | ||
| 184 | + const int& nx, | ||
| 185 | + const int& ny, | ||
| 186 | + const int& nmaps) | ||
| 187 | +{ | ||
| 188 | + // Initialise class members for clean destruction | ||
| 189 | + init_members(); | ||
| 190 | + | ||
| 191 | + // Check parameters | ||
| 192 | + if (nx < 1) { | ||
| 193 | + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, nx, | ||
| 194 | + "nx parameter must be >0."); | ||
| 195 | + } | ||
| 196 | + if (ny < 1) { | ||
| 197 | + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, ny, | ||
| 198 | + "ny parameter must be >0."); | ||
| 199 | + } | ||
| 200 | + if (nmaps < 1) { | ||
| 201 | + throw GException::skymap_bad_par(G_CONSTRUCT_MAP, nmaps, | ||
| 202 | + "nmaps parameter must be >0."); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + // Set WCS | ||
| 206 | + double crval1 = x; | ||
| 207 | + double crval2 = y; | ||
| 208 | + double crpix1 = double(nx+1)/2.0; | ||
| 209 | + double crpix2 = double(ny+1)/2.0; | ||
| 210 | + double cdelt1 = dx; | ||
| 211 | + double cdelt2 = dy; | ||
| 212 | + GMatrix cd(2,2); | ||
| 213 | + GVector pv2(21); | ||
| 214 | + set_wcs(wcs, coords, crval1, crval2, crpix1, crpix2, cdelt1, cdelt2, | ||
| 215 | + cd, pv2); | ||
| 216 | + | ||
| 217 | + // Set number of pixels and number of maps | ||
| 218 | + m_num_x = nx; | ||
| 219 | + m_num_y = ny; | ||
| 220 | + m_num_pixels = m_num_x * m_num_y; | ||
| 221 | + m_num_maps = nmaps; | ||
| 222 | + | ||
| 223 | + // Allocate pixels | ||
| 224 | + alloc_pixels(); | ||
| 225 | + | ||
| 226 | + // Return | ||
| 227 | + return; | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | + | ||
| 231 | +/***********************************************************************//** | ||
| 232 | + * @brief Copy constructor | ||
| 233 | + * | ||
| 234 | + * @param[in] map Sky map. | ||
| 235 | + ***************************************************************************/ | ||
| 236 | +GSkymap::GSkymap(const GSkymap& map) | ||
| 237 | +{ | ||
| 238 | + // Initialise class members for clean destruction | ||
| 239 | + init_members(); | ||
| 240 | + | ||
| 241 | + // Copy members | ||
| 242 | + copy_members(map); | ||
| 243 | + | ||
| 244 | + // Return | ||
| 245 | + return; | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | + | ||
| 249 | +/***********************************************************************//** | ||
| 250 | + * @brief Destructor | ||
| 251 | + ***************************************************************************/ | ||
| 252 | +GSkymap::~GSkymap(void) | ||
| 253 | +{ | ||
| 254 | + // Free members | ||
| 255 | + free_members(); | ||
| 256 | + | ||
| 257 | + // Return | ||
| 258 | + return; | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | + | ||
| 262 | +/*========================================================================== | ||
| 263 | + = = | ||
| 264 | + = Operators = | ||
| 265 | + = = | ||
| 266 | + ==========================================================================*/ | ||
| 267 | + | ||
| 268 | +/***********************************************************************//** | ||
| 269 | + * @brief Assignment operator | ||
| 270 | + * | ||
| 271 | + * @param[in] map Sky map. | ||
| 272 | + * @return Sky map. | ||
| 273 | + ***************************************************************************/ | ||
| 274 | +GSkymap& GSkymap::operator=(const GSkymap& map) | ||
| 275 | +{ | ||
| 276 | + // Execute only if object is not identical | ||
| 277 | + if (this != &map) { | ||
| 278 | + | ||
| 279 | + // Free members | ||
| 280 | + free_members(); | ||
| 281 | + | ||
| 282 | + // Initialise private members for clean destruction | ||
| 283 | + init_members(); | ||
| 284 | + | ||
| 285 | + // Copy members | ||
| 286 | + copy_members(map); | ||
| 287 | + | ||
| 288 | + } // endif: object was not identical | ||
| 289 | + | ||
| 290 | + // Return this object | ||
| 291 | + return *this; | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | + | ||
| 295 | +/***********************************************************************//** | ||
| 296 | + * @brief Value setting operator | ||
| 297 | + * | ||
| 298 | + * @param[in] value Value. | ||
| 299 | + * @return Sky map. | ||
| 300 | + * | ||
| 301 | + * Sets all pixels to the specified @p value. | ||
| 302 | + ***************************************************************************/ | ||
| 303 | +GSkymap& GSkymap::operator=(const double& value) | ||
| 304 | +{ | ||
| 305 | + // Get number of pixels | ||
| 306 | + int num = m_num_pixels * m_num_maps; | ||
| 307 | + | ||
| 308 | + // Loop over all pixels | ||
| 309 | + for (int i = 0; i < num; ++i) { | ||
| 310 | + m_pixels[i] = value; | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + // Return this object | ||
| 314 | + return *this; | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | + | ||
| 318 | +/***********************************************************************//** | ||
| 319 | + * @brief Map addition operator | ||
| 320 | + * | ||
| 321 | + * @param[in] map Sky map. | ||
| 322 | + * @return Sky map. | ||
| 323 | + * | ||
| 324 | + * @exception GException::invalid_value | ||
| 325 | + * Mismatch between number of maps in skymap object. | ||
| 326 | + * | ||
| 327 | + * Adds the content of @p map to the skymap. The operator only works on sky | ||
| 328 | + * maps with an identical number of layers. The content is added by | ||
| 329 | + * bi-linearily interpolating the values in the source sky map, allowing thus | ||
| 330 | + * for a reprojection of sky map values. | ||
| 331 | + * | ||
| 332 | + * @todo The method is not optimized for speed as the transformation is done | ||
| 333 | + * for each layer separately. A private method should be introduced that | ||
| 334 | + * does the transformation, allowing the to loop more effectively over the | ||
| 335 | + * layers. | ||
| 336 | + ***************************************************************************/ | ||
| 337 | +GSkymap& GSkymap::operator+=(const GSkymap& map) | ||
| 338 | +{ | ||
| 339 | + // Check if number of layers are identical | ||
| 340 | + if (map.nmaps() != nmaps()) { | ||
| 341 | + std::string msg = "Mismatch of number of maps in skymap object" | ||
| 342 | + " ("+gammalib::str(nmaps())+" maps in destination" | ||
| 343 | + " map, "+gammalib::str(map.nmaps())+" in source" | ||
| 344 | + " map."; | ||
| 345 | + throw GException::invalid_value(G_OP_UNARY_ADD, msg); | ||
| 346 | + } | ||
| 347 | + | ||
| 348 | + // Loop over all pixels of sky map | ||
| 349 | + for (int index = 0; index < npix(); ++index) { | ||
| 350 | + | ||
| 351 | + // Get sky direction of actual pixel | ||
| 352 | + GSkyDir dir = inx2dir(index); | ||
| 353 | + | ||
| 354 | + // Loop over all layers | ||
| 355 | + for (int layer = 0; layer < nmaps(); ++layer) { | ||
| 356 | + | ||
| 357 | + // Add value | ||
| 358 | + (*this)(index, layer) += map(dir, layer); | ||
| 359 | + | ||
| 360 | + } // endfor: looped over all layers | ||
| 361 | + | ||
| 362 | + } // endfor: looped over all pixels | ||
| 363 | + | ||
| 364 | + // Return this object | ||
| 365 | + return *this; | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | + | ||
| 369 | +/***********************************************************************//** | ||
| 370 | + * @brief Value addition operator | ||
| 371 | + * | ||
| 372 | + * @param[in] value Value. | ||
| 373 | + * @return Sky map. | ||
| 374 | + * | ||
| 375 | + * Add @p value to all sky map pixels. | ||
| 376 | + ***************************************************************************/ | ||
| 377 | +GSkymap& GSkymap::operator+=(const double& value) | ||
| 378 | +{ | ||
| 379 | + // Set total number of sky map pixels | ||
| 380 | + int num = m_num_pixels * m_num_maps; | ||
| 381 | + | ||
| 382 | + // Loop over all pixels of sky map | ||
| 383 | + for (int i = 0; i < num; ++i) { | ||
| 384 | + m_pixels[i] += value; | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + // Return this object | ||
| 388 | + return *this; | ||
| 389 | +} | ||
| 390 | + | ||
| 391 | + | ||
| 392 | +/***********************************************************************//** | ||
| 393 | + * @brief Map subtraction operator | ||
| 394 | + * | ||
| 395 | + * @param[in] map Sky map. | ||
| 396 | + * @return Sky map. | ||
| 397 | + * | ||
| 398 | + * @exception GException::invalid_value | ||
| 399 | + * Mismatch between number of maps in skymap object. | ||
| 400 | + * | ||
| 401 | + * Subtracts the content of @p map from the skymap. The operator only works | ||
| 402 | + * on sky maps with an identical number of layers. The content is subtracted | ||
| 403 | + * by bi-linearily interpolating the values in the source sky map, allowing | ||
| 404 | + * thus for a reprojection of sky map values. | ||
| 405 | + * | ||
| 406 | + * @todo The method is not optimized for speed as the transformation is done | ||
| 407 | + * for each layer separately. A private method should be introduced that | ||
| 408 | + * does the transformation, allowing the to loop more effectively over the | ||
| 409 | + * layers. | ||
| 410 | + ***************************************************************************/ | ||
| 411 | +GSkymap& GSkymap::operator-=(const GSkymap& map) | ||
| 412 | +{ | ||
| 413 | + // Check if number of layers are identical | ||
| 414 | + if (map.nmaps() != nmaps()) { | ||
| 415 | + std::string msg = "Mismatch of number of maps in skymap object" | ||
| 416 | + " ("+gammalib::str(nmaps())+" maps in destination" | ||
| 417 | + " map, "+gammalib::str(map.nmaps())+" in source" | ||
| 418 | + " map."; | ||
| 419 | + throw GException::invalid_value(G_OP_UNARY_SUB, msg); | ||
| 420 | + } | ||
| 421 | + | ||
| 422 | + // Loop over all pixels of sky map | ||
| 423 | + for (int index = 0; index < npix(); ++index) { | ||
| 424 | + | ||
| 425 | + // Get sky direction of actual pixel | ||
| 426 | + GSkyDir dir = inx2dir(index); | ||
| 427 | + | ||
| 428 | + // Loop over all layers | ||
| 429 | + for (int layer = 0; layer < nmaps(); ++layer) { | ||
| 430 | + | ||
| 431 | + // Subtract value | ||
| 432 | + (*this)(index, layer) -= map(dir, layer); | ||
| 433 | + | ||
| 434 | + } // endfor: looped over all layers | ||
| 435 | + | ||
| 436 | + } // endfor: looped over all pixels | ||
| 437 | + | ||
| 438 | + // Return this object | ||
| 439 | + return *this; | ||
| 440 | +} | ||
| 441 | + | ||
| 442 | + | ||
| 443 | +/***********************************************************************//** | ||
| 444 | + * @brief Value subtraction operator | ||
| 445 | + * | ||
| 446 | + * @param[in] value Value. | ||
| 447 | + * @return Sky map. | ||
| 448 | + * | ||
| 449 | + * Subtracts @p value from all sky map pixels. | ||
| 450 | + ***************************************************************************/ | ||
| 451 | +GSkymap& GSkymap::operator-=(const double& value) | ||
| 452 | +{ | ||
| 453 | + // Set total number of sky map pixels | ||
| 454 | + int num = m_num_pixels * m_num_maps; | ||
| 455 | + | ||
| 456 | + // Loop over all pixels of sky map | ||
| 457 | + for (int i = 0; i < num; ++i) { | ||
| 458 | + m_pixels[i] -= value; | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + // Return this object | ||
| 462 | + return *this; | ||
| 463 | +} | ||
| 464 | + | ||
| 465 | + | ||
| 466 | +/***********************************************************************//** | ||
| 467 | + * @brief Multiplication operator | ||
| 468 | + * | ||
| 469 | + * @param[in] map Sky map. | ||
| 470 | + * @return Sky map. | ||
| 471 | + * | ||
| 472 | + * @exception GException::invalid_value | ||
| 473 | + * Mismatch between number of maps in skymap object. | ||
| 474 | + * | ||
| 475 | + * Multiplies the content of @p map from the skymap. The operator only works | ||
| 476 | + * on sky maps with an identical number of layers. The content is multiplied | ||
| 477 | + * by bi-linearily interpolating the values in the source sky map, allowing | ||
| 478 | + * thus for a reprojection of sky map values. | ||
| 479 | + * | ||
| 480 | + * @todo The method is not optimized for speed as the transformation is done | ||
| 481 | + * for each layer separately. A private method should be introduced that | ||
| 482 | + * does the transformation, allowing to loop more effectively over the | ||
| 483 | + * layers. | ||
| 484 | + ***************************************************************************/ | ||
| 485 | +GSkymap& GSkymap::operator*=(const GSkymap& map) | ||
| 486 | +{ | ||
| 487 | + // Check if number of layers are identical | ||
| 488 | + if (map.nmaps() != nmaps()) { | ||
| 489 | + std::string msg = "Mismatch of number of maps in skymap object" | ||
| 490 | + " ("+gammalib::str(nmaps())+" maps in destination" | ||
| 491 | + " map, "+gammalib::str(map.nmaps())+" in source" | ||
| 492 | + " map."; | ||
| 493 | + throw GException::invalid_value(G_OP_UNARY_MUL, msg); | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + // Loop over all pixels of sky map | ||
| 497 | + for (int index = 0; index < npix(); ++index) { | ||
| 498 | + | ||
| 499 | + // Get sky direction of actual pixel | ||
| 500 | + GSkyDir dir = inx2dir(index); | ||
| 501 | + | ||
| 502 | + // Loop over all layers | ||
| 503 | + for (int layer = 0; layer < nmaps(); ++layer) { | ||
| 504 | + | ||
| 505 | + // Subtract value | ||
| 506 | + (*this)(index, layer) *= map(dir, layer); | ||
| 507 | + | ||
| 508 | + } // endfor: looped over all layers | ||
| 509 | + | ||
| 510 | + } // endfor: looped over all pixels | ||
| 511 | + | ||
| 512 | + // Return this object | ||
| 513 | + return *this; | ||
| 514 | +} | ||
| 515 | + | ||
| 516 | + | ||
| 517 | +/***********************************************************************//** | ||
| 518 | + * @brief Sky map scaling operator | ||
| 519 | + * | ||
| 520 | + * @param[in] factor Scale factor. | ||
| 521 | + * @return Sky map. | ||
| 522 | + * | ||
| 523 | + * Multiplies all pixels of the sky map by the given scale @p factor. | ||
| 524 | + ***************************************************************************/ | ||
| 525 | +GSkymap& GSkymap::operator*=(const double& factor) | ||
| 526 | +{ | ||
| 527 | + // Compute total number of pixels | ||
| 528 | + int n = npix() * nmaps(); | ||
| 529 | + | ||
| 530 | + // Loop over all pixels | ||
| 531 | + double* pixel = m_pixels; | ||
| 532 | + for (int i = 0; i < n; ++i) { | ||
| 533 | + *pixel++ *= factor; | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + // Return this object | ||
| 537 | + return *this; | ||
| 538 | +} | ||
| 539 | + | ||
| 540 | + | ||
| 541 | +/***********************************************************************//** | ||
| 542 | + * @brief Division operator | ||
| 543 | + * | ||
| 544 | + * @param[in] map Sky map. | ||
| 545 | + * @return Sky map. | ||
| 546 | + * | ||
| 547 | + * @exception GException::invalid_value | ||
| 548 | + * Mismatch between number of maps in skymap object. | ||
| 549 | + * | ||
| 550 | + * Divides the content of @p map from the skymap. The operator only works | ||
| 551 | + * on sky maps with an identical number of layers. The content is divided | ||
| 552 | + * by bi-linearily interpolating the values in the source sky map, allowing | ||
| 553 | + * thus for a reprojection of sky map values. | ||
| 554 | + * | ||
| 555 | + * @todo The method is not optimized for speed as the transformation is done | ||
| 556 | + * for each layer separately. A private method should be introduced that | ||
| 557 | + * does the transformation, allowing to loop more effectively over the | ||
| 558 | + * layers. | ||
| 559 | + ***************************************************************************/ | ||
| 560 | +GSkymap& GSkymap::operator/=(const GSkymap& map) | ||
| 561 | +{ | ||
| 562 | + // Check if number of layers are identical | ||
| 563 | + if (map.nmaps() != nmaps()) { | ||
| 564 | + std::string msg = "Mismatch of number of maps in skymap object" | ||
| 565 | + " ("+gammalib::str(nmaps())+" maps in destination" | ||
| 566 | + " map, "+gammalib::str(map.nmaps())+" in source" | ||
| 567 | + " map."; | ||
| 568 | + throw GException::invalid_value(G_OP_UNARY_DIV, msg); | ||
| 569 | + } | ||
| 570 | + | ||
| 571 | + // Loop over all pixels of sky map | ||
| 572 | + for (int index = 0; index < npix(); ++index) { | ||
| 573 | + | ||
| 574 | + // Get sky direction of actual pixel | ||
| 575 | + GSkyDir dir = inx2dir(index); | ||
| 576 | + | ||
| 577 | + // Loop over all layers | ||
| 578 | + for (int layer = 0; layer < nmaps(); ++layer) { | ||
| 579 | + | ||
| 580 | + // Check for division by zero | ||
| 581 | + if (map(dir,layer) == 0.0) { | ||
| 582 | + std::string msg = "Trying to divide by zero." | ||
| 583 | + " Map entries have to be strictly non-zero" | ||
| 584 | + " for division"; | ||
| 585 | + throw GException::invalid_value(G_OP_UNARY_DIV, msg); | ||
| 586 | + } | ||
| 587 | + | ||
| 588 | + // Subtract value | ||
| 589 | + (*this)(index, layer) /= map(dir, layer); | ||
| 590 | + | ||
| 591 | + } // endfor: looped over all layers | ||
| 592 | + | ||
| 593 | + } // endfor: looped over all pixels | ||
| 594 | + | ||
| 595 | + // Return this object | ||
| 596 | + return *this; | ||
| 597 | +} | ||
| 598 | + | ||
| 599 | + | ||
| 600 | +/***********************************************************************//** | ||
| 601 | + * @brief Sky map division operator | ||
| 602 | + * | ||
| 603 | + * @param[in] factor Scale factor. | ||
| 604 | + * @return Sky map. | ||
| 605 | + * | ||
| 606 | + * @exception GException::invalid_argument | ||
| 607 | + * Division by zero error. | ||
| 608 | + * | ||
| 609 | + * Divides all pixels of the sky map by the given @p factor. | ||
| 610 | + ***************************************************************************/ | ||
| 611 | +#define G_OP_UNARY_DIV2 "GSkymap::operator/=(double&)" | ||
| 612 | +GSkymap& GSkymap::operator/=(const double& factor) | ||
| 613 | +{ | ||
| 614 | + // Check for division by zero | ||
| 615 | + if (factor == 0.0) { | ||
| 616 | + std::string msg = "Trying to divide sky map pixels by zero."; | ||
| 617 | + throw GException::invalid_argument(G_OP_UNARY_DIV2, msg); | ||
| 618 | + } | ||
| 619 | + | ||
| 620 | + // Compute total number of pixels | ||
| 621 | + int n = npix() * nmaps(); | ||
| 622 | + | ||
| 623 | + // Loop over all pixels | ||
| 624 | + double* pixel = m_pixels; | ||
| 625 | + for (int i = 0; i < n; ++i) { | ||
| 626 | + *pixel++ /= factor; | ||
| 627 | + } | ||
| 628 | + | ||
| 629 | + // Return this object | ||
| 630 | + return *this; | ||
| 631 | +} | ||
| 632 | + | ||
| 633 | + | ||
| 634 | +/***********************************************************************//** | ||
| 635 | + * @brief Pixel index access operator | ||
| 636 | + * | ||
| 637 | + * @param[in] index Pixel index [0,...,npix()-1]. | ||
| 638 | + * @param[in] map Map index [0,...,nmaps()-1]. | ||
| 639 | + * @return Sky map pixel value. | ||
| 640 | + * | ||
| 641 | + * @exception GException::out_of_range | ||
| 642 | + * Pixel index and/or map index are outside valid range. | ||
| 643 | + * | ||
| 644 | + * Access sky map pixel by its index, where the most quickly varying axis is | ||
| 645 | + * the x axis of the map. | ||
| 646 | + ***************************************************************************/ | ||
| 647 | +double& GSkymap::operator()(const int& index, const int& map) | ||
| 648 | +{ | ||
| 649 | + // Throw an error if pixel index or map index is not in valid range | ||
| 650 | + #if defined(G_RANGE_CHECK) | ||
| 651 | + if (index < 0 || index >= m_num_pixels) { | ||
| 652 | + throw GException::out_of_range(G_OP_ACCESS_1D, | ||
| 653 | + "Sky map pixel index", | ||
| 654 | + index, m_num_pixels); | ||
| 655 | + } | ||
| 656 | + if (map < 0 || map >= m_num_maps) { | ||
| 657 | + throw GException::out_of_range(G_OP_ACCESS_1D, | ||
| 658 | + "Sky map map index", | ||
| 659 | + map, m_num_maps); | ||
| 660 | + } | ||
| 661 | + #endif | ||
| 662 | + | ||
| 663 | + // Return reference to pixel value | ||
| 664 | + return m_pixels[index+m_num_pixels*map]; | ||
| 665 | +} | ||
| 666 | + | ||
| 667 | + | ||
| 668 | +/***********************************************************************//** | ||
| 669 | + * @brief Pixel index access operator (const variant) | ||
| 670 | + * | ||
| 671 | + * @param[in] index Pixel index [0,...,npix()-1]. | ||
| 672 | + * @param[in] map Map index [0,...,nmaps()-1]. | ||
| 673 | + * | ||
| 674 | + * @exception GException::out_of_range | ||
| 675 | + * Pixel index and/or map index are outside valid range. | ||
| 676 | + * | ||
| 677 | + * Access sky map pixel by its index, where the most quickly varying axis is | ||
| 678 | + * the x axis of the map. | ||
| 679 | + ***************************************************************************/ | ||
| 680 | +const double& GSkymap::operator()(const int& index, const int& map) const | ||
| 681 | +{ | ||
| 682 | + // Throw an error if pixel index or map index is not in valid range | ||
| 683 | + #if defined(G_RANGE_CHECK) | ||
| 684 | + if (index < 0 || index >= m_num_pixels) { | ||
| 685 | + throw GException::out_of_range(G_OP_ACCESS_1D, | ||
| 686 | + "Sky map pixel index", | ||
| 687 | + index, m_num_pixels); | ||
| 688 | + } | ||
| 689 | + if (map < 0 || map >= m_num_maps) { | ||
| 690 | + throw GException::out_of_range(G_OP_ACCESS_1D, | ||
| 691 | + "Sky map map index", | ||
| 692 | + map, m_num_maps); | ||
| 693 | + } | ||
| 694 | + #endif | ||
| 695 | + | ||
| 696 | + // Return reference to pixel value | ||
| 697 | + return m_pixels[index+m_num_pixels*map]; | ||
| 698 | +} | ||
| 699 | + | ||
| 700 | + | ||
| 701 | +/***********************************************************************//** | ||
| 702 | + * @brief Sky map pixel access operator | ||
| 703 | + * | ||
| 704 | + * @param[in] pixel Sky map pixel. | ||
| 705 | + * @param[in] map Map index [0,...,nmaps()-1]. | ||
| 706 | + * | ||
| 707 | + * @exception GException::out_of_range | ||
| 708 | + * Sky pixel and/or map index are outside valid range. | ||
| 709 | + * | ||
| 710 | + * Access sky map pixel by its 2D index (x,y) that is implemented by the | ||
| 711 | + * GSkyPixel class. | ||
| 712 | + * | ||
| 713 | + * @todo Implement proper skymap exception (actual is for matrix elements) | ||
| 714 | + ***************************************************************************/ | ||
| 715 | +double& GSkymap::operator()(const GSkyPixel& pixel, const int& map) | ||
| 716 | +{ | ||
| 717 | + // Throw an error if pixel index or map index is not in valid range | ||
| 718 | + #if defined(G_RANGE_CHECK) | ||
| 719 | + if (!contains(pixel)) { | ||
| 720 | + throw GException::out_of_range(G_OP_ACCESS_2D, | ||
| 721 | + int(pixel.x()), int(pixel.y()), | ||
| 722 | + m_num_x-1, m_num_y-1); | ||
| 723 | + } | ||
| 724 | + if (map < 0 || map >= m_num_maps) { | ||
| 725 | + throw GException::out_of_range(G_OP_ACCESS_2D, | ||
| 726 | + "Sky map map index", | ||
| 727 | + map, m_num_maps); | ||
| 728 | + } | ||
| 729 | + #endif | ||
| 730 | + | ||
| 731 | + // Get pixel index | ||
| 732 | + int index = pix2inx(pixel); | ||
| 733 | + | ||
| 734 | + // Return reference to pixel value | ||
| 735 | + return m_pixels[index+m_num_pixels*map]; | ||
| 736 | +} | ||
| 737 | + | ||
| 738 | + | ||
| 739 | +/***********************************************************************//** | ||
| 740 | + * @brief Sky map pixel access operator | ||
| 741 | + * | ||
| 742 | + * @param[in] pixel Sky map pixel. | ||
| 743 | + * @param[in] map Map index [0,...,nmaps()-1]. | ||
| 744 | + * | ||
| 745 | + * @exception GException::out_of_range | ||
| 746 | + * Sky pixel and/or map index are outside valid range. | ||
| 747 | + * | ||
| 748 | + * Access sky map pixel by its 2D index (x,y) that is implemented by the | ||
| 749 | + * GSkyPixel class. | ||
| 750 | + * | ||
| 751 | + * @todo Implement proper skymap exception (actual is for matrix elements) | ||
| 752 | + ***************************************************************************/ | ||
| 753 | +const double& GSkymap::operator()(const GSkyPixel& pixel, const int& map) const | ||
| 754 | +{ | ||
| 755 | + // Throw an error if pixel index or map index is not in valid range | ||
| 756 | + #if defined(G_RANGE_CHECK) | ||
| 757 | + if (!contains(pixel)) { | ||
| 758 | + throw GException::out_of_range(G_OP_ACCESS_2D, | ||
| 759 | + int(pixel.x()), int(pixel.y()), | ||
| 760 | + m_num_x-1, m_num_y-1); | ||
| 761 | + } | ||
| 762 | + if (map < 0 || map >= m_num_maps) { | ||
| 763 | + throw GException::out_of_range(G_OP_ACCESS_2D, | ||
| 764 | + "Sky map map index", | ||
| 765 | + map, m_num_maps); | ||
| 766 | + } | ||
| 767 | + #endif | ||
| 768 | + | ||
| 769 | + // Get pixel index | ||
| 770 | + int index = pix2inx(pixel); | ||
| 771 | + | ||
| 772 | + // Return reference to pixel value | ||
| 773 | + return m_pixels[index+m_num_pixels*map]; | ||
| 774 | +} | ||
| 775 | + | ||
| 776 | + | ||
| 777 | +/***********************************************************************//** | ||
| 778 | + * @brief Return interpolated skymap value for sky direction | ||
| 779 | + * | ||
| 780 | + * @param[in] dir Sky direction. | ||
| 781 | + * @param[in] map Map index [0,...,nmaps()-1]. | ||
| 782 | + * @return Sky intensity. | ||
| 783 | + * | ||
| 784 | + * @exception GException::out_of_range | ||
| 785 | + * Map index lies outside valid range. | ||
| 786 | + * | ||
| 787 | + * Returns the skymap value for a given sky direction, obtained by bi-linear | ||
| 788 | + * interpolation of the neighbouring pixels. If the sky direction falls | ||
| 789 | + * outside the area covered by the skymap, a value of 0 is returned. | ||
| 790 | + * | ||
| 791 | + * The method implements a computation cache that avoids recomputation of | ||
| 792 | + * interpolation indices and weights in case that the same sky direction | ||
| 793 | + * is requested several times. This speeds up use cases where skymap values | ||
| 794 | + * for various map indices have to be returned for the same sky direction. | ||
| 795 | + ***************************************************************************/ | ||
| 796 | +double GSkymap::operator()(const GSkyDir& dir, const int& map) const | ||
| 797 | +{ | ||
| 798 | + // Throw an error if the map index is not in valid range | ||
| 799 | + #if defined(G_RANGE_CHECK) | ||
| 800 | + if (map < 0 || map >= m_num_maps) { | ||
| 801 | + throw GException::out_of_range(G_OP_VALUE, | ||
| 802 | + "Sky map map index", | ||
| 803 | + map, m_num_maps); | ||
| 804 | + } | ||
| 805 | + #endif | ||
| 806 | + | ||
| 807 | + // Initialise intensity | ||
| 808 | + double intensity = 0.0; | ||
| 809 | + | ||
| 810 | + // If the pre-computation cache has not been set or if the sky direction | ||
| 811 | + // has changed then compute the bilinear interpolator | ||
| 812 | + if (!m_hascache || (dir != m_last_dir)) { | ||
| 813 | + | ||
| 814 | + // Perform computation for HealPix map | ||
| 815 | + if (m_proj->size() == 1) { | ||
| 816 | + | ||
| 817 | + // Get Healpix interpolator | ||
| 818 | + m_interpol = static_cast<GHealpix*>(m_proj)->interpolator(dir); | ||
| 819 | + | ||
| 820 | + // Set containment flag and store actual sky direction as last | ||
| 821 | + // direction | ||
| 822 | + m_hascache = true; | ||
| 823 | + m_contained = true; | ||
| 824 | + m_last_dir = dir; | ||
| 825 | + | ||
| 826 | + } // endif: we had a Healpix projection | ||
| 827 | + | ||
| 828 | + // ... otherwise perform computation for WCS map | ||
| 829 | + else { | ||
| 830 | + | ||
| 831 | + // Determine sky pixel. At this point an exception may occur | ||
| 832 | + // in case that the pixel cannot be represented by the | ||
| 833 | + // relevant projection. We catch this exception here | ||
| 834 | + try { | ||
| 835 | + | ||
| 836 | + // Determine sky pixel | ||
| 837 | + GSkyPixel pixel = dir2pix(dir); | ||
| 838 | + | ||
| 839 | + // Set containment flag and store actual sky direction | ||
| 840 | + // as last direction | ||
| 841 | + m_hascache = true; | ||
| 842 | + m_contained = contains(pixel); | ||
| 843 | + m_last_dir = dir; | ||
| 844 | + | ||
| 845 | + // Continue only if pixel is within the map | ||
| 846 | + if (m_contained) { | ||
| 847 | + | ||
| 848 | + // Set left indices for interpolation. The left index is | ||
| 849 | + // comprised between 0 and npixels-2. By definition, the | ||
| 850 | + // right index is then the left index + 1 | ||
| 851 | + int inx_x = int(pixel.x()); | ||
| 852 | + int inx_y = int(pixel.y()); | ||
| 853 | + if (inx_x < 0) { | ||
| 854 | + inx_x = 0; | ||
| 855 | + } | ||
| 856 | + else if (inx_x > m_num_x-2) { | ||
| 857 | + inx_x = m_num_x - 2; | ||
| 858 | + } | ||
| 859 | + if (inx_y < 0) { | ||
| 860 | + inx_y = 0; | ||
| 861 | + } | ||
| 862 | + else if (inx_y > m_num_y-2) { | ||
| 863 | + inx_y = m_num_y - 2; | ||
| 864 | + } | ||
| 865 | + | ||
| 866 | + // Set weighting factors for interpolation | ||
| 867 | + double wgt_x_right = (pixel.x() - inx_x); | ||
| 868 | + double wgt_x_left = 1.0 - wgt_x_right; | ||
| 869 | + double wgt_y_right = (pixel.y() - inx_y); | ||
| 870 | + double wgt_y_left = 1.0 - wgt_y_right; | ||
| 871 | + | ||
| 872 | + // Compute skymap pixel indices for bi-linear interpolation | ||
| 873 | + m_interpol.index1() = inx_x + inx_y * m_num_x; | ||
| 874 | + m_interpol.index2() = m_interpol.index1() + m_num_x; | ||
| 875 | + m_interpol.index3() = m_interpol.index1() + 1; | ||
| 876 | + m_interpol.index4() = m_interpol.index2() + 1; | ||
| 877 | + | ||
| 878 | + // Compute weighting factors for bi-linear interpolation | ||
| 879 | + m_interpol.weight1() = wgt_x_left * wgt_y_left; | ||
| 880 | + m_interpol.weight2() = wgt_x_left * wgt_y_right; | ||
| 881 | + m_interpol.weight3() = wgt_x_right * wgt_y_left; | ||
| 882 | + m_interpol.weight4() = wgt_x_right * wgt_y_right; | ||
| 883 | + | ||
| 884 | + } // endif: pixel was contained in map | ||
| 885 | + | ||
| 886 | + } // endtry: pixel computation was successful | ||
| 887 | + catch (GException::wcs_invalid_phi_theta) { | ||
| 888 | + m_contained = false; | ||
| 889 | + } | ||
| 890 | + | ||
| 891 | + } // endelse: we had a WCS map | ||
| 892 | + | ||
| 893 | + } // endif: computation of the bi-linear interpolater was required | ||
| 894 | + | ||
| 895 | + // Compute the interpolated intensity if the pixel is contained in | ||
| 896 | + // the map | ||
| 897 | + if (m_contained) { | ||
| 898 | + | ||
| 899 | + // Compute map offset | ||
| 900 | + int offset = m_num_pixels * map; | ||
| 901 | + | ||
| 902 | + // Compute interpolated skymap value | ||
| 903 | + intensity = m_interpol(m_pixels+offset); | ||
| 904 | + | ||
| 905 | + } // endif: direction was contained in map | ||
| 906 | + | ||
| 907 | + // Return intensity | ||
| 908 | + return intensity; | ||
| 909 | +} | ||
| 910 | + | ||
| 911 | + | ||
| 912 | +/*========================================================================== | ||
| 913 | + = = | ||
| 914 | + = Public methods = | ||
| 915 | + = = | ||
| 916 | + ==========================================================================*/ | ||
| 917 | + | ||
| 918 | + /***********************************************************************//** | ||
| 919 | + * @brief Clear instance. | ||
| 920 | + * | ||
| 921 | + * Resets the sky map to the initial state. | ||
| 922 | + ***************************************************************************/ | ||
| 923 | +void GSkymap::clear(void) | ||
| 924 | +{ | ||
| 925 | + // Free class members | ||
| 926 | + free_members(); | ||
| 927 | + | ||
| 928 | + // Initialise members | ||
| 929 | + init_members(); | ||
| 930 | + | ||
| 931 | + // Return | ||
| 932 | + return; | ||
| 933 | +} | ||
| 934 | + | ||
| 935 | + | ||
| 936 | +/***********************************************************************//** | ||
| 937 | + * @brief Clone sky map | ||
| 938 | + * | ||
| 939 | + * @return Pointer to deep copy of sky map. | ||
| 940 | + ***************************************************************************/ | ||
| 941 | +GSkymap* GSkymap::clone(void) const | ||
| 942 | +{ | ||
| 943 | + return new GSkymap(*this); | ||
| 944 | +} | ||
| 945 | + | ||
| 946 | + | ||
| 947 | +/***********************************************************************//** | ||
| 948 | + * @brief Set number of maps | ||
| 949 | + * | ||
| 950 | + * @param[in] nmaps Number of maps. | ||
| 951 | + * | ||
| 952 | + * @exception GException::invalid_argument | ||
| 953 | + * Invalid number of maps specified. | ||
| 954 | + * | ||
| 955 | + * Redefines the number of maps in an GSkymap object. If the number of maps | ||
| 956 | + * is increased with respect to the existing number, additional maps with | ||
| 957 | + * pixel values of zero are append to the object. Existing map pixel values | ||
| 958 | + * are kept. If the number of maps is decreased with respect to the existing | ||
| 959 | + * number, the excedent maps are dropped. The remaining map pixel values are | ||
| 960 | + * kept. | ||
| 961 | + ***************************************************************************/ | ||
| 962 | +void GSkymap::nmaps(const int& nmaps) | ||
| 963 | +{ | ||
| 964 | + // Throw an exception if less than 1 map is required | ||
| 965 | + if (nmaps < 1) { | ||
| 966 | + std::string msg = "At least one map is required in an GSkymap object." | ||
| 967 | + " Please specify an argument >=1."; | ||
| 968 | + throw GException::invalid_argument(G_NMAPS, msg); | ||
| 969 | + } | ||
| 970 | + | ||
| 971 | + // If the map has pixels and if the number of maps changes then set a new | ||
| 972 | + // number of maps. Copy over any existing information. | ||
| 973 | + if (m_num_pixels > 0 && nmaps != m_num_maps) { | ||
| 974 | + | ||
| 975 | + // Compute new skymap size | ||
| 976 | + int new_size = m_num_pixels * nmaps; | ||
| 977 | + | ||
| 978 | + // Allocate memory for new map | ||
| 979 | + double* pixels = new double[new_size]; | ||
| 980 | + | ||
| 981 | + // Copy over existing pixels | ||
| 982 | + int num_copy = (nmaps > m_num_maps) ? m_num_maps : nmaps; | ||
| 983 | + num_copy *= m_num_pixels; | ||
| 984 | + for (int i = 0; i < num_copy; ++i) { | ||
| 985 | + pixels[i] = m_pixels[i]; | ||
| 986 | + } | ||
| 987 | + | ||
| 988 | + // Set any additional pixels to zero | ||
| 989 | + if (nmaps > m_num_maps) { | ||
| 990 | + for (int i = num_copy; i < new_size; ++i) { | ||
| 991 | + pixels[i] = 0.0; | ||
| 992 | + } | ||
| 993 | + } | ||
| 994 | + | ||
| 995 | + // Free existing pixels | ||
| 996 | + if (m_pixels != NULL) delete [] m_pixels; | ||
| 997 | + | ||
| 998 | + // Set pointer to stacked pixels | ||
| 999 | + m_pixels = pixels; | ||
| 1000 | + | ||
| 1001 | + // Set number of maps | ||
| 1002 | + m_num_maps = nmaps; | ||
| 1003 | + | ||
| 1004 | + } // endif: map had pixels | ||
| 1005 | + | ||
| 1006 | + // Return | ||
| 1007 | + return; | ||
| 1008 | +} | ||
| 1009 | + | ||
| 1010 | + | ||
| 1011 | +/***********************************************************************//** | ||
| 1012 | + * @brief Converts pixel index into sky map pixel | ||
| 1013 | + * | ||
| 1014 | + * @param[in] index Pixel index [0,...,npix()-1]. | ||
| 1015 | + * @return Sky map pixel. | ||
| 1016 | + * | ||
| 1017 | + * Converts the pixel @p index into a sky map pixel (GSkyPixel).The dimension | ||
| 1018 | + * of GSkyPixel will be identical to the dimension of the sky map (i.e. a 1D | ||
| 1019 | + * sky map leads to a 1D GSkyPixel object, a 2D sky map leads to a 2D | ||
| 1020 | + * GSkyPixel object. | ||
| 1021 | + ***************************************************************************/ | ||
| 1022 | +GSkyPixel GSkymap::inx2pix(const int& index) const | ||
| 1023 | +{ | ||
| 1024 | + // Initialise sky map pixel | ||
| 1025 | + GSkyPixel pixel; | ||
| 1026 | + | ||
| 1027 | + // Get x and y indices | ||
| 1028 | + if (m_num_x != 0) { //!< 2D sky map | ||
| 1029 | + pixel.x(double(index % m_num_x)); | ||
| 1030 | + pixel.y(double(index / m_num_x)); | ||
| 1031 | + } | ||
| 1032 | + else { //!< 1D sky map | ||
| 1033 | + pixel.index(index); | ||
| 1034 | + } | ||
| 1035 | + | ||
| 1036 | + // Return pixel | ||
| 1037 | + return pixel; | ||
| 1038 | +} | ||
| 1039 | + | ||
| 1040 | + | ||
| 1041 | +/***********************************************************************//** | ||
| 1042 | + * @brief Returns sky direction of pixel | ||
| 1043 | + * | ||
| 1044 | + * @param[in] index Pixel index [0,...,npix()-1]. | ||
| 1045 | + * @return Sky direction. | ||
| 1046 | + * | ||
| 1047 | + * @exception GException::invalid_value | ||
| 1048 | + * No valid sky projection found. | ||
| 1049 | + * | ||
| 1050 | + * Returns sky direction for a given pixel index. | ||
| 1051 | + ***************************************************************************/ | ||
| 1052 | +GSkyDir GSkymap::inx2dir(const int& index) const | ||
| 1053 | +{ | ||
| 1054 | + // Throw error if sky projection is not valid | ||
| 1055 | + if (m_proj == NULL) { | ||
| 1056 | + std::string msg = "Sky projection has not been defined."; | ||
| 1057 | + throw GException::invalid_value(G_INX2DIR, msg); | ||
| 1058 | + } | ||
| 1059 | + | ||
| 1060 | + // Determine sky direction from pixel index. | ||
| 1061 | + GSkyDir dir = m_proj->pix2dir(inx2pix(index)); | ||
| 1062 | + | ||
| 1063 | + // Return sky direction | ||
| 1064 | + return dir; | ||
| 1065 | +} | ||
| 1066 | + | ||
| 1067 | + | ||
| 1068 | +/***********************************************************************//** | ||
| 1069 | + * @brief Returns sky direction of pixel | ||
| 1070 | + * | ||
| 1071 | + * @param[in] pixel Sky map pixel. | ||
| 1072 | + * @return Sky direction. | ||
| 1073 | + * | ||
| 1074 | + * @exception GException::invalid_value | ||
| 1075 | + * No valid sky projection found. | ||
| 1076 | + * @exception GException::invalid_argument | ||
| 1077 | + * 2D sky map pixel used to access 1D projection. | ||
| 1078 | + * | ||
| 1079 | + * Returns sky direction for a given sky map @p pixel. | ||
| 1080 | + ***************************************************************************/ | ||
| 1081 | +GSkyDir GSkymap::pix2dir(const GSkyPixel& pixel) const | ||
| 1082 | +{ | ||
| 1083 | + // Throw error if WCS is not valid | ||
| 1084 | + if (m_proj == NULL) { | ||
| 1085 | + std::string msg = "Sky projection has not been defined."; | ||
| 1086 | + throw GException::invalid_value(G_PIX2DIR, msg); | ||
| 1087 | + } | ||
| 1088 | + | ||
| 1089 | + // Initialise sky direction | ||
| 1090 | + GSkyDir dir; | ||
| 1091 | + | ||
| 1092 | + // If pixel size matches the projection size then perform a straight | ||
| 1093 | + // forward conversion | ||
| 1094 | + if (m_proj->size() == pixel.size()) { | ||
| 1095 | + dir = m_proj->pix2dir(pixel); | ||
| 1096 | + } | ||
| 1097 | + | ||
| 1098 | + // ... otherwise, if we have a 2D projection but a 1D pixel then | ||
| 1099 | + // interpret the pixel as the linear index in the pixel array | ||
| 1100 | + else if (m_proj->size() == 2) { | ||
| 1101 | + dir = m_proj->pix2dir(GSkyPixel(inx2pix(int(pixel)))); | ||
| 1102 | + } | ||
| 1103 | + | ||
| 1104 | + // ... otherwise we have a 1D projection but a 2D pixel. There is | ||
| 1105 | + // no unambiguous way to handle this case, hence we throw an exception | ||
| 1106 | + else { | ||
| 1107 | + std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+ | ||
| 1108 | + " is used to determine the sky direction for" | ||
| 1109 | + " the 1-dimensional sky projection \""+ | ||
| 1110 | + m_proj->name()+"\"\n" | ||
| 1111 | + "Please specify a 1-dimensional sky map pixel."; | ||
| 1112 | + throw GException::invalid_argument(G_PIX2DIR, msg); | ||
| 1113 | + } | ||
| 1114 | + | ||
| 1115 | + // Return sky direction | ||
| 1116 | + return dir; | ||
| 1117 | +} | ||
| 1118 | + | ||
| 1119 | + | ||
| 1120 | +/***********************************************************************//** | ||
| 1121 | + * @brief Converts sky map pixel into pixel index | ||
| 1122 | + * | ||
| 1123 | + * @param[in] pixel Sky map pixel. | ||
| 1124 | + * @return Pixel index [0,...,npix()-1]. | ||
| 1125 | + * | ||
| 1126 | + * Converts a sky map @p pixel into the pixel index. | ||
| 1127 | + ***************************************************************************/ | ||
| 1128 | +int GSkymap::pix2inx(const GSkyPixel& pixel) const | ||
| 1129 | +{ | ||
| 1130 | + // Initialise pixel index | ||
| 1131 | + int index = 0; | ||
| 1132 | + | ||
| 1133 | + // Handle 1D sky map pixel | ||
| 1134 | + if (pixel.is_1D()) { | ||
| 1135 | + index = int(pixel); | ||
| 1136 | + } | ||
| 1137 | + | ||
| 1138 | + // Handle 2D sky map pixel | ||
| 1139 | + else if (pixel.is_2D()) { | ||
| 1140 | + | ||
| 1141 | + // Get x and y indices by rounding the (x,y) values | ||
| 1142 | + int ix = int(pixel.x()+0.5); | ||
| 1143 | + int iy = int(pixel.y()+0.5); | ||
| 1144 | + | ||
| 1145 | + // Set index | ||
| 1146 | + index = ix + iy * m_num_x; | ||
| 1147 | + | ||
| 1148 | + } | ||
| 1149 | + | ||
| 1150 | + // Return index | ||
| 1151 | + return index; | ||
| 1152 | +} | ||
| 1153 | + | ||
| 1154 | + | ||
| 1155 | +/***********************************************************************//** | ||
| 1156 | + * @brief Returns pixel index for a given sky direction | ||
| 1157 | + * | ||
| 1158 | + * @param[in] dir Sky direction. | ||
| 1159 | + * @return Pixel index [0,...,npix()-1]. | ||
| 1160 | + * | ||
| 1161 | + * @exception GException::invalid_value | ||
| 1162 | + * No valid sky projection found. | ||
| 1163 | + * | ||
| 1164 | + * Returns sky map pixel index for a given sky direction. | ||
| 1165 | + ***************************************************************************/ | ||
| 1166 | +int GSkymap::dir2inx(const GSkyDir& dir) const | ||
| 1167 | +{ | ||
| 1168 | + // Throw error if WCS is not valid | ||
| 1169 | + if (m_proj == NULL) { | ||
| 1170 | + std::string msg = "Sky projection has not been defined."; | ||
| 1171 | + throw GException::invalid_value(G_DIR2INX, msg); | ||
| 1172 | + } | ||
| 1173 | + | ||
| 1174 | + // Determine pixel index for a given sky direction | ||
| 1175 | + int index = pix2inx(m_proj->dir2pix(dir)); | ||
| 1176 | + | ||
| 1177 | + // Return pixel index | ||
| 1178 | + return index; | ||
| 1179 | +} | ||
| 1180 | + | ||
| 1181 | + | ||
| 1182 | +/***********************************************************************//** | ||
| 1183 | + * @brief Returns sky map pixel for a given sky direction | ||
| 1184 | + * | ||
| 1185 | + * @param[in] dir Sky direction. | ||
| 1186 | + * @return Sky map pixel. | ||
| 1187 | + * | ||
| 1188 | + * @exception GException::invalid_value | ||
| 1189 | + * No valid sky projection found. | ||
| 1190 | + * | ||
| 1191 | + * Returns sky map pixel for a given sky direction. | ||
| 1192 | + ***************************************************************************/ | ||
| 1193 | +GSkyPixel GSkymap::dir2pix(const GSkyDir& dir) const | ||
| 1194 | +{ | ||
| 1195 | + // Throw error if WCS is not valid | ||
| 1196 | + if (m_proj == NULL) { | ||
| 1197 | + std::string msg = "Sky projection has not been defined."; | ||
| 1198 | + throw GException::invalid_value(G_DIR2PIX, msg); | ||
| 1199 | + } | ||
| 1200 | + | ||
| 1201 | + // Determine pixel for a given sky direction | ||
| 1202 | + GSkyPixel pixel = m_proj->dir2pix(dir); | ||
| 1203 | + | ||
| 1204 | + // Return pixel | ||
| 1205 | + return pixel; | ||
| 1206 | +} | ||
| 1207 | + | ||
| 1208 | + | ||
| 1209 | +/***********************************************************************//** | ||
| 1210 | + * @brief Returns solid angle of pixel | ||
| 1211 | + * | ||
| 1212 | + * @param[in] index Pixel index [0,...,npix()-1]. | ||
| 1213 | + * @return Solid angle (steradians) | ||
| 1214 | + * | ||
| 1215 | + * @exception GException::invalid_value | ||
| 1216 | + * No valid sky projection found. | ||
| 1217 | + * | ||
| 1218 | + * Returns the solid angle of the pixel with the specified @p index. | ||
| 1219 | + ***************************************************************************/ | ||
| 1220 | +double GSkymap::solidangle(const int& index) const | ||
| 1221 | +{ | ||
| 1222 | + // Throw error if WCS is not valid | ||
| 1223 | + if (m_proj == NULL) { | ||
| 1224 | + std::string msg = "Sky projection has not been defined."; | ||
| 1225 | + throw GException::invalid_value(G_SOLIDANGLE1, msg); | ||
| 1226 | + } | ||
| 1227 | + | ||
| 1228 | + // Determine solid angle from pixel index. | ||
| 1229 | + double solidangle = m_proj->solidangle(inx2pix(index)); | ||
| 1230 | + | ||
| 1231 | + // Return solid angle | ||
| 1232 | + return solidangle; | ||
| 1233 | +} | ||
| 1234 | + | ||
| 1235 | + | ||
| 1236 | +/***********************************************************************//** | ||
| 1237 | + * @brief Returns solid angle of pixel | ||
| 1238 | + * | ||
| 1239 | + * @param[in] pixel Sky map pixel. | ||
| 1240 | + * @return Solid angle (steradians) | ||
| 1241 | + * | ||
| 1242 | + * @exception GException::invalid_value | ||
| 1243 | + * No valid sky projection found. | ||
| 1244 | + * | ||
| 1245 | + * Returns the solid angle of the specified sky map @p pixel. | ||
| 1246 | + ***************************************************************************/ | ||
| 1247 | +double GSkymap::solidangle(const GSkyPixel& pixel) const | ||
| 1248 | +{ | ||
| 1249 | + // Throw error if WCS is not valid | ||
| 1250 | + if (m_proj == NULL) { | ||
| 1251 | + std::string msg = "Sky projection has not been defined."; | ||
| 1252 | + throw GException::invalid_value(G_SOLIDANGLE2, msg); | ||
| 1253 | + } | ||
| 1254 | + | ||
| 1255 | + // Initialise solid angle | ||
| 1256 | + double solidangle = 0.0; | ||
| 1257 | + | ||
| 1258 | + // If pixel size matches the projection size then perform a straight | ||
| 1259 | + // forward solid angle determination | ||
| 1260 | + if (m_proj->size() == pixel.size()) { | ||
| 1261 | + solidangle = m_proj->solidangle(pixel); | ||
| 1262 | + } | ||
| 1263 | + | ||
| 1264 | + // ... otherwise, if we have a 2D projection but a 1D pixel then | ||
| 1265 | + // interpret the pixel as the linear index in the pixel array | ||
| 1266 | + else if (m_proj->size() == 2) { | ||
| 1267 | + solidangle = m_proj->solidangle(GSkyPixel(inx2pix(int(pixel)))); | ||
| 1268 | + } | ||
| 1269 | + | ||
| 1270 | + // ... otherwise we have a 1D projection but a 2D pixel. There is | ||
| 1271 | + // no unambiguous way to handle this case, hence we throw an exception | ||
| 1272 | + else { | ||
| 1273 | + std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+ | ||
| 1274 | + " is used to determine the solid angle for" | ||
| 1275 | + " the 1-dimensional sky projection \""+ | ||
| 1276 | + m_proj->name()+"\"\n" | ||
| 1277 | + "Please specify a 1-dimensional sky map pixel."; | ||
| 1278 | + throw GException::invalid_argument(G_SOLIDANGLE2, msg); | ||
| 1279 | + } | ||
| 1280 | + | ||
| 1281 | + // Return solid angle | ||
| 1282 | + return solidangle; | ||
| 1283 | +} | ||
| 1284 | + | ||
| 1285 | + | ||
| 1286 | +/***********************************************************************//** | ||
| 1287 | + * @brief Set sky projection | ||
| 1288 | + * | ||
| 1289 | + * @param[in] proj Sky projection. | ||
| 1290 | + * | ||
| 1291 | + * Sets the projection from celestial to pixel coordinates. The method | ||
| 1292 | + * performs a deep copy of @p proj, allowing to destroy the argument after | ||
| 1293 | + * using the method. | ||
| 1294 | + * | ||
| 1295 | + * Warning: this method may corrupt the GSkymap object as it allows assigning | ||
| 1296 | + * for example a 1D projection to a 2D skymap. Please use this method only | ||
| 1297 | + * when you know what you're doing. | ||
| 1298 | + * | ||
| 1299 | + * @todo We may restrict this method to not allow changing the projection | ||
| 1300 | + * dimension. | ||
| 1301 | + ***************************************************************************/ | ||
| 1302 | +void GSkymap::projection(const GSkyProjection& proj) | ||
| 1303 | +{ | ||
| 1304 | + // Free any existing WCS | ||
| 1305 | + if (m_proj != NULL) delete m_proj; | ||
| 1306 | + | ||
| 1307 | + // Clone input WCS | ||
| 1308 | + m_proj = proj.clone(); | ||
| 1309 | + | ||
| 1310 | + // Return | ||
| 1311 | + return; | ||
| 1312 | +} | ||
| 1313 | + | ||
| 1314 | + | ||
| 1315 | +/***********************************************************************//** | ||
| 1316 | + * @brief Verifies if sky direction falls in map | ||
| 1317 | + * | ||
| 1318 | + * @param[in] dir Sky direction. | ||
| 1319 | + * | ||
| 1320 | + * This method checks if the specified sky direction falls within the pixels | ||
| 1321 | + * covered by the skymap. The method uses the dir2xy method to convert the | ||
| 1322 | + * sky direction into 2D pixel indices, and then checks whether the pixel | ||
| 1323 | + * indices fall in the skymap. | ||
| 1324 | + ***************************************************************************/ | ||
| 1325 | +bool GSkymap::contains(const GSkyDir& dir) const | ||
| 1326 | +{ | ||
| 1327 | + // Convert sky direction into sky pixel | ||
| 1328 | + GSkyPixel pixel = dir2pix(dir); | ||
| 1329 | + | ||
| 1330 | + // Return location flag | ||
| 1331 | + return (contains(pixel)); | ||
| 1332 | +} | ||
| 1333 | + | ||
| 1334 | + | ||
| 1335 | +/***********************************************************************//** | ||
| 1336 | + * @brief Checks if sky map pixel falls in map | ||
| 1337 | + * | ||
| 1338 | + * @param[in] pixel Sky map pixel. | ||
| 1339 | + * @return Trus if pixels is within map, false otherwise. | ||
| 1340 | + * | ||
| 1341 | + * Checks whether the specified sky map @p pixel falls within the skymap | ||
| 1342 | + * or not. | ||
| 1343 | + ***************************************************************************/ | ||
| 1344 | +bool GSkymap::contains(const GSkyPixel& pixel) const | ||
| 1345 | +{ | ||
| 1346 | + // Initialise containment flag | ||
| 1347 | + bool inmap = false; | ||
| 1348 | + | ||
| 1349 | + // Test 1D pixels | ||
| 1350 | + if (pixel.is_1D()) { | ||
| 1351 | + if (pixel.index()+0.5 >= 0.0 && pixel.index()-0.5 < m_num_pixels) { | ||
| 1352 | + inmap = true; | ||
| 1353 | + } | ||
| 1354 | + } | ||
| 1355 | + | ||
| 1356 | + // Test 2D pixels | ||
| 1357 | + else if (pixel.is_2D()) { | ||
| 1358 | + | ||
| 1359 | + // If pixel is in range then set containment flag to true | ||
| 1360 | + if ((pixel.x()+0.5 >= 0.0 && pixel.x()-0.5 < m_num_x) && | ||
| 1361 | + (pixel.y()+0.5 >= 0.0 && pixel.y()-0.5 < m_num_y)) { | ||
| 1362 | + inmap = true; | ||
| 1363 | + } | ||
| 1364 | + | ||
| 1365 | + } | ||
| 1366 | + | ||
| 1367 | + // Return containment flag | ||
| 1368 | + return inmap; | ||
| 1369 | +} | ||
| 1370 | + | ||
| 1371 | + | ||
| 1372 | +/***********************************************************************//** | ||
| 1373 | + * @brief Extract maps into a new sky map object | ||
| 1374 | + * | ||
| 1375 | + * @param[in] map First map to extract | ||
| 1376 | + * @param[in] nmaps Number of maps to extract (default: 1) | ||
| 1377 | + * @return Extracted map(s). | ||
| 1378 | + * | ||
| 1379 | + * @exception GException::out_of_range | ||
| 1380 | + * First map index outside valid range | ||
| 1381 | + * @exception GException::invalid_argument | ||
| 1382 | + * Requested number of maps are not available. | ||
| 1383 | + * | ||
| 1384 | + * Extracts @p nmaps sky maps starting from @p map from the sky map. | ||
| 1385 | + ***************************************************************************/ | ||
| 1386 | +GSkymap GSkymap::extract(const int& map, const int& nmaps) const | ||
| 1387 | +{ | ||
| 1388 | + // Throw an exception if the first map index is invalid | ||
| 1389 | + if (map < 0 || map >= m_num_maps) { | ||
| 1390 | + throw GException::out_of_range(G_EXTRACT, "Sky map index", map, | ||
| 1391 | + m_num_maps); | ||
| 1392 | + } | ||
| 1393 | + | ||
| 1394 | + // Throw an exception if the number of maps is invalid | ||
| 1395 | + if (nmaps < 0) { | ||
| 1396 | + std::string msg = "The number of maps to extract cannot be negative " | ||
| 1397 | + "(nmaps="+gammalib::str(nmaps)+")."; | ||
| 1398 | + throw GException::invalid_argument(G_EXTRACT, msg); | ||
| 1399 | + } | ||
| 1400 | + if (nmaps > m_num_maps-map) { | ||
| 1401 | + std::string msg = "The number of maps to extract ("+ | ||
| 1402 | + gammalib::str(nmaps)+") exceeds the number of maps " | ||
| 1403 | + "that are available ("+ | ||
| 1404 | + gammalib::str(m_num_maps-map)+")."; | ||
| 1405 | + throw GException::invalid_argument(G_EXTRACT, msg); | ||
| 1406 | + } | ||
| 1407 | + | ||
| 1408 | + // Compute memory size for extracted map | ||
| 1409 | + int n_size = m_num_pixels * nmaps; | ||
| 1410 | + | ||
| 1411 | + // Allocate memory for extracted maps (handle the case that the | ||
| 1412 | + // extracted map can be empty) | ||
| 1413 | + double* pixels = NULL; | ||
| 1414 | + if (n_size > 0) { | ||
| 1415 | + pixels = new double[n_size]; | ||
| 1416 | + } | ||
| 1417 | + | ||
| 1418 | + // Extract pixels | ||
| 1419 | + double *src = m_pixels + map*m_num_pixels; | ||
| 1420 | + double *dst = pixels; | ||
| 1421 | + for (int i = 0; i < n_size; ++i) { | ||
| 1422 | + *dst++ = *src++; | ||
| 1423 | + } | ||
| 1424 | + | ||
| 1425 | + // Create a copy of the map | ||
| 1426 | + GSkymap result = *this; | ||
| 1427 | + | ||
| 1428 | + // Delete pixels from that map | ||
| 1429 | + if (result.m_pixels != NULL) delete [] result.m_pixels; | ||
| 1430 | + | ||
| 1431 | + // Attach copied pixels to the map | ||
| 1432 | + result.m_pixels = pixels; | ||
| 1433 | + | ||
| 1434 | + // Set number of maps | ||
| 1435 | + result.m_num_maps = nmaps; | ||
| 1436 | + | ||
| 1437 | + // Return map | ||
| 1438 | + return result; | ||
| 1439 | +} | ||
| 1440 | + | ||
| 1441 | + | ||
| 1442 | +/***********************************************************************//** | ||
| 1443 | + * @brief Stack all maps into a single map | ||
| 1444 | + * | ||
| 1445 | + * @return Stacked map. | ||
| 1446 | + * | ||
| 1447 | + * The methods replaces the sky map by a version with only a single map | ||
| 1448 | + * by summing over the pixel values for all maps. If the sky map has no | ||
| 1449 | + * pixels or there is only a single map in the object, the method does | ||
| 1450 | + * nothing. | ||
| 1451 | + ***************************************************************************/ | ||
| 1452 | +void GSkymap::stack_maps(void) | ||
| 1453 | +{ | ||
| 1454 | + // Continue only if the map has pixels and if there is more than 1 map | ||
| 1455 | + if (m_num_pixels > 0 && m_num_maps > 1) { | ||
| 1456 | + | ||
| 1457 | + // Allocate memory for stacked map | ||
| 1458 | + double* pixels = new double[m_num_pixels]; | ||
| 1459 | + | ||
| 1460 | + // Stack map and save in memory | ||
| 1461 | + for (int i = 0; i < m_num_pixels; ++i) { | ||
| 1462 | + double sum = 0.0; | ||
| 1463 | + for (int k = 0; k < m_num_maps; ++k) { | ||
| 1464 | + sum += (*this)(i,k); | ||
| 1465 | + } | ||
| 1466 | + pixels[i] = sum; | ||
| 1467 | + } | ||
| 1468 | + | ||
| 1469 | + // Free existing pixels | ||
| 1470 | + if (m_pixels != NULL) delete [] m_pixels; | ||
| 1471 | + | ||
| 1472 | + // Set pointer to stacked pixels | ||
| 1473 | + m_pixels = pixels; | ||
| 1474 | + | ||
| 1475 | + // Set number of maps to 1 | ||
| 1476 | + m_num_maps = 1; | ||
| 1477 | + | ||
| 1478 | + } // endif: map had pixels | ||
| 1479 | + | ||
| 1480 | + // Return | ||
| 1481 | + return; | ||
| 1482 | +} | ||
| 1483 | + | ||
| 1484 | + | ||
| 1485 | +/***********************************************************************//** | ||
| 1486 | + * @brief Load skymap from FITS file. | ||
| 1487 | + * | ||
| 1488 | + * @param[in] filename FITS file name.. | ||
| 1489 | + * | ||
| 1490 | + * Loads HEALPix and non HEALPix skymaps. First searches for HEALPix map in | ||
| 1491 | + * FITS file by scanning all HDUs for PIXTYPE=HEALPIX. If no HEALPix map has | ||
| 1492 | + * been found then search load first non-empty image. | ||
| 1493 | + * | ||
| 1494 | + * @todo Do we have to restrict a HEALPix map to a BinTable and a WCS map | ||
| 1495 | + * to a Double precision image??? | ||
| 1496 | + ***************************************************************************/ | ||
| 1497 | +void GSkymap::load(const std::string& filename) | ||
| 1498 | +{ | ||
| 1499 | + // Free memory and initialise members | ||
| 1500 | + free_members(); | ||
| 1501 | + init_members(); | ||
| 1502 | + | ||
| 1503 | + // Open FITS file | ||
| 1504 | + GFits fits(filename); | ||
| 1505 | + | ||
| 1506 | + // Get number of HDUs | ||
| 1507 | + int num = fits.size(); | ||
| 1508 | + | ||
| 1509 | + // Initialize load flag | ||
| 1510 | + bool loaded = false; | ||
| 1511 | + | ||
| 1512 | + // First search for HEALPix extension. We can skip the first extension | ||
| 1513 | + // since this is always an image and a HEALPix map is stored in a | ||
| 1514 | + // binary table | ||
| 1515 | + for (int extno = 1; extno < num; ++extno) { | ||
| 1516 | + | ||
| 1517 | + // Get reference to HDU | ||
| 1518 | + const GFitsHDU& hdu = *fits.at(extno); | ||
| 1519 | + | ||
| 1520 | + // If PIXTYPE keyword equals "HEALPIX" then load map | ||
| 1521 | + if (hdu.has_card("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") { | ||
| 1522 | + read_healpix(static_cast<const GFitsTable&>(hdu)); | ||
| 1523 | + loaded = true; | ||
| 1524 | + break; | ||
| 1525 | + } | ||
| 1526 | + | ||
| 1527 | + } // endfor: looped over HDUs | ||
| 1528 | + | ||
| 1529 | + // If we have not found a HEALPIX map then search now for image. | ||
| 1530 | + // Skip empty images | ||
| 1531 | + if (!loaded) { | ||
| 1532 | + for (int extno = 0; extno < num; ++extno) { | ||
| 1533 | + | ||
| 1534 | + // Get referene to HDU | ||
| 1535 | + const GFitsHDU& hdu = *fits.at(extno); | ||
| 1536 | + | ||
| 1537 | + // Skip if extension is not an image | ||
| 1538 | + if (extno > 0) { | ||
| 1539 | + if (hdu.string("XTENSION") != "IMAGE") | ||
| 1540 | + continue; | ||
| 1541 | + } | ||
| 1542 | + | ||
| 1543 | + // Load WCS map | ||
| 1544 | + read_wcs(static_cast<const GFitsImage&>(hdu)); | ||
| 1545 | + //loaded = true; | ||
| 1546 | + break; | ||
| 1547 | + | ||
| 1548 | + } // endfor: looped over HDUs | ||
| 1549 | + } // endif: no HEALPix map found | ||
| 1550 | + | ||
| 1551 | + // Close FITS file | ||
| 1552 | + fits.close(); | ||
| 1553 | + | ||
| 1554 | + // Return | ||
| 1555 | + return; | ||
| 1556 | +} | ||
| 1557 | + | ||
| 1558 | + | ||
| 1559 | +/***********************************************************************//** | ||
| 1560 | + * @brief Save skymap into FITS file. | ||
| 1561 | + * | ||
| 1562 | + * @param[in] filename FITS file name. | ||
| 1563 | + * @param[in] clobber Overwrite existing file? (true=yes) | ||
| 1564 | + * | ||
| 1565 | + * The method does nothing if the skymap holds no valid WCS. | ||
| 1566 | + ***************************************************************************/ | ||
| 1567 | +void GSkymap::save(const std::string& filename, bool clobber) const | ||
| 1568 | +{ | ||
| 1569 | + // Continue only if we have data to save | ||
| 1570 | + if (m_proj != NULL) { | ||
| 1571 | + | ||
| 1572 | + // Initialise HDU pointer | ||
| 1573 | + GFitsHDU* hdu = NULL; | ||
| 1574 | + | ||
| 1575 | + // Case A: Skymap is Healpix | ||
| 1576 | + if (m_proj->code() == "HPX") { | ||
| 1577 | + hdu = create_healpix_hdu(); | ||
| 1578 | + } | ||
| 1579 | + | ||
| 1580 | + // Case B: Skymap is not Healpix | ||
| 1581 | + else { | ||
| 1582 | + hdu = create_wcs_hdu(); | ||
| 1583 | + } | ||
| 1584 | + | ||
| 1585 | + // Create FITS file and save it to disk | ||
| 1586 | + if (hdu != NULL) { | ||
| 1587 | + GFits fits; | ||
| 1588 | + fits.append(*hdu); | ||
| 1589 | + fits.saveto(filename, clobber); | ||
| 1590 | + } | ||
| 1591 | + | ||
| 1592 | + // Delete HDU | ||
| 1593 | + if (hdu != NULL) delete hdu; | ||
| 1594 | + | ||
| 1595 | + } // endif: we had data to save | ||
| 1596 | + | ||
| 1597 | + // Return | ||
| 1598 | + return; | ||
| 1599 | +} | ||
| 1600 | + | ||
| 1601 | + | ||
| 1602 | +/***********************************************************************//** | ||
| 1603 | + * @brief Read skymap from FITS HDU | ||
| 1604 | + * | ||
| 1605 | + * @param[in] hdu FITS HDU. | ||
| 1606 | + ***************************************************************************/ | ||
| 1607 | +void GSkymap::read(const GFitsHDU& hdu) | ||
| 1608 | +{ | ||
| 1609 | + // Free memory and initialise members | ||
| 1610 | + free_members(); | ||
| 1611 | + init_members(); | ||
| 1612 | + | ||
| 1613 | + // Initialize load flag | ||
| 1614 | + bool loaded = false; | ||
| 1615 | + | ||
| 1616 | + // If PIXTYPE keyword equals "HEALPIX" then load map | ||
| 1617 | + if (hdu.has_card("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") { | ||
| 1618 | + read_healpix(static_cast<const GFitsTable&>(hdu)); | ||
| 1619 | + loaded = true; | ||
| 1620 | + } | ||
| 1621 | + | ||
| 1622 | + // ... otherwise try loading as non HEALPix map | ||
| 1623 | + if (!loaded) { | ||
| 1624 | + | ||
| 1625 | + // Load only if HDU contains an image | ||
| 1626 | + if (hdu.exttype() == 0) { | ||
| 1627 | + read_wcs(static_cast<const GFitsImage&>(hdu)); | ||
| 1628 | + //loaded = true; | ||
| 1629 | + } | ||
| 1630 | + | ||
| 1631 | + } // endif | ||
| 1632 | + | ||
| 1633 | + // Return | ||
| 1634 | + return; | ||
| 1635 | +} | ||
| 1636 | + | ||
| 1637 | + | ||
| 1638 | +/***********************************************************************//** | ||
| 1639 | + * @brief Write skymap into FITS file | ||
| 1640 | + * | ||
| 1641 | + * @param[in] file FITS file pointer. | ||
| 1642 | + ***************************************************************************/ | ||
| 1643 | +void GSkymap::write(GFits& file) const | ||
| 1644 | +{ | ||
| 1645 | + // Continue only if we have data to save | ||
| 1646 | + if (m_proj != NULL) { | ||
| 1647 | + | ||
| 1648 | + // Initialise HDU pointer | ||
| 1649 | + GFitsHDU* hdu = NULL; | ||
| 1650 | + | ||
| 1651 | + // Case A: Skymap is Healpix | ||
| 1652 | + if (m_proj->code() == "HPX") { | ||
| 1653 | + hdu = create_healpix_hdu(); | ||
| 1654 | + } | ||
| 1655 | + | ||
| 1656 | + // Case B: Skymap is not Healpix | ||
| 1657 | + else { | ||
| 1658 | + hdu = create_wcs_hdu(); | ||
| 1659 | + } | ||
| 1660 | + | ||
| 1661 | + // Append HDU to FITS file. | ||
| 1662 | + if (hdu != NULL) { | ||
| 1663 | + file.append(*hdu); | ||
| 1664 | + } | ||
| 1665 | + | ||
| 1666 | + // Delete HDU | ||
| 1667 | + if (hdu != NULL) delete hdu; | ||
| 1668 | + | ||
| 1669 | + } // endif: we had data to save | ||
| 1670 | + | ||
| 1671 | + // Return | ||
| 1672 | + return; | ||
| 1673 | +} | ||
| 1674 | + | ||
| 1675 | + | ||
| 1676 | +/***********************************************************************//** | ||
| 1677 | + * @brief Print sky map | ||
| 1678 | + * | ||
| 1679 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 1680 | + * @return String containing sky map information. | ||
| 1681 | + ***************************************************************************/ | ||
| 1682 | +std::string GSkymap::print(const GChatter& chatter) const | ||
| 1683 | +{ | ||
| 1684 | + // Initialise result string | ||
| 1685 | + std::string result; | ||
| 1686 | + | ||
| 1687 | + // Continue only if chatter is not silent | ||
| 1688 | + if (chatter != SILENT) { | ||
| 1689 | + | ||
| 1690 | + // Append header | ||
| 1691 | + result.append("=== GSkymap ==="); | ||
| 1692 | + | ||
| 1693 | + // Append information | ||
| 1694 | + result.append("\n"+gammalib::parformat("Number of pixels")); | ||
| 1695 | + result.append(gammalib::str(m_num_pixels)); | ||
| 1696 | + result.append("\n"+gammalib::parformat("Number of maps")); | ||
| 1697 | + result.append(gammalib::str(m_num_maps)); | ||
| 1698 | + if (m_proj != NULL && m_proj->size() == 2) { | ||
| 1699 | + result.append("\n"+gammalib::parformat("X axis dimension")); | ||
| 1700 | + result.append(gammalib::str(m_num_x)); | ||
| 1701 | + result.append("\n"+gammalib::parformat("Y axis dimension")); | ||
| 1702 | + result.append(gammalib::str(m_num_y)); | ||
| 1703 | + } | ||
| 1704 | + | ||
| 1705 | + // Append sky projection information | ||
| 1706 | + if (gammalib::reduce(chatter) > SILENT) { | ||
| 1707 | + if (m_proj != NULL) { | ||
| 1708 | + result.append("\n"+m_proj->print(gammalib::reduce(chatter))); | ||
| 1709 | + } | ||
| 1710 | + else { | ||
| 1711 | + result.append("\n"+gammalib::parformat("Sky projection")); | ||
| 1712 | + result.append("not defined"); | ||
| 1713 | + } | ||
| 1714 | + } | ||
| 1715 | + | ||
| 1716 | + } // endif: chatter was not silent | ||
| 1717 | + | ||
| 1718 | + // Return result | ||
| 1719 | + return result; | ||
| 1720 | +} | ||
| 1721 | + | ||
| 1722 | +/*========================================================================== | ||
| 1723 | + = = | ||
| 1724 | + = Private methods = | ||
| 1725 | + = = | ||
| 1726 | + ==========================================================================*/ | ||
| 1727 | + | ||
| 1728 | +/***********************************************************************//** | ||
| 1729 | + * @brief Initialise class members | ||
| 1730 | + ***************************************************************************/ | ||
| 1731 | +void GSkymap::init_members(void) | ||
| 1732 | +{ | ||
| 1733 | + // Initialise members | ||
| 1734 | + m_num_pixels = 0; | ||
| 1735 | + m_num_maps = 0; | ||
| 1736 | + m_num_x = 0; | ||
| 1737 | + m_num_y = 0; | ||
| 1738 | + m_proj = NULL; | ||
| 1739 | + m_pixels = NULL; | ||
| 1740 | + | ||
| 1741 | + // Initialise computation cache | ||
| 1742 | + m_hascache = false; | ||
| 1743 | + m_contained = false; | ||
| 1744 | + m_last_dir.clear(); | ||
| 1745 | + m_interpol.clear(); | ||
| 1746 | + | ||
| 1747 | + // Return | ||
| 1748 | + return; | ||
| 1749 | +} | ||
| 1750 | + | ||
| 1751 | + | ||
| 1752 | +/***********************************************************************//** | ||
| 1753 | + * @brief Allocate skymap pixels | ||
| 1754 | + ***************************************************************************/ | ||
| 1755 | +void GSkymap::alloc_pixels(void) | ||
| 1756 | +{ | ||
| 1757 | + // Compute data size | ||
| 1758 | + int size = m_num_pixels * m_num_maps; | ||
| 1759 | + | ||
| 1760 | + // Continue only if there are pixels | ||
| 1761 | + if (size > 0) { | ||
| 1762 | + | ||
| 1763 | + // Allocate pixels and initialize them to 0 | ||
| 1764 | + m_pixels = new double[size]; | ||
| 1765 | + for (int i = 0; i < size; ++i) { | ||
| 1766 | + m_pixels[i] = 0.0; | ||
| 1767 | + } | ||
| 1768 | + | ||
| 1769 | + } // endif: there were pixels | ||
| 1770 | + | ||
| 1771 | + // Return | ||
| 1772 | + return; | ||
| 1773 | +} | ||
| 1774 | + | ||
| 1775 | + | ||
| 1776 | +/***********************************************************************//** | ||
| 1777 | + * @brief Copy class members | ||
| 1778 | + * | ||
| 1779 | + * @param[in] map Sky map. | ||
| 1780 | + ***************************************************************************/ | ||
| 1781 | +void GSkymap::copy_members(const GSkymap& map) | ||
| 1782 | +{ | ||
| 1783 | + // Copy attributes | ||
| 1784 | + m_num_pixels = map.m_num_pixels; | ||
| 1785 | + m_num_maps = map.m_num_maps; | ||
| 1786 | + m_num_x = map.m_num_x; | ||
| 1787 | + m_num_y = map.m_num_y; | ||
| 1788 | + | ||
| 1789 | + // Copy computation cache | ||
| 1790 | + m_hascache = map.m_hascache; | ||
| 1791 | + m_contained = map.m_contained; | ||
| 1792 | + m_last_dir = map.m_last_dir; | ||
| 1793 | + m_interpol = map.m_interpol; | ||
| 1794 | + | ||
| 1795 | + // Clone sky projection if it is valid | ||
| 1796 | + if (map.m_proj != NULL) m_proj = map.m_proj->clone(); | ||
| 1797 | + | ||
| 1798 | + // Compute data size | ||
| 1799 | + int size = m_num_pixels * m_num_maps; | ||
| 1800 | + | ||
| 1801 | + // Copy pixels | ||
| 1802 | + if (size > 0 && map.m_pixels != NULL) { | ||
| 1803 | + alloc_pixels(); | ||
| 1804 | + for (int i = 0; i < size; ++i) { | ||
| 1805 | + m_pixels[i] = map.m_pixels[i]; | ||
| 1806 | + } | ||
| 1807 | + } | ||
| 1808 | + | ||
| 1809 | + // Return | ||
| 1810 | + return; | ||
| 1811 | +} | ||
| 1812 | + | ||
| 1813 | + | ||
| 1814 | +/***********************************************************************//** | ||
| 1815 | + * @brief Delete class members | ||
| 1816 | + ***************************************************************************/ | ||
| 1817 | +void GSkymap::free_members(void) | ||
| 1818 | +{ | ||
| 1819 | + // Free memory | ||
| 1820 | + if (m_proj != NULL) delete m_proj; | ||
| 1821 | + if (m_pixels != NULL) delete [] m_pixels; | ||
| 1822 | + | ||
| 1823 | + // Signal free pointers | ||
| 1824 | + m_proj = NULL; | ||
| 1825 | + m_pixels = NULL; | ||
| 1826 | + | ||
| 1827 | + // Reset number of pixels | ||
| 1828 | + m_num_pixels = 0; | ||
| 1829 | + m_num_maps = 0; | ||
| 1830 | + m_num_x = 0; | ||
| 1831 | + m_num_y = 0; | ||
| 1832 | + | ||
| 1833 | + // Return | ||
| 1834 | + return; | ||
| 1835 | +} | ||
| 1836 | + | ||
| 1837 | + | ||
| 1838 | +/***********************************************************************//** | ||
| 1839 | + * @brief Set World Coordinate System | ||
| 1840 | + * | ||
| 1841 | + * @param[in] wcs World Coordinate System code. | ||
| 1842 | + * @param[in] coords Coordinate system. | ||
| 1843 | + * @param[in] crval1 X value of reference pixel. | ||
| 1844 | + * @param[in] crval2 Y value of reference pixel. | ||
| 1845 | + * @param[in] crpix1 X index of reference pixel. | ||
| 1846 | + * @param[in] crpix2 Y index of reference pixel. | ||
| 1847 | + * @param[in] cdelt1 Increment in x direction at reference pixel (deg). | ||
| 1848 | + * @param[in] cdelt2 Increment in y direction at reference pixel (deg). | ||
| 1849 | + * @param[in] cd Astrometry parameters (2x2 matrix, deg/pixel). | ||
| 1850 | + * @param[in] pv2 Projection parameters (length WCS type dependent). | ||
| 1851 | + * | ||
| 1852 | + * @exception GException::wcs_invalid | ||
| 1853 | + * Invalid wcs parameter (World Coordinate System not known). | ||
| 1854 | + * | ||
| 1855 | + * This method sets the WCS projection pointer based on the WCS code and | ||
| 1856 | + * sky map parameters. It makes use of the GWcsRegistry class to allocate | ||
| 1857 | + * the correct derived class. Note that this method does not support the | ||
| 1858 | + * HPX projection. | ||
| 1859 | + * | ||
| 1860 | + * @todo Remove cd and pv2 parameters. | ||
| 1861 | + ***************************************************************************/ | ||
| 1862 | +void GSkymap::set_wcs(const std::string& wcs, const std::string& coords, | ||
| 1863 | + const double& crval1, const double& crval2, | ||
| 1864 | + const double& crpix1, const double& crpix2, | ||
| 1865 | + const double& cdelt1, const double& cdelt2, | ||
| 1866 | + const GMatrix& cd, const GVector& pv2) | ||
| 1867 | +{ | ||
| 1868 | + // Convert WCS to upper case | ||
| 1869 | + std::string uwcs = gammalib::toupper(wcs); | ||
| 1870 | + | ||
| 1871 | + // Check if HPX was requested (since this is not allowed) | ||
| 1872 | + if (uwcs == "HPX") { | ||
| 1873 | + throw GException::wcs_invalid(G_SET_WCS, uwcs, | ||
| 1874 | + "Method not valid for HPX projection."); | ||
| 1875 | + } | ||
| 1876 | + | ||
| 1877 | + // ... otherwise get projection from registry | ||
| 1878 | + else { | ||
| 1879 | + // Allocate WCS registry | ||
| 1880 | + GWcsRegistry registry; | ||
| 1881 | + | ||
| 1882 | + // Allocate projection from registry | ||
| 1883 | + GWcs* projection = registry.alloc(uwcs); | ||
| 1884 | + m_proj = projection; | ||
| 1885 | + | ||
| 1886 | + // Signal if projection type is not known | ||
| 1887 | + if (projection == NULL) { | ||
| 1888 | + std::string message = "Projection code not known. " | ||
| 1889 | + "Should be one of "+registry.list()+"."; | ||
| 1890 | + throw GException::wcs_invalid(G_SET_WCS, uwcs, message); | ||
| 1891 | + } | ||
| 1892 | + | ||
| 1893 | + // Setup WCS | ||
| 1894 | + projection->set(coords, crval1, crval2, crpix1, crpix2, | ||
| 1895 | + cdelt1, cdelt2); | ||
| 1896 | + | ||
| 1897 | + } // endelse: got projection from registry | ||
| 1898 | + | ||
| 1899 | + // Return | ||
| 1900 | + return; | ||
| 1901 | +} | ||
| 1902 | + | ||
| 1903 | + | ||
| 1904 | +/***********************************************************************//** | ||
| 1905 | + * @brief Read Healpix data from FITS table. | ||
| 1906 | + * | ||
| 1907 | + * @param[in] table FITS table. | ||
| 1908 | + * | ||
| 1909 | + * HEALPix data may be stored in various formats depending on the | ||
| 1910 | + * application that has writted the data. HEALPix IDL, for example, may | ||
| 1911 | + * store the data in vectors of length 1024 if the number of pixels is | ||
| 1912 | + * a multiple of 1024. On the other hand, vectors may also be used to store | ||
| 1913 | + * several HEALPix maps into a single column. Alternatively, multiple maps | ||
| 1914 | + * may be stored in multiple columns. | ||
| 1915 | + ***************************************************************************/ | ||
| 1916 | +void GSkymap::read_healpix(const GFitsTable& table) | ||
| 1917 | +{ | ||
| 1918 | + // Determine number of rows and columns in table | ||
| 1919 | + int nrows = table.nrows(); | ||
| 1920 | + int ncols = table.ncols(); | ||
| 1921 | + #if defined(G_READ_HEALPIX_DEBUG) | ||
| 1922 | + std::cout << "nrows=" << nrows << " ncols=" << ncols << std::endl; | ||
| 1923 | + #endif | ||
| 1924 | + | ||
| 1925 | + // Allocate Healpix projection | ||
| 1926 | + m_proj = new GHealpix; | ||
| 1927 | + | ||
| 1928 | + // Read WCS information from FITS header | ||
| 1929 | + m_proj->read(table); | ||
| 1930 | + | ||
| 1931 | + // Set number of pixels based on NSIDE parameter | ||
| 1932 | + m_num_pixels = static_cast<GHealpix*>(m_proj)->npix(); | ||
| 1933 | + #if defined(G_READ_HEALPIX_DEBUG) | ||
| 1934 | + std::cout << "m_num_pixels=" << m_num_pixels << std::endl; | ||
| 1935 | + #endif | ||
| 1936 | + | ||
| 1937 | + // Number of map pixels has to be a multiple of the number of | ||
| 1938 | + // rows in column | ||
| 1939 | + if (m_num_pixels % nrows != 0) { | ||
| 1940 | + throw GException::skymap_bad_size(G_READ_HEALPIX, nrows, | ||
| 1941 | + m_num_pixels); | ||
| 1942 | + } | ||
| 1943 | + | ||
| 1944 | + // Determine vector length for HEALPix data storage | ||
| 1945 | + int nentry = m_num_pixels / nrows; | ||
| 1946 | + #if defined(G_READ_HEALPIX_DEBUG) | ||
| 1947 | + std::cout << "nentry=" << nentry << std::endl; | ||
| 1948 | + #endif | ||
| 1949 | + | ||
| 1950 | + // Determine number of maps from the number of maps that fit into | ||
| 1951 | + // all columns. Only count columns that can fully hold the map. | ||
| 1952 | + m_num_maps = 0; | ||
| 1953 | + for (int icol = 0; icol < ncols; ++icol) { | ||
| 1954 | + const GFitsTableCol* col = table[icol]; | ||
| 1955 | + if (col->number() % nentry == 0) { | ||
| 1956 | + m_num_maps += col->number() / nentry; | ||
| 1957 | + } | ||
| 1958 | + } | ||
| 1959 | + #if defined(G_READ_HEALPIX_DEBUG) | ||
| 1960 | + std::cout << "m_num_maps=" << m_num_maps << std::endl; | ||
| 1961 | + #endif | ||
| 1962 | + | ||
| 1963 | + // Allocate pixels to hold the map | ||
| 1964 | + alloc_pixels(); | ||
| 1965 | + | ||
| 1966 | + // Initialise map counter | ||
| 1967 | + int imap = 0; | ||
| 1968 | + | ||
| 1969 | + // Loop over all columns | ||
| 1970 | + for (int icol = 0; icol < ncols; ++icol) { | ||
| 1971 | + | ||
| 1972 | + // Get next column | ||
| 1973 | + const GFitsTableCol* col = table[icol]; | ||
| 1974 | + | ||
| 1975 | + // Only consider columns that can fully hold maps | ||
| 1976 | + if (col->number() % nentry == 0) { | ||
| 1977 | + | ||
| 1978 | + // Determine number of maps in column | ||
| 1979 | + int num = col->number() / nentry; | ||
| 1980 | + | ||
| 1981 | + // Loop over all maps in column | ||
| 1982 | + int inx_start = 0; | ||
| 1983 | + int inx_end = nentry; | ||
| 1984 | + for (int i = 0; i < num; ++i) { | ||
| 1985 | + | ||
| 1986 | + // Load map | ||
| 1987 | + double *ptr = m_pixels + m_num_pixels*imap; | ||
| 1988 | + for (int row = 0; row < col->length(); ++row) { | ||
| 1989 | + for (int inx = inx_start; inx < inx_end; ++inx) { | ||
| 1990 | + *ptr++ = col->real(row,inx); | ||
| 1991 | + } | ||
| 1992 | + } | ||
| 1993 | + #if defined(G_READ_HEALPIX_DEBUG) | ||
| 1994 | + std::cout << "Load map=" << imap << " index=" | ||
| 1995 | + << inx_start << "-" << inx_end << std::endl; | ||
| 1996 | + #endif | ||
| 1997 | + | ||
| 1998 | + // Increment index range | ||
| 1999 | + inx_start = inx_end; | ||
| 2000 | + inx_end += nentry; | ||
| 2001 | + | ||
| 2002 | + // Increment map counter | ||
| 2003 | + imap++; | ||
| 2004 | + | ||
| 2005 | + // Break if we have loaded all maps | ||
| 2006 | + if (imap >= m_num_maps) { | ||
| 2007 | + break; | ||
| 2008 | + } | ||
| 2009 | + | ||
| 2010 | + } // endfor: looped over all maps in column | ||
| 2011 | + } // endif: column could fully hold maps | ||
| 2012 | + | ||
| 2013 | + // Break if we have loaded all maps | ||
| 2014 | + if (imap >= m_num_maps) { | ||
| 2015 | + break; | ||
| 2016 | + } | ||
| 2017 | + | ||
| 2018 | + } // endfor: looped over all columns | ||
| 2019 | + | ||
| 2020 | + // Return | ||
| 2021 | + return; | ||
| 2022 | +} | ||
| 2023 | + | ||
| 2024 | + | ||
| 2025 | +/***********************************************************************//** | ||
| 2026 | + * @brief Read WCS image from FITS HDU | ||
| 2027 | + * | ||
| 2028 | + * @param[in] image FITS image. | ||
| 2029 | + * | ||
| 2030 | + * @exception GException::skymap_bad_image_dim | ||
| 2031 | + * WCS image has invalid dimension (naxis=2 or 3). | ||
| 2032 | + ***************************************************************************/ | ||
| 2033 | +void GSkymap::read_wcs(const GFitsImage& image) | ||
| 2034 | +{ | ||
| 2035 | + // Allocate WCS | ||
| 2036 | + alloc_wcs(image); | ||
| 2037 | + | ||
| 2038 | + // Read projection information from FITS header | ||
| 2039 | + m_proj->read(image); | ||
| 2040 | + | ||
| 2041 | + // Extract map dimension and number of maps from image | ||
| 2042 | + if (image.naxis() == 2) { | ||
| 2043 | + m_num_x = image.naxes(0); | ||
| 2044 | + m_num_y = image.naxes(1); | ||
| 2045 | + m_num_maps = 1; | ||
| 2046 | + } | ||
| 2047 | + else if (image.naxis() >= 3) { | ||
| 2048 | + m_num_x = image.naxes(0); | ||
| 2049 | + m_num_y = image.naxes(1); | ||
| 2050 | + m_num_maps = image.naxes(2); | ||
| 2051 | + } | ||
| 2052 | + else { | ||
| 2053 | + throw GException::skymap_bad_image_dim(G_READ_WCS, image.naxis()); | ||
| 2054 | + } | ||
| 2055 | + #if defined(G_READ_WCS_DEBUG) | ||
| 2056 | + std::cout << "m_num_x=" << m_num_x << std::endl; | ||
| 2057 | + std::cout << "m_num_y=" << m_num_y << std::endl; | ||
| 2058 | + std::cout << "m_num_maps=" << m_num_maps << std::endl; | ||
| 2059 | + #endif | ||
| 2060 | + | ||
| 2061 | + // Compute number of pixels | ||
| 2062 | + m_num_pixels = m_num_x * m_num_y; | ||
| 2063 | + #if defined(G_READ_WCS_DEBUG) | ||
| 2064 | + std::cout << "m_num_pixels=" << m_num_pixels << std::endl; | ||
| 2065 | + #endif | ||
| 2066 | + | ||
| 2067 | + // Allocate pixels to hold the map | ||
| 2068 | + alloc_pixels(); | ||
| 2069 | + | ||
| 2070 | + // Read image | ||
| 2071 | + if (image.naxis() == 2) { | ||
| 2072 | + double* ptr = m_pixels; | ||
| 2073 | + for (int iy = 0; iy < m_num_y; ++iy) { | ||
| 2074 | + for (int ix = 0; ix < m_num_x; ++ix) { | ||
| 2075 | + *ptr++ = image.pixel(ix,iy); | ||
| 2076 | + } | ||
| 2077 | + } | ||
| 2078 | + } | ||
| 2079 | + else { | ||
| 2080 | + double* ptr = m_pixels; | ||
| 2081 | + for (int imap = 0; imap < m_num_maps; ++imap) { | ||
| 2082 | + for (int iy = 0; iy < m_num_y; ++iy) { | ||
| 2083 | + for (int ix = 0; ix < m_num_x; ++ix) { | ||
| 2084 | + *ptr++ = image.pixel(ix,iy,imap); | ||
| 2085 | + } | ||
| 2086 | + } | ||
| 2087 | + } | ||
| 2088 | + } | ||
| 2089 | + | ||
| 2090 | + // Return | ||
| 2091 | + return; | ||
| 2092 | +} | ||
| 2093 | + | ||
| 2094 | + | ||
| 2095 | +/***********************************************************************//** | ||
| 2096 | + * @brief Allocate WCS class | ||
| 2097 | + * | ||
| 2098 | + * @param[in] image FITS image. | ||
| 2099 | + * | ||
| 2100 | + * @exception GException::fits_key_not_found | ||
| 2101 | + * Unable to find required FITS header keyword. | ||
| 2102 | + * @exception GException::skymap_bad_ctype | ||
| 2103 | + * CTYPE1 and CTYPE2 keywords are incompatible. | ||
| 2104 | + * @exception GException::wcs_invalid | ||
| 2105 | + * WCS projection of FITS file not supported by GammaLib. | ||
| 2106 | + ***************************************************************************/ | ||
| 2107 | +void GSkymap::alloc_wcs(const GFitsImage& image) | ||
| 2108 | +{ | ||
| 2109 | + // Get standard keywords | ||
| 2110 | + std::string ctype1 = image.string("CTYPE1"); | ||
| 2111 | + std::string ctype2 = image.string("CTYPE2"); | ||
| 2112 | + | ||
| 2113 | + // Extract projection type | ||
| 2114 | + std::string xproj = ctype1.substr(5,3); | ||
| 2115 | + std::string yproj = ctype2.substr(5,3); | ||
| 2116 | + | ||
| 2117 | + // Check that projection type is identical on both axes | ||
| 2118 | + if (xproj != yproj) { | ||
| 2119 | + throw GException::skymap_bad_ctype(G_ALLOC_WCS, | ||
| 2120 | + ctype1, ctype2); | ||
| 2121 | + } | ||
| 2122 | + | ||
| 2123 | + // Allocate WCS registry | ||
| 2124 | + GWcsRegistry registry; | ||
| 2125 | + | ||
| 2126 | + // Allocate projection from registry | ||
| 2127 | + m_proj = registry.alloc(xproj); | ||
| 2128 | + | ||
| 2129 | + // Signal if projection type is not known | ||
| 2130 | + if (m_proj == NULL) { | ||
| 2131 | + std::string message = "Projection code not known. " | ||
| 2132 | + "Should be one of "+registry.list()+"."; | ||
| 2133 | + throw GException::wcs_invalid(G_ALLOC_WCS, xproj, message); | ||
| 2134 | + } | ||
| 2135 | + | ||
| 2136 | + // Return | ||
| 2137 | + return; | ||
| 2138 | +} | ||
| 2139 | + | ||
| 2140 | + | ||
| 2141 | +/***********************************************************************//** | ||
| 2142 | + * @brief Create FITS HDU containing Healpix data | ||
| 2143 | + * | ||
| 2144 | + * This method allocates a binary table HDU that contains the Healpix data. | ||
| 2145 | + * Deallocation of the table has to be done by the client. | ||
| 2146 | + ***************************************************************************/ | ||
| 2147 | +GFitsBinTable* GSkymap::create_healpix_hdu(void) const | ||
| 2148 | +{ | ||
| 2149 | + // Initialise result to NULL pointer | ||
| 2150 | + GFitsBinTable* hdu = NULL; | ||
| 2151 | + | ||
| 2152 | + // Compute size of Healpix data | ||
| 2153 | + int size = m_num_pixels * m_num_maps; | ||
| 2154 | + | ||
| 2155 | + // Continue only if we have pixels | ||
| 2156 | + if (size > 0) { | ||
| 2157 | + | ||
| 2158 | + // Set number of rows and columns | ||
| 2159 | + int rows = m_num_pixels; | ||
| 2160 | + int number = m_num_maps; | ||
| 2161 | + | ||
| 2162 | + // Create column to hold Healpix data | ||
| 2163 | + GFitsTableDoubleCol column = GFitsTableDoubleCol("DATA", rows, number); | ||
| 2164 | + | ||
| 2165 | + // Fill data into column | ||
| 2166 | + double* ptr = m_pixels; | ||
| 2167 | + for (int inx = 0; inx < number; ++inx) { | ||
| 2168 | + for (int row = 0; row < rows; ++row) { | ||
| 2169 | + column(row,inx) = *ptr++; | ||
| 2170 | + } | ||
| 2171 | + } | ||
| 2172 | + | ||
| 2173 | + // Create HDU that contains Healpix map in a binary table | ||
| 2174 | + hdu = new GFitsBinTable(rows); | ||
| 2175 | + hdu->append(column); | ||
| 2176 | + | ||
| 2177 | + } // endif: there were pixels | ||
| 2178 | + | ||
| 2179 | + // ... otherwise create an empty header | ||
| 2180 | + else { | ||
| 2181 | + hdu = new GFitsBinTable; | ||
| 2182 | + } | ||
| 2183 | + | ||
| 2184 | + // Set extension name | ||
| 2185 | + hdu->extname("HEALPIX"); | ||
| 2186 | + | ||
| 2187 | + // If we have WCS information then write into FITS header | ||
| 2188 | + if (m_proj != NULL) m_proj->write(*hdu); | ||
| 2189 | + | ||
| 2190 | + // Set additional keywords | ||
| 2191 | + hdu->card("NBRBINS", m_num_maps, "Number of HEALPix maps"); | ||
| 2192 | + | ||
| 2193 | + // Return HDU | ||
| 2194 | + return hdu; | ||
| 2195 | +} | ||
| 2196 | + | ||
| 2197 | + | ||
| 2198 | +/***********************************************************************//** | ||
| 2199 | + * @brief Create FITS HDU containing WCS image | ||
| 2200 | + * | ||
| 2201 | + * This method allocates an image HDU that contains the WCS image data. | ||
| 2202 | + * Deallocation of the image has to be done by the client. | ||
| 2203 | + * | ||
| 2204 | + * @todo Set additional keywords. | ||
| 2205 | + ***************************************************************************/ | ||
| 2206 | +GFitsImageDouble* GSkymap::create_wcs_hdu(void) const | ||
| 2207 | +{ | ||
| 2208 | + // Initialise result to NULL pointer | ||
| 2209 | + GFitsImageDouble* hdu = NULL; | ||
| 2210 | + | ||
| 2211 | + // Compute size of Healpix data | ||
| 2212 | + int size = m_num_pixels * m_num_maps; | ||
| 2213 | + | ||
| 2214 | + // Continue only if we have pixels | ||
| 2215 | + if (size > 0) { | ||
| 2216 | + | ||
| 2217 | + // Set axis parameters for image construction | ||
| 2218 | + int naxis = (m_num_maps == 1) ? 2 : 3; | ||
| 2219 | + int naxes[] = {m_num_x, m_num_y, m_num_maps}; | ||
| 2220 | + | ||
| 2221 | + // Allocate image | ||
| 2222 | + hdu = new GFitsImageDouble(naxis, naxes); | ||
| 2223 | + | ||
| 2224 | + // Store data in image | ||
| 2225 | + if (naxis == 2) { | ||
| 2226 | + double* ptr = m_pixels; | ||
| 2227 | + for (int iy = 0; iy < m_num_y; ++iy) { | ||
| 2228 | + for (int ix = 0; ix < m_num_x; ++ix) { | ||
| 2229 | + (*hdu)(ix,iy) = *ptr++; | ||
| 2230 | + } | ||
| 2231 | + } | ||
| 2232 | + } | ||
| 2233 | + else { | ||
| 2234 | + double* ptr = m_pixels; | ||
| 2235 | + for (int imap = 0; imap < m_num_maps; ++imap) { | ||
| 2236 | + for (int iy = 0; iy < m_num_y; ++iy) { | ||
| 2237 | + for (int ix = 0; ix < m_num_x; ++ix) { | ||
| 2238 | + (*hdu)(ix,iy,imap) = *ptr++; | ||
| 2239 | + } | ||
| 2240 | + } | ||
| 2241 | + } | ||
| 2242 | + } | ||
| 2243 | + | ||
| 2244 | + } // endif: there were pixels | ||
| 2245 | + | ||
| 2246 | + // ... otherwise create an empty header | ||
| 2247 | + else { | ||
| 2248 | + hdu = new GFitsImageDouble; | ||
| 2249 | + } | ||
| 2250 | + | ||
| 2251 | + // Set extension name | ||
| 2252 | + hdu->extname("IMAGE"); | ||
| 2253 | + | ||
| 2254 | + // If we have sky projection information then write into FITS header | ||
| 2255 | + if (m_proj != NULL) m_proj->write(*hdu); | ||
| 2256 | + | ||
| 2257 | + // Set additional keywords | ||
| 2258 | + //TODO | ||
| 2259 | + | ||
| 2260 | + // Return HDU | ||
| 2261 | + return hdu; | ||
| 2262 | +} | ||
| 2263 | + | ||
| 2264 | +/***********************************************************************//** | ||
| 2265 | + * @brief publishes the skymap in a VO Hub | ||
| 2266 | + * | ||
| 2267 | + * @param[in] | ||
| 2268 | + * | ||
| 2269 | + * @exception GException:: | ||
| 2270 | + * | ||
| 2271 | + ***************************************************************************/ | ||
| 2272 | +void GSkymap::publish(void) | ||
| 2273 | +{ | ||
| 2274 | + make_votable(); | ||
| 2275 | + // Return | ||
| 2276 | + return; | ||
| 2277 | +} | ||
| 2278 | + | ||
| 2279 | +/***********************************************************************//** | ||
| 2280 | + * @brief makes GVOTable object and fills ot with current skymap(s) | ||
| 2281 | + * | ||
| 2282 | + * @param[in] | ||
| 2283 | + * | ||
| 2284 | + * @exception GException:: | ||
| 2285 | + * | ||
| 2286 | + ***************************************************************************/ | ||
| 2287 | +void GSkymap::make_votable(void) | ||
| 2288 | +{ | ||
| 2289 | + GVOTable* m_skytable; | ||
| 2290 | + m_skytable->create_votable(); | ||
| 2291 | + //For each pixel set the value of the pixel inside the data part | ||
| 2292 | + m_skytable->fill_content("Test value"); | ||
| 2293 | + // Return | ||
| 2294 | + return; | ||
| 2295 | +} | ||
| 2296 | +/*========================================================================== | ||
| 2297 | + = = | ||
| 2298 | + = Friends = | ||
| 2299 | + = = | ||
| 2300 | + ==========================================================================*/ | ||
| 2301 | + | ||
| 2302 | +/***********************************************************************//** | ||
| 2303 | + * @brief Computes square root of skymap elements | ||
| 2304 | + * | ||
| 2305 | + * @param[in] map Skymap. | ||
| 2306 | + * @return Skymap containing the square root of every element. | ||
| 2307 | + ***************************************************************************/ | ||
| 2308 | +GSkymap sqrt(const GSkymap& map) | ||
| 2309 | +{ | ||
| 2310 | + // Initialise result vector | ||
| 2311 | + GSkymap result(map); | ||
| 2312 | + | ||
| 2313 | + // Loop over all maps | ||
| 2314 | + for (int i = 0; i < map.nmaps(); ++i) { | ||
| 2315 | + | ||
| 2316 | + // Loop over all bins | ||
| 2317 | + for (int j = 0; j < map.npix(); ++j) { | ||
| 2318 | + | ||
| 2319 | + // Get the content from the bin | ||
| 2320 | + double content = map(j,i); | ||
| 2321 | + | ||
| 2322 | + // Check if content is not negative | ||
| 2323 | + if (content < 0.0) { | ||
| 2324 | + std::string msg = "Negative value envountered." | ||
| 2325 | + " Cannot take the sqrt from a negative value"; | ||
| 2326 | + throw GException::invalid_value(G_OP_UNARY_DIV, msg); | ||
| 2327 | + } | ||
| 2328 | + | ||
| 2329 | + // Set content of the result map | ||
| 2330 | + result(j,i) = std::sqrt(content); | ||
| 2331 | + | ||
| 2332 | + } // endfor: Loop over all bins | ||
| 2333 | + | ||
| 2334 | + } // endfor: Loop over all maps | ||
| 2335 | + | ||
| 2336 | + // Return vector | ||
| 2337 | + return result; | ||
| 2338 | +} |
src/vo/GVOApp.cpp~
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOApp.hpp - VO SAMP Hub class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2014 by Thierry Louge * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOApp.cpp | ||
| 23 | + * @brief VO Application connected to SAMP HUB class implementation | ||
| 24 | + * @author Thierry Louge | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#include <errno.h> | ||
| 31 | +#endif | ||
| 32 | +#include <cstdlib> // std::getenv() function | ||
| 33 | +#include <cstdio> // std::fopen(), etc. functions | ||
| 34 | +#include <cstring> // std::memset() function | ||
| 35 | +#include <unistd.h> // close() function | ||
| 36 | +#include "GVOApp.hpp" | ||
| 37 | +#include "GException.hpp" | ||
| 38 | +#include "GTools.hpp" | ||
| 39 | + | ||
| 40 | +/* __ Method name definitions ____________________________________________ */ | ||
| 41 | + | ||
| 42 | +/* __ Macros _____________________________________________________________ */ | ||
| 43 | + | ||
| 44 | +/* __ Coding definitions _________________________________________________ */ | ||
| 45 | + | ||
| 46 | +/* __ Debug definitions __________________________________________________ */ | ||
| 47 | + | ||
| 48 | + | ||
| 49 | +/*========================================================================== | ||
| 50 | + = = | ||
| 51 | + = Constructors/destructors = | ||
| 52 | + = = | ||
| 53 | + ==========================================================================*/ | ||
| 54 | + | ||
| 55 | +/***********************************************************************//** | ||
| 56 | + * @brief Void constructor | ||
| 57 | + ***************************************************************************/ | ||
| 58 | +GVOApp::GVOApp(void) | ||
| 59 | +{ | ||
| 60 | + // Initialise members | ||
| 61 | + init_members(); | ||
| 62 | + | ||
| 63 | + // Return | ||
| 64 | + return; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | + | ||
| 68 | +/***********************************************************************//** | ||
| 69 | + * @brief Copy constructor | ||
| 70 | + * | ||
| 71 | + * @param[in] hub VO Hub. | ||
| 72 | + ***************************************************************************/ | ||
| 73 | +GVOApp::GVOApp(const GVOApp& hub) | ||
| 74 | +{ | ||
| 75 | + // Initialise members | ||
| 76 | + init_members(); | ||
| 77 | + | ||
| 78 | + // Copy members | ||
| 79 | + copy_members(hub); | ||
| 80 | + | ||
| 81 | + // Return | ||
| 82 | + return; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | + | ||
| 86 | +/***********************************************************************//** | ||
| 87 | + * @brief Destructor | ||
| 88 | + ***************************************************************************/ | ||
| 89 | +GVOApp::~GVOApp(void) | ||
| 90 | +{ | ||
| 91 | + | ||
| 92 | + // Return | ||
| 93 | + return; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | + | ||
| 97 | +/*========================================================================== | ||
| 98 | + = = | ||
| 99 | + = Operators = | ||
| 100 | + = = | ||
| 101 | + ==========================================================================*/ | ||
| 102 | + | ||
| 103 | +/***********************************************************************//** | ||
| 104 | + * @brief Assignment operator | ||
| 105 | + * | ||
| 106 | + * @param[in] hub VO hub. | ||
| 107 | + * @return VO hub. | ||
| 108 | + ***************************************************************************/ | ||
| 109 | +GVOApp& GVOApp::operator=(const GVOApp& hub) | ||
| 110 | +{ | ||
| 111 | + // Execute only if object is not identical | ||
| 112 | + if (this != &hub) { | ||
| 113 | + | ||
| 114 | + // Free members | ||
| 115 | + free_members(); | ||
| 116 | + | ||
| 117 | + // Initialise members | ||
| 118 | + init_members(); | ||
| 119 | + | ||
| 120 | + // Copy members | ||
| 121 | + copy_members(hub); | ||
| 122 | + | ||
| 123 | + } // endif: object was not identical | ||
| 124 | + | ||
| 125 | + // Return | ||
| 126 | + return *this; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | + | ||
| 130 | +/*========================================================================== | ||
| 131 | + = = | ||
| 132 | + = Public methods = | ||
| 133 | + = = | ||
| 134 | + ==========================================================================*/ | ||
| 135 | + | ||
| 136 | +/***********************************************************************//** | ||
| 137 | + * @brief Clear object. | ||
| 138 | + * | ||
| 139 | + * Reset object to a clean initial state. | ||
| 140 | + ***************************************************************************/ | ||
| 141 | +void GVOApp::clear(void) | ||
| 142 | +{ | ||
| 143 | + // Free memory and initialise members | ||
| 144 | + free_members(); | ||
| 145 | + init_members(); | ||
| 146 | + | ||
| 147 | + // Return | ||
| 148 | + return; | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | + | ||
| 152 | +/***********************************************************************//** | ||
| 153 | + * @brief Clone object | ||
| 154 | + ***************************************************************************/ | ||
| 155 | +GVOApp* GVOApp::clone(void) const | ||
| 156 | +{ | ||
| 157 | + // Clone client | ||
| 158 | + return new GVOApp(*this); | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | + | ||
| 162 | +/***********************************************************************//** | ||
| 163 | + * @brief TBD | ||
| 164 | + * | ||
| 165 | + ***************************************************************************/ | ||
| 166 | +void GVOApp::start(void) | ||
| 167 | +{ | ||
| 168 | + // Does nothing | ||
| 169 | + | ||
| 170 | + // Return | ||
| 171 | + return; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | + | ||
| 175 | +/***********************************************************************//** | ||
| 176 | + * @brief Print VO hub information | ||
| 177 | + * | ||
| 178 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 179 | + * @return String containing VO hub information | ||
| 180 | + ***************************************************************************/ | ||
| 181 | +std::string GVOApp::print(const GChatter& chatter) const | ||
| 182 | +{ | ||
| 183 | + // Initialise result string | ||
| 184 | + std::string result; | ||
| 185 | + std::list<std::string> temp; | ||
| 186 | + temp = registered_calls; | ||
| 187 | + | ||
| 188 | + // Continue only if chatter is not silent | ||
| 189 | + if (chatter != SILENT) { | ||
| 190 | + | ||
| 191 | + // Append header | ||
| 192 | + result.append("=== GVOApp ==="); | ||
| 193 | + result.append(m_id); | ||
| 194 | + result.append("%d",temp.size()); | ||
| 195 | + for (std::list<std::string>::iterator i = temp.begin(); i != temp.end(); ++i) { | ||
| 196 | + result.append("Method:\n"); | ||
| 197 | + result.append(*i); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + | ||
| 201 | + | ||
| 202 | + } // endif: chatter was not silent | ||
| 203 | + | ||
| 204 | + // Return result | ||
| 205 | + return result; | ||
| 206 | +} | ||
| 207 | + | ||
| 208 | + | ||
| 209 | +/*========================================================================== | ||
| 210 | + = = | ||
| 211 | + = Private methods = | ||
| 212 | + = = | ||
| 213 | + ==========================================================================*/ | ||
| 214 | + | ||
| 215 | +/***********************************************************************//** | ||
| 216 | + * @brief Initialise class members | ||
| 217 | + ***************************************************************************/ | ||
| 218 | +void GVOApp::init_members(void) | ||
| 219 | +{ | ||
| 220 | + // Initialise members | ||
| 221 | + std::list<std::string> registeredMethods; | ||
| 222 | + // Return | ||
| 223 | + return; | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | + | ||
| 227 | +/***********************************************************************//** | ||
| 228 | + * @brief Copy class members | ||
| 229 | + * | ||
| 230 | + * @param[in] app registered in Hub. | ||
| 231 | + ***************************************************************************/ | ||
| 232 | +void GVOApp::copy_members(const GVOApp& app) | ||
| 233 | +{ | ||
| 234 | + // Copy members | ||
| 235 | + | ||
| 236 | + | ||
| 237 | + // Return | ||
| 238 | + return; | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | + | ||
| 242 | +/***********************************************************************//** | ||
| 243 | + * @brief Delete class members | ||
| 244 | + ***************************************************************************/ | ||
| 245 | +void GVOApp::free_members(void) | ||
| 246 | +{ | ||
| 247 | + // Return | ||
| 248 | + return; | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +/***********************************************************************//** | ||
| 252 | + * @brief Creates nex application container | ||
| 253 | + ***************************************************************************/ | ||
| 254 | +void GVOApp::start_app(void) | ||
| 255 | +{ | ||
| 256 | + // Creates Hub | ||
| 257 | + printf("Creating new application Container\n"); | ||
| 258 | + | ||
| 259 | + // Return | ||
| 260 | + return; | ||
| 261 | +} |
src/vo/GVOClient.cpp~
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOClient.hpp - VO client class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2013 by Juergen Knoedlseder * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOClient.cpp | ||
| 23 | + * @brief VO client class implementation | ||
| 24 | + * @author Juergen Knoedlseder | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#endif | ||
| 31 | +#include <cstdlib> // std::getenv() function | ||
| 32 | +#include <cstdio> // std::fopen(), etc. functions | ||
| 33 | +#include <cstring> // std::memset() function | ||
| 34 | +#include <unistd.h> // close() function | ||
| 35 | +#include <netdb.h> // getaddrinfo() function | ||
| 36 | +#include <sys/socket.h> // socket(), connect() functions | ||
| 37 | +#include "GVOClient.hpp" | ||
| 38 | +#include "GException.hpp" | ||
| 39 | +#include "GTools.hpp" | ||
| 40 | + | ||
| 41 | +/* __ Method name definitions ____________________________________________ */ | ||
| 42 | + | ||
| 43 | +/* __ Macros _____________________________________________________________ */ | ||
| 44 | + | ||
| 45 | +/* __ Coding definitions _________________________________________________ */ | ||
| 46 | + | ||
| 47 | +/* __ Debug definitions __________________________________________________ */ | ||
| 48 | + | ||
| 49 | + | ||
| 50 | +/*========================================================================== | ||
| 51 | + = = | ||
| 52 | + = Constructors/destructors = | ||
| 53 | + = = | ||
| 54 | + ==========================================================================*/ | ||
| 55 | + | ||
| 56 | +/***********************************************************************//** | ||
| 57 | + * @brief Void constructor | ||
| 58 | + ***************************************************************************/ | ||
| 59 | +GVOClient::GVOClient(void) | ||
| 60 | +{ | ||
| 61 | + // Initialise members | ||
| 62 | + init_members(); | ||
| 63 | + | ||
| 64 | + // Find Hub | ||
| 65 | + find_hub(); | ||
| 66 | + | ||
| 67 | + // Return | ||
| 68 | + return; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | + | ||
| 72 | +/***********************************************************************//** | ||
| 73 | + * @brief Copy constructor | ||
| 74 | + * | ||
| 75 | + * @param[in] client VO client. | ||
| 76 | + ***************************************************************************/ | ||
| 77 | +GVOClient::GVOClient(const GVOClient& client) | ||
| 78 | +{ | ||
| 79 | + // Initialise members | ||
| 80 | + init_members(); | ||
| 81 | + | ||
| 82 | + // Copy members | ||
| 83 | + copy_members(client); | ||
| 84 | + | ||
| 85 | + // Return | ||
| 86 | + return; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | + | ||
| 90 | +/***********************************************************************//** | ||
| 91 | + * @brief Destructor | ||
| 92 | + ***************************************************************************/ | ||
| 93 | +GVOClient::~GVOClient(void) | ||
| 94 | +{ | ||
| 95 | + // Free members | ||
| 96 | + free_members(); | ||
| 97 | + | ||
| 98 | + // Return | ||
| 99 | + return; | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | + | ||
| 103 | +/*========================================================================== | ||
| 104 | + = = | ||
| 105 | + = Operators = | ||
| 106 | + = = | ||
| 107 | + ==========================================================================*/ | ||
| 108 | + | ||
| 109 | +/***********************************************************************//** | ||
| 110 | + * @brief Assignment operator | ||
| 111 | + * | ||
| 112 | + * @param[in] client VO client. | ||
| 113 | + * @return VO client. | ||
| 114 | + ***************************************************************************/ | ||
| 115 | +GVOClient& GVOClient::operator= (const GVOClient& client) | ||
| 116 | +{ | ||
| 117 | + // Execute only if object is not identical | ||
| 118 | + if (this != &client) { | ||
| 119 | + | ||
| 120 | + // Free members | ||
| 121 | + free_members(); | ||
| 122 | + | ||
| 123 | + // Initialise members | ||
| 124 | + init_members(); | ||
| 125 | + | ||
| 126 | + // Copy members | ||
| 127 | + copy_members(client); | ||
| 128 | + | ||
| 129 | + } // endif: object was not identical | ||
| 130 | + | ||
| 131 | + // Return | ||
| 132 | + return *this; | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | + | ||
| 136 | +/*========================================================================== | ||
| 137 | + = = | ||
| 138 | + = Public methods = | ||
| 139 | + = = | ||
| 140 | + ==========================================================================*/ | ||
| 141 | + | ||
| 142 | +/***********************************************************************//** | ||
| 143 | + * @brief Clear object. | ||
| 144 | + * | ||
| 145 | + * Reset object to a clean initial state. | ||
| 146 | + ***************************************************************************/ | ||
| 147 | +void GVOClient::clear(void) | ||
| 148 | +{ | ||
| 149 | + // Free memory and initialise members | ||
| 150 | + free_members(); | ||
| 151 | + init_members(); | ||
| 152 | + | ||
| 153 | + // Return | ||
| 154 | + return; | ||
| 155 | +} | ||
| 156 | + | ||
| 157 | + | ||
| 158 | +/***********************************************************************//** | ||
| 159 | + * @brief Clone object | ||
| 160 | + ***************************************************************************/ | ||
| 161 | +GVOClient* GVOClient::clone(void) const | ||
| 162 | +{ | ||
| 163 | + // Clone client | ||
| 164 | + return new GVOClient(*this); | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | + | ||
| 168 | +/***********************************************************************//** | ||
| 169 | + * @brief Register client to SAMP Hub | ||
| 170 | + * | ||
| 171 | + * Connects the VO client to the Hub. A socket to the Hub is opened and the | ||
| 172 | + * client is registered at the Hub. Metadata are sent. | ||
| 173 | + ***************************************************************************/ | ||
| 174 | +void GVOClient::connect(void) | ||
| 175 | +{ | ||
| 176 | + // Register to Hub | ||
| 177 | + printf("Sending registration to hub\n"); | ||
| 178 | + fflush(stdout); | ||
| 179 | + register_to_hub(); | ||
| 180 | + printf("Registration to hub sent\n"); | ||
| 181 | + fflush(stdout); | ||
| 182 | + // Send meta data | ||
| 183 | + send_metadata(); | ||
| 184 | + printf("Metadata sent\n"); | ||
| 185 | + fflush(stdout); | ||
| 186 | + // Return | ||
| 187 | + return; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | + | ||
| 191 | +/***********************************************************************//** | ||
| 192 | + * @brief Unregister client from SAMP Hub | ||
| 193 | + * | ||
| 194 | + * Disconnects the VO client from the Hub. The client is unregistered and the | ||
| 195 | + * socket to the Hub is closed. | ||
| 196 | + ***************************************************************************/ | ||
| 197 | +void GVOClient::disconnect(void) | ||
| 198 | +{ | ||
| 199 | + // Unregister from Hub | ||
| 200 | + unregister_from_hub(); | ||
| 201 | + | ||
| 202 | + // Close socket | ||
| 203 | + if (m_socket != -1) { | ||
| 204 | + close(m_socket); | ||
| 205 | + m_socket = -1; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + // Return | ||
| 209 | + return; | ||
| 210 | +} | ||
| 211 | + | ||
| 212 | + | ||
| 213 | +/***********************************************************************//** | ||
| 214 | + * @brief Signals if client has Hub information | ||
| 215 | + * | ||
| 216 | + * @return True if client has Hub information, false otherwise. | ||
| 217 | + * | ||
| 218 | + * Checks if all mandatory Hub tokens are non-empty. | ||
| 219 | + ***************************************************************************/ | ||
| 220 | +bool GVOClient::has_hub(void) const | ||
| 221 | +{ | ||
| 222 | + // Return Hub information status | ||
| 223 | + return (!m_secret.empty() && !m_hub_url.empty() && !m_version.empty()); | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | + | ||
| 227 | +/***********************************************************************//** | ||
| 228 | + * @brief Signals if client is connected to Hub | ||
| 229 | + * | ||
| 230 | + * @return True if client is connected to Hub, false otherwise. | ||
| 231 | + * | ||
| 232 | + * Checks if a client is connected to Hub. | ||
| 233 | + ***************************************************************************/ | ||
| 234 | +bool GVOClient::is_connected(void) const | ||
| 235 | +{ | ||
| 236 | + // Return | ||
| 237 | + return false; | ||
| 238 | +} | ||
| 239 | + | ||
| 240 | + | ||
| 241 | +/***********************************************************************//** | ||
| 242 | + * @brief Returns Hub response a XML object | ||
| 243 | + * | ||
| 244 | + * @return Hub response. | ||
| 245 | + ***************************************************************************/ | ||
| 246 | +GXml GVOClient::response(void) const | ||
| 247 | +{ | ||
| 248 | + // Declare empty XML document | ||
| 249 | + GXml xml; | ||
| 250 | + | ||
| 251 | + // Continue only if connection has been established | ||
| 252 | + if (m_socket != -1) { | ||
| 253 | + printf("Socket identified, receive string\n"); | ||
| 254 | + fflush(stdout); | ||
| 255 | + // Receive a string | ||
| 256 | + std::string response = receive_string(); | ||
| 257 | + | ||
| 258 | + // Find start of XML text | ||
| 259 | + size_t start = response.find("<?xml"); | ||
| 260 | + | ||
| 261 | + // If found then convert text into XML document | ||
| 262 | + if (start != std::string::npos) { | ||
| 263 | + xml = GXml(response.substr(start, std::string::npos)); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + } // endif: connection has been established | ||
| 267 | + | ||
| 268 | + // Return XML document | ||
| 269 | + printf("End of response function\n"); | ||
| 270 | + fflush(stdout); | ||
| 271 | + return xml; | ||
| 272 | +} | ||
| 273 | + | ||
| 274 | + | ||
| 275 | +/***********************************************************************//** | ||
| 276 | + * @brief Print VO client information | ||
| 277 | + * | ||
| 278 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 279 | + * @return String containing VO client information | ||
| 280 | + ***************************************************************************/ | ||
| 281 | +std::string GVOClient::print(const GChatter& chatter) const | ||
| 282 | +{ | ||
| 283 | + // Initialise result string | ||
| 284 | + std::string result; | ||
| 285 | + | ||
| 286 | + // Continue only if chatter is not silent | ||
| 287 | + if (chatter != SILENT) { | ||
| 288 | + | ||
| 289 | + // Append header | ||
| 290 | + result.append("=== GVOClient ==="); | ||
| 291 | + | ||
| 292 | + // Append client information | ||
| 293 | + result.append("\n"+gammalib::parformat("Name")+m_name); | ||
| 294 | + | ||
| 295 | + // Append Hub information | ||
| 296 | + if (has_hub()) { | ||
| 297 | + result.append("\n"+gammalib::parformat("Hub key")+m_secret); | ||
| 298 | + result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url); | ||
| 299 | + result.append("\n"+gammalib::parformat("Hub host (port)")); | ||
| 300 | + result.append(m_hub_host+" ("+m_hub_port+")"); | ||
| 301 | + result.append("\n"+gammalib::parformat("SAMP protocol version")); | ||
| 302 | + result.append(m_version); | ||
| 303 | + result.append("\n"+gammalib::parformat("Hub connection")); | ||
| 304 | + if (m_socket == -1) { | ||
| 305 | + result.append("no"); | ||
| 306 | + } | ||
| 307 | + else { | ||
| 308 | + if (!m_client_key.empty()) { | ||
| 309 | + result.append("registered as \""+m_client_id); | ||
| 310 | + result.append("\" on Hub \""+m_hub_id); | ||
| 311 | + result.append("\" via socket "+gammalib::str(m_socket)); | ||
| 312 | + } | ||
| 313 | + else { | ||
| 314 | + result.append("established on socket "); | ||
| 315 | + result.append(gammalib::str(m_socket)); | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + } | ||
| 319 | + else { | ||
| 320 | + result.append("\n"+gammalib::parformat("Hub key")); | ||
| 321 | + result.append("No Hub has been found"); | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + } // endif: chatter was not silent | ||
| 325 | + | ||
| 326 | + // Return result | ||
| 327 | + return result; | ||
| 328 | +} | ||
| 329 | + | ||
| 330 | + | ||
| 331 | +/*========================================================================== | ||
| 332 | + = = | ||
| 333 | + = Private methods = | ||
| 334 | + = = | ||
| 335 | + ==========================================================================*/ | ||
| 336 | + | ||
| 337 | +/***********************************************************************//** | ||
| 338 | + * @brief Initialise class members | ||
| 339 | + ***************************************************************************/ | ||
| 340 | +void GVOClient::init_members(void) | ||
| 341 | +{ | ||
| 342 | + // Initialise members | ||
| 343 | + m_name = "GammaLib"; | ||
| 344 | + m_secret.clear(); | ||
| 345 | + m_hub_url.clear(); | ||
| 346 | + m_hub_host.clear(); | ||
| 347 | + m_hub_port.clear(); | ||
| 348 | + m_version.clear(); | ||
| 349 | + m_client_key.clear(); | ||
| 350 | + m_hub_id.clear(); | ||
| 351 | + m_client_id.clear(); | ||
| 352 | + m_socket = -1; // Signals no socket | ||
| 353 | + | ||
| 354 | + // Return | ||
| 355 | + return; | ||
| 356 | +} | ||
| 357 | + | ||
| 358 | + | ||
| 359 | +/***********************************************************************//** | ||
| 360 | + * @brief Copy class members | ||
| 361 | + * | ||
| 362 | + * @param[in] client VO client. | ||
| 363 | + ***************************************************************************/ | ||
| 364 | +void GVOClient::copy_members(const GVOClient& client) | ||
| 365 | +{ | ||
| 366 | + // Copy members | ||
| 367 | + m_name = client.m_name; | ||
| 368 | + m_secret = client.m_secret; | ||
| 369 | + m_hub_url = client.m_hub_url; | ||
| 370 | + m_hub_host = client.m_hub_host; | ||
| 371 | + m_hub_port = client.m_hub_port; | ||
| 372 | + m_version = client.m_version; | ||
| 373 | + m_client_key = client.m_client_key; | ||
| 374 | + m_hub_id = client.m_hub_id; | ||
| 375 | + m_client_id = client.m_client_id; | ||
| 376 | + m_socket = client.m_socket; | ||
| 377 | + | ||
| 378 | + // Return | ||
| 379 | + return; | ||
| 380 | +} | ||
| 381 | + | ||
| 382 | + | ||
| 383 | +/***********************************************************************//** | ||
| 384 | + * @brief Delete class members | ||
| 385 | + ***************************************************************************/ | ||
| 386 | +void GVOClient::free_members(void) | ||
| 387 | +{ | ||
| 388 | + // Unregister from Hub | ||
| 389 | + unregister_from_hub(); | ||
| 390 | + | ||
| 391 | + // Close socket | ||
| 392 | + if (m_socket != -1) { | ||
| 393 | + close(m_socket); | ||
| 394 | + m_socket = -1; | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + // Return | ||
| 398 | + return; | ||
| 399 | +} | ||
| 400 | + | ||
| 401 | + | ||
| 402 | +/***********************************************************************//** | ||
| 403 | + * @brief Find SAMP Hub | ||
| 404 | + * | ||
| 405 | + * @return True of SAMP Hub has been found, false otherwise. | ||
| 406 | + * | ||
| 407 | + * Search a valid SAMP Hub and retrieve all mandatory token for this Hub. | ||
| 408 | + * The manadtory tokens are | ||
| 409 | + * | ||
| 410 | + * samp.secret Opaque text string required for Hub registration | ||
| 411 | + * samp.hub.xmlrpc.url XML-RPC endpoint for communication | ||
| 412 | + * samp.profile.version Version of SAMP profile | ||
| 413 | + * | ||
| 414 | + * Implements IVOA standard REC-SAMP-1.3-20120411. | ||
| 415 | + * | ||
| 416 | + * @todo If no valid Hub was found the method should attempt to start its | ||
| 417 | + * own Hub. | ||
| 418 | + ***************************************************************************/ | ||
| 419 | +bool GVOClient::find_hub(void) | ||
| 420 | +{ | ||
| 421 | + // Allocate line buffer | ||
| 422 | + const int n = 1000; | ||
| 423 | + char line[n]; | ||
| 424 | + | ||
| 425 | + // Initialise find flag to false | ||
| 426 | + bool found = false; | ||
| 427 | + | ||
| 428 | + // Get lockfile URL | ||
| 429 | + std::string lockurl = get_hub_lockfile(); | ||
| 430 | + | ||
| 431 | + // Continue only if a URL has been found | ||
| 432 | + if (!lockurl.empty()) { | ||
| 433 | + | ||
| 434 | + // If we have a file:// prefix then strip it now. This is a kluge | ||
| 435 | + // and should be remplaced by a method that allows opening any kind | ||
| 436 | + // of URL | ||
| 437 | + if (lockurl.compare(0, 7, "file://") == 0) { | ||
| 438 | + lockurl = lockurl.substr(7, std::string::npos); | ||
| 439 | + } | ||
| 440 | + | ||
| 441 | + // Open SAMP lockfile. Continue only if opening was successful | ||
| 442 | + FILE* fptr = fopen(lockurl.c_str(), "r"); | ||
| 443 | + if (fptr != NULL) { | ||
| 444 | + | ||
| 445 | + // Parse lockfile and search for mandatory tokens | ||
| 446 | + while (fgets(line, n, fptr) != NULL) { | ||
| 447 | + | ||
| 448 | + // Convert line to C++ string | ||
| 449 | + std::string cline = std::string(line); | ||
| 450 | + | ||
| 451 | + // Check for secret key | ||
| 452 | + if (cline.compare(0, 12, "samp.secret=") == 0) { | ||
| 453 | + m_secret = gammalib::strip_chars(cline.substr(12, std::string::npos), "\r\n"); | ||
| 454 | + } | ||
| 455 | + | ||
| 456 | + // Check for Hub URL | ||
| 457 | + else if (cline.compare(0, 20, "samp.hub.xmlrpc.url=") == 0) { | ||
| 458 | + m_hub_url = gammalib::strip_chars(cline.substr(20, std::string::npos), "\r\n"); | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + // Check for profile version | ||
| 462 | + else if (cline.compare(0, 21, "samp.profile.version=") == 0) { | ||
| 463 | + m_version = gammalib::strip_chars(cline.substr(21, std::string::npos), "\r\n"); | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + // Close SAMP lockfile | ||
| 469 | + fclose(fptr); | ||
| 470 | + | ||
| 471 | + // Extract host and port from Hub URL | ||
| 472 | + if (m_hub_url.compare(0, 7, "http://") == 0) { | ||
| 473 | + size_t length; | ||
| 474 | + size_t start = 7; | ||
| 475 | + size_t stop = m_hub_url.find(":", start); | ||
| 476 | + if (stop != std::string::npos) { | ||
| 477 | + length = stop - start; | ||
| 478 | + } | ||
| 479 | + else { | ||
| 480 | + length = std::string::npos; | ||
| 481 | + } | ||
| 482 | + m_hub_host = m_hub_url.substr(start, length); | ||
| 483 | + if (stop != std::string::npos) { | ||
| 484 | + stop = stop + 1; | ||
| 485 | + size_t end = m_hub_url.find("/", stop); | ||
| 486 | + if (end != std::string::npos) { | ||
| 487 | + length = end - stop; | ||
| 488 | + } | ||
| 489 | + else { | ||
| 490 | + length = std::string::npos; | ||
| 491 | + } | ||
| 492 | + m_hub_port = m_hub_url.substr(stop, length); | ||
| 493 | + } | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + // Check for existence of mandatory tokens | ||
| 497 | + found = has_hub(); | ||
| 498 | + | ||
| 499 | + } // endif: SAMP lockfile opened | ||
| 500 | + | ||
| 501 | + } // endif: URL has been found | ||
| 502 | + | ||
| 503 | + //TODO: Create GammaLib own Hub in case that no Hub has been found | ||
| 504 | + //if (!found) { | ||
| 505 | + //} | ||
| 506 | + | ||
| 507 | + // If no Hub has been found, clear all Hub related members | ||
| 508 | + if (!found) { | ||
| 509 | + m_secret.clear(); | ||
| 510 | + m_hub_url.clear(); | ||
| 511 | + m_version.clear(); | ||
| 512 | + } | ||
| 513 | + | ||
| 514 | + // Return find flag | ||
| 515 | + return found; | ||
| 516 | +} | ||
| 517 | + | ||
| 518 | + | ||
| 519 | +/***********************************************************************//** | ||
| 520 | + * @brief Connect to SAMP Hub | ||
| 521 | + * | ||
| 522 | + * Connects to Hub by creating a socket and connecting to this socket. The | ||
| 523 | + * method expects that a Hub has already been found. If no Hub has been found | ||
| 524 | + * (i.e. has_hub() returns false), the method does nothing. | ||
| 525 | + * | ||
| 526 | + * The method extracts the hostname and the port from the Hub endpoint URL. | ||
| 527 | + * If Hub connection fails, any created socket is closed. | ||
| 528 | + * | ||
| 529 | + * If the method is successful, m_socket will contain on exit a non-negative | ||
| 530 | + * number. If any failure occurs, m_socket will be set to -1. | ||
| 531 | + ***************************************************************************/ | ||
| 532 | +void GVOClient::connect_to_hub(void) | ||
| 533 | +{ | ||
| 534 | + // Close any existing socket | ||
| 535 | + if (m_socket != -1) { | ||
| 536 | + close(m_socket); | ||
| 537 | + m_socket = -1; | ||
| 538 | + } | ||
| 539 | + | ||
| 540 | + // Continue only if host and port information was found | ||
| 541 | + if (!m_hub_host.empty() && !m_hub_port.empty()) { | ||
| 542 | + | ||
| 543 | + // Set hints | ||
| 544 | + struct addrinfo hints; | ||
| 545 | + std::memset(&hints, 0, sizeof(hints)); | ||
| 546 | + hints.ai_family = AF_INET; | ||
| 547 | + hints.ai_socktype = SOCK_STREAM; | ||
| 548 | + | ||
| 549 | + // Get server information | ||
| 550 | + struct addrinfo* servinfo; | ||
| 551 | + if (getaddrinfo(m_hub_host.c_str(), m_hub_port.c_str(), | ||
| 552 | + &hints, &servinfo) == 0) { | ||
| 553 | + | ||
| 554 | + // Loop through all the results and connect to the first | ||
| 555 | + // we can | ||
| 556 | + for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) { | ||
| 557 | + | ||
| 558 | + // Create socket | ||
| 559 | + m_socket = socket(ptr->ai_family, | ||
| 560 | + ptr->ai_socktype, | ||
| 561 | + ptr->ai_protocol); | ||
| 562 | + | ||
| 563 | + // Connect to socket if socket is valid | ||
| 564 | + if (m_socket != -1) { | ||
| 565 | + if (::connect(m_socket, | ||
| 566 | + ptr->ai_addr, | ||
| 567 | + ptr->ai_addrlen) == -1) { | ||
| 568 | + close(m_socket); | ||
| 569 | + m_socket = -1; | ||
| 570 | + } | ||
| 571 | + } | ||
| 572 | + | ||
| 573 | + } // endfor: looped through all results | ||
| 574 | + | ||
| 575 | + } // endif: server information was valid | ||
| 576 | + | ||
| 577 | + } // endif: host and port information found | ||
| 578 | + | ||
| 579 | + // Return | ||
| 580 | + return; | ||
| 581 | +} | ||
| 582 | + | ||
| 583 | + | ||
| 584 | +/***********************************************************************//** | ||
| 585 | + * @brief Register client at SAMP Hub | ||
| 586 | + ***************************************************************************/ | ||
| 587 | +void GVOClient::register_to_hub(void) | ||
| 588 | +{ | ||
| 589 | + // Connect to Hub | ||
| 590 | + connect_to_hub(); | ||
| 591 | + | ||
| 592 | + // Continue only if Hub connection has been established | ||
| 593 | + if (m_socket != -1) { | ||
| 594 | + | ||
| 595 | + // Declare message | ||
| 596 | + std::string msg = ""; | ||
| 597 | + | ||
| 598 | + // Set metadata header | ||
| 599 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 600 | + msg.append("<methodCall>\n"); | ||
| 601 | + msg.append("<methodName>samp.hub.register</methodName>\n"); | ||
| 602 | + msg.append("<params>\n"); | ||
| 603 | + msg.append("<param><value><string>"+m_secret+"</string></value></param>\n"); | ||
| 604 | + msg.append("</params>\n"); | ||
| 605 | + msg.append("</methodCall>\n"); | ||
| 606 | + | ||
| 607 | + // Post message | ||
| 608 | + post_string(msg); | ||
| 609 | + printf("Waiting for Hub response\n"); | ||
| 610 | + fflush(stdout); | ||
| 611 | + // Get Hub response | ||
| 612 | + GXml xml = response(); | ||
| 613 | + | ||
| 614 | + printf("Hub response received"); | ||
| 615 | + fflush(stdout); | ||
| 616 | + | ||
| 617 | + // Extract Hub and client identifiers | ||
| 618 | + m_client_key = get_response_value(xml, "samp.private-key"); | ||
| 619 | + m_hub_id = get_response_value(xml, "samp.hub-id"); | ||
| 620 | + m_client_id = get_response_value(xml, "samp.self-id"); | ||
| 621 | + | ||
| 622 | + } // endif: Hub connection has been established | ||
| 623 | + | ||
| 624 | + // Return | ||
| 625 | + return; | ||
| 626 | +} | ||
| 627 | + | ||
| 628 | + | ||
| 629 | +/***********************************************************************//** | ||
| 630 | + * @brief Unregister client from SAMP Hub | ||
| 631 | + ***************************************************************************/ | ||
| 632 | +void GVOClient::unregister_from_hub(void) | ||
| 633 | +{ | ||
| 634 | + // Connect to Hub | ||
| 635 | + connect_to_hub(); | ||
| 636 | + | ||
| 637 | + // Continue only if Hub connection has been established | ||
| 638 | + if (m_socket != -1) { | ||
| 639 | + | ||
| 640 | + // Declare message | ||
| 641 | + std::string msg = ""; | ||
| 642 | + | ||
| 643 | + // Set metadata header | ||
| 644 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 645 | + msg.append("<methodCall>\n"); | ||
| 646 | + msg.append("<methodName>samp.hub.unregister</methodName>\n"); | ||
| 647 | + msg.append("<params>\n"); | ||
| 648 | + msg.append("<param><value><string>"+m_client_key+"</string></value></param>\n"); | ||
| 649 | + msg.append("</params>\n"); | ||
| 650 | + msg.append("</methodCall>\n"); | ||
| 651 | + | ||
| 652 | + // Post message | ||
| 653 | + post_string(msg); | ||
| 654 | + | ||
| 655 | + // Get Hub response | ||
| 656 | + GXml xml = response(); | ||
| 657 | + | ||
| 658 | + // Reset Hub and client identifiers | ||
| 659 | + m_client_key.clear(); | ||
| 660 | + m_hub_id.clear(); | ||
| 661 | + m_client_id.clear(); | ||
| 662 | + | ||
| 663 | + } // endif: Hub connection has been established | ||
| 664 | + | ||
| 665 | + // Return | ||
| 666 | + return; | ||
| 667 | +} | ||
| 668 | + | ||
| 669 | + | ||
| 670 | +/***********************************************************************//** | ||
| 671 | + * @brief Send client metadata to Hub | ||
| 672 | + ***************************************************************************/ | ||
| 673 | +void GVOClient::send_metadata(void) | ||
| 674 | +{ | ||
| 675 | + // Connect to Hub. This was needed to post the metadata to the Hub. | ||
| 676 | + // Apparently, the connection is lost after each write/read cycle. | ||
| 677 | + // Maybe this is socket standard? | ||
| 678 | + connect_to_hub(); | ||
| 679 | + | ||
| 680 | + printf("send metadata function \n"); | ||
| 681 | + fflush(stdout); | ||
| 682 | + // Continue only if Hub connection has been established | ||
| 683 | + if (m_socket != -1) { | ||
| 684 | + | ||
| 685 | + // Declare message | ||
| 686 | + std::string msg = ""; | ||
| 687 | + | ||
| 688 | + // Set metadata header | ||
| 689 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 690 | + msg.append("<methodCall>\n"); | ||
| 691 | + msg.append("<methodName>samp.hub.declareMetadata</methodName>\n"); | ||
| 692 | + msg.append("<params>\n"); | ||
| 693 | + msg.append("<param><value><string>"+m_client_key+"</string></value></param>\n"); | ||
| 694 | + msg.append("<param><value><struct>\n"); | ||
| 695 | + | ||
| 696 | + // Set SAMP name | ||
| 697 | + msg.append("<member>\n"); | ||
| 698 | + msg.append("<name>samp.name</name>\n"); | ||
| 699 | + msg.append("<value><string>"+m_name+"</string></value>\n"); | ||
| 700 | + msg.append("</member>\n"); | ||
| 701 | + | ||
| 702 | + // Set SAMP description text | ||
| 703 | + msg.append("<member>\n"); | ||
| 704 | + msg.append("<name>samp.description.text</name>\n"); | ||
| 705 | + msg.append("<value><string>GammaLib client</string></value>\n"); | ||
| 706 | + msg.append("</member>\n"); | ||
| 707 | + | ||
| 708 | + // Set SAMP icon URL | ||
| 709 | + msg.append("<member>\n"); | ||
| 710 | + msg.append("<name>samp.icon.url</name>\n"); | ||
| 711 | + msg.append("<value><string>http://a.fsdn.com/allura/p/gammalib/icon</string></value>\n"); | ||
| 712 | + msg.append("</member>\n"); | ||
| 713 | + | ||
| 714 | + // Set author affiliation | ||
| 715 | + msg.append("<member>\n"); | ||
| 716 | + msg.append("<name>author.affiliation</name>\n"); | ||
| 717 | + msg.append("<value><string>IRAP, Toulouse, France</string></value>\n"); | ||
| 718 | + msg.append("</member>\n"); | ||
| 719 | + | ||
| 720 | + // Set author e-mail | ||
| 721 | + msg.append("<member>\n"); | ||
| 722 | + msg.append("<name>author.email</name>\n"); | ||
| 723 | + msg.append("<value><string>jurgen.knodlseder@irap.omp.eu</string></value>\n"); | ||
| 724 | + msg.append("</member>\n"); | ||
| 725 | + | ||
| 726 | + // Set author name | ||
| 727 | + msg.append("<member>\n"); | ||
| 728 | + msg.append("<name>author.name</name>\n"); | ||
| 729 | + msg.append("<value><string>Juergen Knoedlseder</string></value>\n"); | ||
| 730 | + msg.append("</member>\n"); | ||
| 731 | + | ||
| 732 | + // Set metadata trailer | ||
| 733 | + msg.append("</struct></value></param>\n"); | ||
| 734 | + msg.append("</params>\n"); | ||
| 735 | + msg.append("</methodCall>\n"); | ||
| 736 | + | ||
| 737 | + // Post message | ||
| 738 | + post_string(msg); | ||
| 739 | + | ||
| 740 | + // Get Hub response | ||
| 741 | + GXml xml = response(); | ||
| 742 | + | ||
| 743 | + } // endif: Hub connection has been established | ||
| 744 | + | ||
| 745 | + // Return | ||
| 746 | + return; | ||
| 747 | +} | ||
| 748 | + | ||
| 749 | + | ||
| 750 | +/***********************************************************************//** | ||
| 751 | + * @brief Returns value for a SAMP Hub response parameter | ||
| 752 | + * | ||
| 753 | + * @param[in] xml Hub response XML document. | ||
| 754 | + * @param[in] name Parameter name. | ||
| 755 | + * @return Parameter value. | ||
| 756 | + * | ||
| 757 | + * Returns value for a SAMP Hub response parameter. If the specified | ||
| 758 | + * parameter was not found or if the response structure is not compliant, | ||
| 759 | + * an empty string is returned. | ||
| 760 | + ***************************************************************************/ | ||
| 761 | +std::string GVOClient::get_response_value(const GXml& xml, | ||
| 762 | + const std::string& name) const | ||
| 763 | +{ | ||
| 764 | + // Declare value | ||
| 765 | + std::string value = ""; | ||
| 766 | + | ||
| 767 | + // Search for value of specified member | ||
| 768 | + const GXmlNode* node = xml.element("methodResponse", 0); | ||
| 769 | + if (node != NULL) { | ||
| 770 | + node = node->element("params", 0); | ||
| 771 | + if (node != NULL) { | ||
| 772 | + node = node->element("param", 0); | ||
| 773 | + if (node != NULL) { | ||
| 774 | + node = node->element("value", 0); | ||
| 775 | + if (node != NULL) { | ||
| 776 | + node = node->element("struct", 0); | ||
| 777 | + if (node != NULL) { | ||
| 778 | + int num = node->elements("member"); | ||
| 779 | + for (int i = 0; i < num; ++i) { | ||
| 780 | + const GXmlNode* member = node->element("member", i); | ||
| 781 | + std::string one_name; | ||
| 782 | + std::string one_value; | ||
| 783 | + get_name_value_pair(member, one_name, one_value); | ||
| 784 | + if (one_name == name) { | ||
| 785 | + value = one_value; | ||
| 786 | + break; | ||
| 787 | + } | ||
| 788 | + } | ||
| 789 | + } | ||
| 790 | + } | ||
| 791 | + } | ||
| 792 | + } | ||
| 793 | + } | ||
| 794 | + | ||
| 795 | + // Return value | ||
| 796 | + return value; | ||
| 797 | +} | ||
| 798 | + | ||
| 799 | + | ||
| 800 | +/***********************************************************************//** | ||
| 801 | + * @brief Extract name / value pair from XML node | ||
| 802 | + * | ||
| 803 | + * @param[in] node Pointer to XML node. | ||
| 804 | + * @param[out] name Name string. | ||
| 805 | + * @param[out] value Value string. | ||
| 806 | + * | ||
| 807 | + * Extracts a name / value pair from a XML node. If the XML node pointer is | ||
| 808 | + * NULL, the name and value strings will be empty. | ||
| 809 | + ***************************************************************************/ | ||
| 810 | +void GVOClient::get_name_value_pair(const GXmlNode* node, | ||
| 811 | + std::string& name, | ||
| 812 | + std::string& value) const | ||
| 813 | +{ | ||
| 814 | + // Clear name and value strings | ||
| 815 | + name.clear(); | ||
| 816 | + value.clear(); | ||
| 817 | + | ||
| 818 | + // Continue only if node is valid | ||
| 819 | + if (node != NULL) { | ||
| 820 | + | ||
| 821 | + // Get name node and extract text content | ||
| 822 | + const GXmlNode* ptr = node->element("name", 0); | ||
| 823 | + if (ptr != NULL) { | ||
| 824 | + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]); | ||
| 825 | + if (text != NULL) { | ||
| 826 | + name = text->text(); | ||
| 827 | + } | ||
| 828 | + } | ||
| 829 | + | ||
| 830 | + // Get value node and extract text content | ||
| 831 | + ptr = node->element("value", 0); | ||
| 832 | + if (ptr != NULL) { | ||
| 833 | + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]); | ||
| 834 | + if (text != NULL) { | ||
| 835 | + value = text->text(); | ||
| 836 | + } | ||
| 837 | + } | ||
| 838 | + } | ||
| 839 | + | ||
| 840 | + // Return | ||
| 841 | + return; | ||
| 842 | +} | ||
| 843 | + | ||
| 844 | + | ||
| 845 | +/***********************************************************************//** | ||
| 846 | + * @brief Post string content to Hub | ||
| 847 | + * | ||
| 848 | + * @param[in] content String content to post | ||
| 849 | + * | ||
| 850 | + * Posts the content of a string to the Hub. | ||
| 851 | + * | ||
| 852 | + * The method does nothing if no Hub connection has been established. | ||
| 853 | + ***************************************************************************/ | ||
| 854 | +void GVOClient::post_string(const std::string& content) const | ||
| 855 | +{ | ||
| 856 | + // Continue only if Hub connection has been established | ||
| 857 | + if (m_socket != -1) { | ||
| 858 | + | ||
| 859 | + // Determine content length | ||
| 860 | + int length = content.length(); | ||
| 861 | + | ||
| 862 | + // Set prefix | ||
| 863 | + std::string prefix = "POST /xmlrpc-1 HTTP/1.0\n" | ||
| 864 | + "User-Agent: GammaLib\n" | ||
| 865 | + "Content-Type: text/xml\n" | ||
| 866 | + "Content-Length: "+gammalib::str(length)+"\n\n"; | ||
| 867 | + | ||
| 868 | + // Build post string | ||
| 869 | + std::string post = prefix + content; | ||
| 870 | + | ||
| 871 | + // Send content to socket | ||
| 872 | + bool done = false; | ||
| 873 | + do { | ||
| 874 | + int length = post.length(); | ||
| 875 | + int sent_length = send(m_socket, post.c_str(), length, 0); | ||
| 876 | + if (sent_length < length) { | ||
| 877 | + post = post.substr(sent_length, std::string::npos); | ||
| 878 | + } | ||
| 879 | + else { | ||
| 880 | + done = true; | ||
| 881 | + } | ||
| 882 | + } while (!done); | ||
| 883 | + | ||
| 884 | + } // endif: Hub connection had been established | ||
| 885 | + | ||
| 886 | + // Return | ||
| 887 | + return; | ||
| 888 | +} | ||
| 889 | + | ||
| 890 | + | ||
| 891 | +/***********************************************************************//** | ||
| 892 | + * @brief Receive string content from Hub | ||
| 893 | + * | ||
| 894 | + * @return String received from Hub. | ||
| 895 | + * | ||
| 896 | + * Reads information sent by Hub into a string. | ||
| 897 | + * | ||
| 898 | + * The method does nothing if no Hub connection has been established. | ||
| 899 | + ***************************************************************************/ | ||
| 900 | +std::string GVOClient::receive_string(void) const | ||
| 901 | +{ | ||
| 902 | + // Initialise empty string | ||
| 903 | + std::string result = ""; | ||
| 904 | + | ||
| 905 | + // Continue only if Hub connection has been established | ||
| 906 | + if (m_socket != -1) { | ||
| 907 | + | ||
| 908 | + // Define buffer | ||
| 909 | + char buffer[1001]; | ||
| 910 | + | ||
| 911 | + // Read buffer until it is empty | ||
| 912 | + int n = 0; | ||
| 913 | + //do { | ||
| 914 | + printf("receive socket instruction\n"); | ||
| 915 | + fflush(stdout); | ||
| 916 | + n = recv(m_socket, buffer, 1000, 0); | ||
| 917 | + printf("data received: %s\n",buffer); | ||
| 918 | + fflush(stdout); | ||
| 919 | + if (n > 0) { | ||
| 920 | + buffer[n+1] = '\0'; | ||
| 921 | + result.append(std::string(buffer)); | ||
| 922 | + } | ||
| 923 | + //} while (n > 0); | ||
| 924 | + | ||
| 925 | + } // endif: Hub connection had been established | ||
| 926 | + | ||
| 927 | + // Return result | ||
| 928 | + return result; | ||
| 929 | +} | ||
| 930 | + | ||
| 931 | + | ||
| 932 | +/***********************************************************************//** | ||
| 933 | + * @brief Returns SAMP Hub lockfile URL | ||
| 934 | + * | ||
| 935 | + * @return SAMP Hub lockfile URL (empty if no lockfile was found). | ||
| 936 | + * | ||
| 937 | + * Implements IVOA standard REC-SAMP-1.3-20120411. | ||
| 938 | + ***************************************************************************/ | ||
| 939 | +std::string GVOClient::get_hub_lockfile(void) const | ||
| 940 | +{ | ||
| 941 | + // Initialise result | ||
| 942 | + std::string url = ""; | ||
| 943 | + | ||
| 944 | + // Check for existence of the SAMP_HUB environment variable first | ||
| 945 | + char* hub_ptr = std::getenv("SAMP_HUB"); | ||
| 946 | + if (hub_ptr != NULL) { | ||
| 947 | + | ||
| 948 | + // Check for mandatory std-lockurl: prefix (no other prefixe is | ||
| 949 | + // supported so far) | ||
| 950 | + std::string lockurl = std::string(hub_ptr); | ||
| 951 | + if (lockurl.compare(0, 12, "std-lockurl:") == 0) { | ||
| 952 | + | ||
| 953 | + // Extract URL | ||
| 954 | + url = lockurl.substr(12, std::string::npos); | ||
| 955 | + | ||
| 956 | + } // endif: std-lockurl: prefix found | ||
| 957 | + | ||
| 958 | + } | ||
| 959 | + | ||
| 960 | + // ... otherwise the lockfile should be $HOME/.samp | ||
| 961 | + else { | ||
| 962 | + | ||
| 963 | + // Get user's HOME directory path as the prefix of the full | ||
| 964 | + // path. If the HOME environment variable is not set we | ||
| 965 | + // expect that .samp is in the local directory. This is non | ||
| 966 | + // standard, but prevents for creating an exception here. | ||
| 967 | + std::string prefix = ""; | ||
| 968 | + char* home_ptr = std::getenv("HOME"); | ||
| 969 | + if (home_ptr != NULL) { | ||
| 970 | + prefix = std::string(home_ptr) + "/"; | ||
| 971 | + } | ||
| 972 | + | ||
| 973 | + // Set filename | ||
| 974 | + url = prefix + ".samp"; | ||
| 975 | + | ||
| 976 | + } // endelse: no SAMP_HUB environment variable found | ||
| 977 | + | ||
| 978 | + // Return URL | ||
| 979 | + return url; | ||
| 980 | +} |
src/vo/GVOHub.cpp
| @@ -488,7 +488,7 @@ void GVOHub::handle_request(const socklen_t& sock) | @@ -488,7 +488,7 @@ void GVOHub::handle_request(const socklen_t& sock) | ||
| 488 | request_ping(sock); | 488 | request_ping(sock); |
| 489 | } | 489 | } |
| 490 | else if (method_called.compare("samp.hub.call") == 0) { | 490 | else if (method_called.compare("samp.hub.call") == 0) { |
| 491 | - request_ping(sock); | 491 | + request_call(xml,sock); |
| 492 | } | 492 | } |
| 493 | else if (method_called.compare("samp.hub.callAll") == 0) { | 493 | else if (method_called.compare("samp.hub.callAll") == 0) { |
| 494 | request_ping(sock); | 494 | request_ping(sock); |
| @@ -904,9 +904,8 @@ void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& so | @@ -904,9 +904,8 @@ void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& so | ||
| 904 | 904 | ||
| 905 | // Declare message | 905 | // Declare message |
| 906 | std::string msg = ""; | 906 | std::string msg = ""; |
| 907 | - | ||
| 908 | // Set response | 907 | // Set response |
| 909 | - msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n"); | 908 | + msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
| 910 | msg.append("<methodResponse>\n"); | 909 | msg.append("<methodResponse>\n"); |
| 911 | msg.append("<params>\n"); | 910 | msg.append("<params>\n"); |
| 912 | msg.append(" <param><value><array><data>\n"); | 911 | msg.append(" <param><value><array><data>\n"); |
| @@ -925,7 +924,6 @@ void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& so | @@ -925,7 +924,6 @@ void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& so | ||
| 925 | msg.append(" </data></array></value></param>\n"); | 924 | msg.append(" </data></array></value></param>\n"); |
| 926 | msg.append("</params>\n"); | 925 | msg.append("</params>\n"); |
| 927 | msg.append("</methodResponse>\n"); | 926 | msg.append("</methodResponse>\n"); |
| 928 | - | ||
| 929 | // Post response | 927 | // Post response |
| 930 | post_string(msg, sock); | 928 | post_string(msg, sock); |
| 931 | 929 | ||
| @@ -950,6 +948,14 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so | @@ -950,6 +948,14 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so | ||
| 950 | std::cout << "GVOHub::request_get_subscribed_clients" << std::endl; | 948 | std::cout << "GVOHub::request_get_subscribed_clients" << std::endl; |
| 951 | #endif | 949 | #endif |
| 952 | 950 | ||
| 951 | + // Declare message | ||
| 952 | + std::string msg = ""; | ||
| 953 | + | ||
| 954 | + msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n"); | ||
| 955 | + msg.append("<methodResponse>\n"); | ||
| 956 | + msg.append("<params>\n"); | ||
| 957 | + msg.append(" <param><value><struct><member><name>c0</name><value><struct></struct></value></member><member><name>gammalib_hub</name><value><struct></struct></value></member></struct></value></param></params></methodResponse>"); | ||
| 958 | + | ||
| 953 | /* | 959 | /* |
| 954 | std::string buffer; | 960 | std::string buffer; |
| 955 | const int n = 1000; | 961 | const int n = 1000; |
| @@ -971,8 +977,10 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so | @@ -971,8 +977,10 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so | ||
| 971 | fclose(fptr); | 977 | fclose(fptr); |
| 972 | */ | 978 | */ |
| 973 | 979 | ||
| 980 | + // Post response | ||
| 981 | + post_string(msg, sock); | ||
| 974 | // Post void message | 982 | // Post void message |
| 975 | - post_samp_void(sock); | 983 | + //post_samp_void(sock); |
| 976 | 984 | ||
| 977 | // Return | 985 | // Return |
| 978 | return; | 986 | return; |
| @@ -1114,6 +1122,77 @@ void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock) | @@ -1114,6 +1122,77 @@ void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock) | ||
| 1114 | return; | 1122 | return; |
| 1115 | } | 1123 | } |
| 1116 | 1124 | ||
| 1125 | +/***********************************************************************//** | ||
| 1126 | + * @brief Handles calls to specific client | ||
| 1127 | + * | ||
| 1128 | + * @param[in] xml XML message sent by client. | ||
| 1129 | + * @param[in] sock Socket. | ||
| 1130 | + * | ||
| 1131 | + * Handles all incoming cals for a specific client | ||
| 1132 | + ***************************************************************************/ | ||
| 1133 | +void GVOHub::request_call(const GXml& xml, const socklen_t& sock) | ||
| 1134 | +{ | ||
| 1135 | + // Header | ||
| 1136 | + #if defined(G_CONSOLE_DUMP) | ||
| 1137 | + std::cout << "GVOHub::request_get_registered_clients" << std::endl; | ||
| 1138 | + #endif | ||
| 1139 | + | ||
| 1140 | + // Get client key | ||
| 1141 | + std::string key = get_client_key(xml); | ||
| 1142 | + // Get message mtype | ||
| 1143 | + std::string mtype = get_mtype(xml); | ||
| 1144 | + // Get the key of client who is to be contacted with the message | ||
| 1145 | + // Declare message | ||
| 1146 | + std::string msg = ""; | ||
| 1147 | + // Determine which call has been invoqued | ||
| 1148 | + // Loop over all clients and send notification | ||
| 1149 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 1150 | + msg = ""; | ||
| 1151 | + | ||
| 1152 | + // Set response for table.load.votable | ||
| 1153 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 1154 | + msg.append("<methodCall><methodName>samp.client.receiveCall</methodName>\n"); | ||
| 1155 | + msg.append("<params>\n"); | ||
| 1156 | + msg.append(" <param><value>"); | ||
| 1157 | + msg.append(m_clients[i].private_key); | ||
| 1158 | + msg.append("</value></param>\n"); | ||
| 1159 | + msg.append(" <param><value>"+m_hub_id+"</value></param>\n"); | ||
| 1160 | + msg.append(" <param><value><struct>\n"); | ||
| 1161 | + msg.append(" <member>\n"); | ||
| 1162 | + msg.append(" <name>samp.mtype</name>\n"); | ||
| 1163 | + msg.append(" <value>table.load.votable</value>\n"); | ||
| 1164 | + msg.append(" </member>\n"); | ||
| 1165 | + msg.append(" <member>\n"); | ||
| 1166 | + msg.append(" <name>samp.params</name>\n"); | ||
| 1167 | + msg.append(" <value><struct>\n"); | ||
| 1168 | + msg.append(" <member>\n"); | ||
| 1169 | + msg.append(" <name>name</name>\n"); | ||
| 1170 | + msg.append(" <value>imagename</value>\n"); | ||
| 1171 | + msg.append(" </member>\n"); | ||
| 1172 | + msg.append(" <member>\n"); | ||
| 1173 | + msg.append(" <name>table-id</name>\n"); | ||
| 1174 | + msg.append(" <value>id of table</value>\n"); | ||
| 1175 | + msg.append(" </member>\n"); | ||
| 1176 | + msg.append(" <member>\n"); | ||
| 1177 | + msg.append(" <name>url</name>\n"); | ||
| 1178 | + msg.append(" <value>url to the table</value>\n"); | ||
| 1179 | + msg.append(" </member>\n"); | ||
| 1180 | + msg.append(" </struct></value>\n"); | ||
| 1181 | + msg.append(" </member>\n"); | ||
| 1182 | + msg.append(" </struct></value>\n"); | ||
| 1183 | + msg.append(" </param>\n"); | ||
| 1184 | + msg.append("</params>\n"); | ||
| 1185 | + msg.append("</methodCall>\n"); | ||
| 1186 | + | ||
| 1187 | + | ||
| 1188 | + // Post notification | ||
| 1189 | + notify(m_clients[i].url, msg); | ||
| 1190 | + } | ||
| 1191 | + | ||
| 1192 | + // Return | ||
| 1193 | + return; | ||
| 1194 | + | ||
| 1195 | +} | ||
| 1117 | 1196 | ||
| 1118 | /***********************************************************************//** | 1197 | /***********************************************************************//** |
| 1119 | * @brief Handles Hub shutdown requests | 1198 | * @brief Handles Hub shutdown requests |
| @@ -1947,4 +2026,61 @@ std::string GVOHub::random_string(const size_t& length) const | @@ -1947,4 +2026,61 @@ std::string GVOHub::random_string(const size_t& length) const | ||
| 1947 | // Return string | 2026 | // Return string |
| 1948 | return str; | 2027 | return str; |
| 1949 | } | 2028 | } |
| 2029 | +/***********************************************************************//** | ||
| 2030 | + * @brief Extract mtype from XML request | ||
| 2031 | + * | ||
| 2032 | + * @param[in] xml XML message sent by client. | ||
| 2033 | + * | ||
| 2034 | + * Extracts the mtype identifying calling message from the XML request. | ||
| 2035 | + ***************************************************************************/ | ||
| 2036 | +std::string GVOHub::get_mtype(const GXml& xml) const | ||
| 2037 | +{ | ||
| 2038 | + // Header | ||
| 2039 | + #if defined(G_CONSOLE_DUMP) | ||
| 2040 | + std::cout << "GVOHub::get_mtype" << std::endl; | ||
| 2041 | + #endif | ||
| 2042 | + | ||
| 2043 | + // Initialise response | ||
| 2044 | + std::string client_key = ""; | ||
| 2045 | + | ||
| 2046 | + // Get the client's private key | ||
| 2047 | + const GXmlNode* node = xml.element("methodCall > params > param > value"); | ||
| 2048 | + if (node != NULL) { | ||
| 2049 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 2050 | + if (text != NULL) { | ||
| 2051 | + client_key = text->text(); | ||
| 2052 | + } | ||
| 2053 | + } | ||
| 2054 | + | ||
| 2055 | + // Return key | ||
| 2056 | + return client_key; | ||
| 2057 | +} | ||
| 2058 | +/***********************************************************************//** | ||
| 2059 | + * @brief Extract client destination from XML request | ||
| 2060 | + * | ||
| 2061 | + * @param[in] xml XML message sent by client. | ||
| 2062 | + * | ||
| 2063 | + * Extracts identifier of destination client from the XML request. | ||
| 2064 | + ***************************************************************************/ | ||
| 2065 | +std::string GVOHub::get_destination(const GXml& xml) const | ||
| 2066 | +{ | ||
| 2067 | + // Header | ||
| 2068 | + #if defined(G_CONSOLE_DUMP) | ||
| 2069 | + std::cout << "GVOHub::get_mtype" << std::endl; | ||
| 2070 | + #endif | ||
| 1950 | 2071 | ||
| 2072 | + // Initialise response | ||
| 2073 | + std::string client_key = ""; | ||
| 2074 | + | ||
| 2075 | + // Get the client's private key | ||
| 2076 | + const GXmlNode* node = xml.element("methodCall > params > param > value"); | ||
| 2077 | + if (node != NULL) { | ||
| 2078 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 2079 | + if (text != NULL) { | ||
| 2080 | + client_key = text->text(); | ||
| 2081 | + } | ||
| 2082 | + } | ||
| 2083 | + | ||
| 2084 | + // Return key | ||
| 2085 | + return client_key; | ||
| 2086 | +} |
src/vo/GVOHub.cpp~
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOHub.cpp - VO SAMP Hub class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2014-2015 by Thierry Louge * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOHub.cpp | ||
| 23 | + * @brief VO SAMP Hub class implementation | ||
| 24 | + * @author Thierry Louge | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#endif | ||
| 31 | +#include <cstdlib> // std::getenv() function | ||
| 32 | +#include <cstdio> // std::fopen(), etc. functions | ||
| 33 | +#include <cstring> // std::memset() function | ||
| 34 | +#include <csignal> // signal() function | ||
| 35 | +#include <cerrno> // errno | ||
| 36 | +#include <unistd.h> // close() function | ||
| 37 | +#include <netdb.h> // getaddrinfo() function | ||
| 38 | +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons | ||
| 39 | +#include <fstream> | ||
| 40 | +#include <sys/shm.h> | ||
| 41 | +#include <sys/socket.h> // socket(), connect() functions | ||
| 42 | +#include <sys/wait.h> // waitpid() function | ||
| 43 | +#include <arpa/inet.h> // inet_addr() function | ||
| 44 | +#include "GVOHub.hpp" | ||
| 45 | +#include "GException.hpp" | ||
| 46 | +#include "GTools.hpp" | ||
| 47 | + | ||
| 48 | +/* __ Method name definitions ____________________________________________ */ | ||
| 49 | +#define G_START_HUB "GVOHub::start_hub()" | ||
| 50 | + | ||
| 51 | +/* __ Macros _____________________________________________________________ */ | ||
| 52 | + | ||
| 53 | +/* __ Coding definitions _________________________________________________ */ | ||
| 54 | + | ||
| 55 | +/* __ Debug definitions __________________________________________________ */ | ||
| 56 | +//#define G_CONSOLE_DUMP | ||
| 57 | +#define G_SHOW_MESSAGE | ||
| 58 | + | ||
| 59 | + | ||
| 60 | +/*========================================================================== | ||
| 61 | + = = | ||
| 62 | + = Constructors/destructors = | ||
| 63 | + = = | ||
| 64 | + ==========================================================================*/ | ||
| 65 | + | ||
| 66 | +/***********************************************************************//** | ||
| 67 | + * @brief Void constructor | ||
| 68 | + ***************************************************************************/ | ||
| 69 | +GVOHub::GVOHub(void) | ||
| 70 | +{ | ||
| 71 | + // Initialise members | ||
| 72 | + init_members(); | ||
| 73 | + | ||
| 74 | + // Return | ||
| 75 | + return; | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | + | ||
| 79 | +/***********************************************************************//** | ||
| 80 | + * @brief Copy constructor | ||
| 81 | + * | ||
| 82 | + * @param[in] hub VO Hub. | ||
| 83 | + ***************************************************************************/ | ||
| 84 | +GVOHub::GVOHub(const GVOHub& hub) | ||
| 85 | +{ | ||
| 86 | + // Initialise members | ||
| 87 | + init_members(); | ||
| 88 | + | ||
| 89 | + // Copy members | ||
| 90 | + copy_members(hub); | ||
| 91 | + | ||
| 92 | + // Return | ||
| 93 | + return; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | + | ||
| 97 | +/***********************************************************************//** | ||
| 98 | + * @brief Destructor | ||
| 99 | + ***************************************************************************/ | ||
| 100 | +GVOHub::~GVOHub(void) | ||
| 101 | +{ | ||
| 102 | + // Free members | ||
| 103 | + free_members(); | ||
| 104 | + | ||
| 105 | + // Return | ||
| 106 | + return; | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | + | ||
| 110 | +/*========================================================================== | ||
| 111 | + = = | ||
| 112 | + = Operators = | ||
| 113 | + = = | ||
| 114 | + ==========================================================================*/ | ||
| 115 | + | ||
| 116 | +/***********************************************************************//** | ||
| 117 | + * @brief Assignment operator | ||
| 118 | + * | ||
| 119 | + * @param[in] hub VO hub. | ||
| 120 | + * @return VO hub. | ||
| 121 | + ***************************************************************************/ | ||
| 122 | +GVOHub& GVOHub::operator=(const GVOHub& hub) | ||
| 123 | +{ | ||
| 124 | + // Execute only if object is not identical | ||
| 125 | + if (this != &hub) { | ||
| 126 | + | ||
| 127 | + // Free members | ||
| 128 | + free_members(); | ||
| 129 | + | ||
| 130 | + // Initialise members | ||
| 131 | + init_members(); | ||
| 132 | + | ||
| 133 | + // Copy members | ||
| 134 | + copy_members(hub); | ||
| 135 | + | ||
| 136 | + } // endif: object was not identical | ||
| 137 | + | ||
| 138 | + // Return | ||
| 139 | + return *this; | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | + | ||
| 143 | +/*========================================================================== | ||
| 144 | + = = | ||
| 145 | + = Public methods = | ||
| 146 | + = = | ||
| 147 | + ==========================================================================*/ | ||
| 148 | + | ||
| 149 | +/***********************************************************************//** | ||
| 150 | + * @brief Clear object. | ||
| 151 | + * | ||
| 152 | + * Reset object to a clean initial state. | ||
| 153 | + ***************************************************************************/ | ||
| 154 | +void GVOHub::clear(void) | ||
| 155 | +{ | ||
| 156 | + // Free members | ||
| 157 | + free_members(); | ||
| 158 | + | ||
| 159 | + // Initialise members | ||
| 160 | + init_members(); | ||
| 161 | + | ||
| 162 | + // Return | ||
| 163 | + return; | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | + | ||
| 167 | +/***********************************************************************//** | ||
| 168 | + * @brief Clone object | ||
| 169 | + ***************************************************************************/ | ||
| 170 | +GVOHub* GVOHub::clone(void) const | ||
| 171 | +{ | ||
| 172 | + // Clone client | ||
| 173 | + return new GVOHub(*this); | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | + | ||
| 177 | +/***********************************************************************//** | ||
| 178 | + * @brief Start Hub | ||
| 179 | + ***************************************************************************/ | ||
| 180 | +void GVOHub::start(void) | ||
| 181 | +{ | ||
| 182 | + // Create SAMP file | ||
| 183 | + create_samp_file(); | ||
| 184 | + | ||
| 185 | + // Start Hub | ||
| 186 | + start_hub(); | ||
| 187 | + | ||
| 188 | + // Return | ||
| 189 | + return; | ||
| 190 | +} | ||
| 191 | + | ||
| 192 | + | ||
| 193 | +/***********************************************************************//** | ||
| 194 | + * @brief Print VO hub information | ||
| 195 | + * | ||
| 196 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 197 | + * @return String containing VO hub information | ||
| 198 | + ***************************************************************************/ | ||
| 199 | +std::string GVOHub::print(const GChatter& chatter) const | ||
| 200 | +{ | ||
| 201 | + // Initialise result string | ||
| 202 | + std::string result; | ||
| 203 | + | ||
| 204 | + // Continue only if chatter is not silent | ||
| 205 | + if (chatter != SILENT) { | ||
| 206 | + | ||
| 207 | + // Append header | ||
| 208 | + result.append("=== GVOHub ==="); | ||
| 209 | + | ||
| 210 | + // Append Hub information | ||
| 211 | + result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id); | ||
| 212 | + result.append("\n"+gammalib::parformat("Hub key")+m_secret); | ||
| 213 | + result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url); | ||
| 214 | + result.append("\n"+gammalib::parformat("Hub host")+m_hub_host); | ||
| 215 | + result.append("\n"+gammalib::parformat("Hub port")+m_hub_port); | ||
| 216 | + result.append("\n"+gammalib::parformat("Hub path")+m_hub_path); | ||
| 217 | + result.append("\n"+gammalib::parformat("SAMP protocol version")); | ||
| 218 | + result.append(m_version); | ||
| 219 | + | ||
| 220 | + } // endif: chatter was not silent | ||
| 221 | + | ||
| 222 | + // Return result | ||
| 223 | + return result; | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | + | ||
| 227 | +/*========================================================================== | ||
| 228 | + = = | ||
| 229 | + = Private methods = | ||
| 230 | + = = | ||
| 231 | + ==========================================================================*/ | ||
| 232 | + | ||
| 233 | +/***********************************************************************//** | ||
| 234 | + * @brief Initialise class members | ||
| 235 | + ***************************************************************************/ | ||
| 236 | +void GVOHub::init_members(void) | ||
| 237 | +{ | ||
| 238 | + // Initialise members | ||
| 239 | + m_secret = random_string(15); | ||
| 240 | + m_hub_host = "127.0.0.1"; | ||
| 241 | + m_hub_port = "2526"; | ||
| 242 | + m_hub_path = "xmlrpc"; | ||
| 243 | + m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path; | ||
| 244 | + m_version = "1.3"; | ||
| 245 | + m_hub_id = "gammalib_hub"; | ||
| 246 | + m_socket = -1; // Signals no socket | ||
| 247 | + m_shutdown = false; | ||
| 248 | + m_clients.clear(); | ||
| 249 | + | ||
| 250 | + // Return | ||
| 251 | + return; | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | + | ||
| 255 | +/***********************************************************************//** | ||
| 256 | + * @brief Copy class members | ||
| 257 | + * | ||
| 258 | + * @param[in] hub VO hub. | ||
| 259 | + ***************************************************************************/ | ||
| 260 | +void GVOHub::copy_members(const GVOHub& hub) | ||
| 261 | +{ | ||
| 262 | + // Copy members | ||
| 263 | + m_secret = hub.m_secret; | ||
| 264 | + m_hub_url = hub.m_hub_url; | ||
| 265 | + m_hub_host = hub.m_hub_host; | ||
| 266 | + m_hub_port = hub.m_hub_port; | ||
| 267 | + m_hub_path = hub.m_hub_path; | ||
| 268 | + m_version = hub.m_version; | ||
| 269 | + m_hub_id = hub.m_hub_id; | ||
| 270 | + m_socket = hub.m_socket; | ||
| 271 | + m_shutdown = hub.m_shutdown; | ||
| 272 | + m_clients = hub.m_clients; | ||
| 273 | + | ||
| 274 | + // Return | ||
| 275 | + return; | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | + | ||
| 279 | +/***********************************************************************//** | ||
| 280 | + * @brief Delete class members | ||
| 281 | + ***************************************************************************/ | ||
| 282 | +void GVOHub::free_members(void) | ||
| 283 | +{ | ||
| 284 | + // Close sockets | ||
| 285 | + if (m_socket != -1) { | ||
| 286 | + close(m_socket); | ||
| 287 | + m_socket = -1; | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + // Remove lockfile | ||
| 291 | + std::string lockurl = get_hub_lockfile(); | ||
| 292 | + std::remove(lockurl.c_str()); | ||
| 293 | + | ||
| 294 | + // Return | ||
| 295 | + return; | ||
| 296 | +} | ||
| 297 | + | ||
| 298 | + | ||
| 299 | +/***********************************************************************//** | ||
| 300 | + * @brief Starts the SAMP hub socket and listens on it | ||
| 301 | + * | ||
| 302 | + * @exception GException::runtime_error | ||
| 303 | + * Problem with creating of or listening on socket | ||
| 304 | + * | ||
| 305 | + * This is the main Hub event loop. | ||
| 306 | + ***************************************************************************/ | ||
| 307 | +void GVOHub::start_hub(void) | ||
| 308 | +{ | ||
| 309 | + // Prepare TCP/IP structure | ||
| 310 | + struct sockaddr_in serv_addr; | ||
| 311 | + std::memset(&serv_addr, 0, sizeof(serv_addr)); | ||
| 312 | + serv_addr.sin_family = AF_INET; | ||
| 313 | + serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str()); | ||
| 314 | + serv_addr.sin_port = htons(gammalib::toint(m_hub_port)); | ||
| 315 | + | ||
| 316 | + // Create Hub socket | ||
| 317 | + m_socket = socket(AF_INET, SOCK_STREAM, 0); | ||
| 318 | + | ||
| 319 | + // Creation of hub main socket | ||
| 320 | + if (m_socket < 0) { | ||
| 321 | + std::string msg = "Unable to create Hub socket. Errno="+ | ||
| 322 | + gammalib::str(errno); | ||
| 323 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + // Set hub main socket to allow multiple connections | ||
| 327 | + int opt = 1; | ||
| 328 | + if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) { | ||
| 329 | + std::string msg = "Unable to set Hub socket to multiple connections." | ||
| 330 | + " Errno="+gammalib::str(errno); | ||
| 331 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 332 | + } | ||
| 333 | + #ifdef SO_REUSEPORT | ||
| 334 | + if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) { | ||
| 335 | + std::string msg = "Unable to set Hub socket to multiple connections." | ||
| 336 | + " Errno="+gammalib::str(errno); | ||
| 337 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 338 | + } | ||
| 339 | + #endif | ||
| 340 | + | ||
| 341 | + // Server socket is opened. Now, bind it to the port, with family etc. | ||
| 342 | + if (bind(m_socket, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { | ||
| 343 | + std::string msg = "Unable to bind Hub socket to server socket. Errno="+ | ||
| 344 | + gammalib::str(errno); | ||
| 345 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 346 | + } | ||
| 347 | + | ||
| 348 | + // Now start listening for the clients: 5 requests simultaneously pending | ||
| 349 | + // at maximum | ||
| 350 | + if (listen(m_socket, 5) < 0) { | ||
| 351 | + std::string msg = "Unable to start listening on Hub socket. Errno="+ | ||
| 352 | + gammalib::str(errno); | ||
| 353 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + // ... | ||
| 357 | + struct sockaddr_in cli_addr; | ||
| 358 | + socklen_t clilen = sizeof(cli_addr); | ||
| 359 | + | ||
| 360 | + // Main event handling loop | ||
| 361 | + while (1) { | ||
| 362 | + | ||
| 363 | + // Accept connection from the client | ||
| 364 | + socklen_t socket = accept(m_socket, (struct sockaddr *)&cli_addr, &clilen); | ||
| 365 | + if (socket < 0) { | ||
| 366 | + std::string msg = "Client connection to socket not accepted."; | ||
| 367 | + throw GException::runtime_error(G_START_HUB, msg); | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + // Handle request | ||
| 371 | + handle_request(socket); | ||
| 372 | + | ||
| 373 | + // Close socket | ||
| 374 | + close(socket); | ||
| 375 | + | ||
| 376 | + // If we have received a shutdown request then exit the event | ||
| 377 | + // loop | ||
| 378 | + if (m_shutdown) { | ||
| 379 | + break; | ||
| 380 | + } | ||
| 381 | + | ||
| 382 | + } // endwhile: main event loop | ||
| 383 | + | ||
| 384 | + // Close socket | ||
| 385 | + close(m_socket); | ||
| 386 | + m_socket = -1; | ||
| 387 | + | ||
| 388 | + // Return | ||
| 389 | + return; | ||
| 390 | +} | ||
| 391 | + | ||
| 392 | + | ||
| 393 | +/***********************************************************************//** | ||
| 394 | + * @brief Reads the client message and runs appropriate function | ||
| 395 | + * | ||
| 396 | + * @param[in] sock Socket to client. | ||
| 397 | + ***************************************************************************/ | ||
| 398 | +void GVOHub::handle_request(const socklen_t& sock) | ||
| 399 | +{ | ||
| 400 | + // Header | ||
| 401 | + #if defined(G_CONSOLE_DUMP) | ||
| 402 | + std::cout << "GVOHub::handle_request" << std::endl; | ||
| 403 | + #endif | ||
| 404 | + | ||
| 405 | + // Initialize buffer | ||
| 406 | + char buffer[1001]; | ||
| 407 | + | ||
| 408 | + // Initialise message | ||
| 409 | + std::string message = ""; | ||
| 410 | + | ||
| 411 | + // Read from socket until nothing is received anymore. | ||
| 412 | + int timeout = 2000; // Initial timeout is 2 sec | ||
| 413 | + int n = 0; | ||
| 414 | + do { | ||
| 415 | + n = gammalib::recv(sock, buffer, 1000, 0, timeout); | ||
| 416 | + if (n > 0) { | ||
| 417 | + buffer[n] = '\0'; | ||
| 418 | + message.append(std::string(buffer)); | ||
| 419 | + } | ||
| 420 | + timeout = 10; // The timeout now is 0.01 sec | ||
| 421 | + } while (n > 0); | ||
| 422 | + | ||
| 423 | + // Dump the buffer | ||
| 424 | + #if defined(G_SHOW_MESSAGE) | ||
| 425 | + std::cout << std::endl; | ||
| 426 | + std::cout << "GVOHub has received the following message:" << std::endl; | ||
| 427 | + std::cout << "==========================================" << std::endl; | ||
| 428 | + std::cout << message << std::endl; | ||
| 429 | + #endif | ||
| 430 | + | ||
| 431 | + // Extract response into an XML object | ||
| 432 | + GXml xml; | ||
| 433 | + size_t start = message.find("<?xml"); | ||
| 434 | + if (start != std::string::npos) { | ||
| 435 | + xml = GXml(message.substr(start, std::string::npos)); | ||
| 436 | + } | ||
| 437 | + | ||
| 438 | + // Get methodName value | ||
| 439 | + std::string method_called; | ||
| 440 | + const GXmlNode* node = xml.element("methodCall > methodName"); | ||
| 441 | + if (node != NULL) { | ||
| 442 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 443 | + if (text != NULL) { | ||
| 444 | + method_called = text->text(); | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + // Dump the buffer | ||
| 449 | + #if defined(G_CONSOLE_DUMP) | ||
| 450 | + std::cout << "Method called: " << method_called << std::endl; | ||
| 451 | + #endif | ||
| 452 | + | ||
| 453 | + // Dispatch according to method | ||
| 454 | + if (method_called.compare("samp.hub.ping") == 0) { | ||
| 455 | + request_ping(sock); | ||
| 456 | + } | ||
| 457 | + else if (method_called.compare("samp.hub.register") == 0) { | ||
| 458 | + request_register(xml, sock); | ||
| 459 | + } | ||
| 460 | + else if (method_called.compare("samp.hub.unregister") == 0) { | ||
| 461 | + request_unregister(xml, sock); | ||
| 462 | + } | ||
| 463 | + else if (method_called.compare("samp.hub.declareMetadata") == 0) { | ||
| 464 | + request_declare_metadata(xml, sock); | ||
| 465 | + } | ||
| 466 | + else if (method_called.compare("samp.hub.declareSubscriptions") == 0) { | ||
| 467 | + request_declare_subscriptions(xml, sock); | ||
| 468 | + } | ||
| 469 | + else if (method_called.compare("samp.hub.setXmlrpcCallback") == 0) { | ||
| 470 | + request_set_xml_rpc_callback(xml, sock); | ||
| 471 | + } | ||
| 472 | + else if (method_called.compare("samp.hub.getSubscriptions") == 0) { | ||
| 473 | + request_get_subscriptions(xml, sock); | ||
| 474 | + } | ||
| 475 | + else if (method_called.compare("samp.hub.getRegisteredClients") == 0) { | ||
| 476 | + request_get_registered_clients(xml, sock); | ||
| 477 | + } | ||
| 478 | + else if (method_called.compare("samp.hub.getSubscribedClients") == 0) { | ||
| 479 | + request_get_subscribed_clients(xml, sock); | ||
| 480 | + } | ||
| 481 | + else if (method_called.compare("samp.hub.getMetadata") == 0) { | ||
| 482 | + request_get_metadata(xml, sock); | ||
| 483 | + } | ||
| 484 | + else if (method_called.compare("samp.hub.notify") == 0) { | ||
| 485 | + request_ping(sock); | ||
| 486 | + } | ||
| 487 | + else if (method_called.compare("samp.hub.notifyAll") == 0) { | ||
| 488 | + request_ping(sock); | ||
| 489 | + } | ||
| 490 | + else if (method_called.compare("samp.hub.call") == 0) { | ||
| 491 | + request_call(xml,sock); | ||
| 492 | + } | ||
| 493 | + else if (method_called.compare("samp.hub.callAll") == 0) { | ||
| 494 | + request_ping(sock); | ||
| 495 | + } | ||
| 496 | + else if (method_called.compare("samp.hub.callAndWait") == 0) { | ||
| 497 | + request_ping(sock); | ||
| 498 | + } | ||
| 499 | + else if (method_called.compare("samp.hub.reply") == 0) { | ||
| 500 | + request_ping(sock); | ||
| 501 | + } | ||
| 502 | + else if (method_called.compare("samp.hub.shutdown") == 0) { | ||
| 503 | + request_shutdown(sock); | ||
| 504 | + } | ||
| 505 | + | ||
| 506 | + // Return | ||
| 507 | + return; | ||
| 508 | +} | ||
| 509 | + | ||
| 510 | + | ||
| 511 | +/***********************************************************************//** | ||
| 512 | + * @brief Handles ping requests | ||
| 513 | + * | ||
| 514 | + * @param[in] sock Socket. | ||
| 515 | + * | ||
| 516 | + * Handles all incoming ping requests. | ||
| 517 | + ***************************************************************************/ | ||
| 518 | +void GVOHub::request_ping(const socklen_t& sock) | ||
| 519 | +{ | ||
| 520 | + // Header | ||
| 521 | + #if defined(G_CONSOLE_DUMP) | ||
| 522 | + std::cout << "GVOHub::request_ping" << std::endl; | ||
| 523 | + #endif | ||
| 524 | + | ||
| 525 | + // Post void message | ||
| 526 | + post_samp_void(sock); | ||
| 527 | + | ||
| 528 | + // Return | ||
| 529 | + return; | ||
| 530 | +} | ||
| 531 | + | ||
| 532 | + | ||
| 533 | +/***********************************************************************//** | ||
| 534 | + * @brief Handles registration requests | ||
| 535 | + * | ||
| 536 | + * @param[in] xml XML message sent by client. | ||
| 537 | + * @param[in] sock Socket. | ||
| 538 | + * | ||
| 539 | + * Handles all incoming registration requests. | ||
| 540 | + ***************************************************************************/ | ||
| 541 | +void GVOHub::request_register(const GXml& xml, const socklen_t& sock) | ||
| 542 | +{ | ||
| 543 | + // Header | ||
| 544 | + #if defined(G_CONSOLE_DUMP) | ||
| 545 | + std::cout << "GVOHub::request_register" << std::endl; | ||
| 546 | + #endif | ||
| 547 | + | ||
| 548 | + // Set client reference | ||
| 549 | + int counter = 0; | ||
| 550 | + std::string reference; | ||
| 551 | + do { | ||
| 552 | + reference = "c"+gammalib::str(counter); | ||
| 553 | + int i = 0; | ||
| 554 | + for (; i < m_clients.size(); ++i) { | ||
| 555 | + if (m_clients[i].reference == reference) { | ||
| 556 | + counter++; | ||
| 557 | + break; | ||
| 558 | + } | ||
| 559 | + } | ||
| 560 | + if (i >= m_clients.size()) { | ||
| 561 | + break; | ||
| 562 | + } | ||
| 563 | + } while (true); | ||
| 564 | + | ||
| 565 | + // Create a new client | ||
| 566 | + struct client voclient; | ||
| 567 | + voclient.reference = reference; | ||
| 568 | + voclient.private_key = random_string(15); | ||
| 569 | + | ||
| 570 | + // Attached client | ||
| 571 | + m_clients.push_back(voclient); | ||
| 572 | + | ||
| 573 | + // Declare response | ||
| 574 | + std::string response = ""; | ||
| 575 | + | ||
| 576 | + // Set response | ||
| 577 | + response.append("<?xml version='1.0' encoding='UTF-8'?>\n"); | ||
| 578 | + response.append("<methodResponse>\n"); | ||
| 579 | + response.append("<params>\n"); | ||
| 580 | + response.append(" <param><value><struct>\n"); | ||
| 581 | + response.append(" <member>\n"); | ||
| 582 | + response.append(" <name>samp.private-key</name>\n"); | ||
| 583 | + response.append(" <value>"+voclient.private_key+"</value>\n"); | ||
| 584 | + response.append(" </member>\n"); | ||
| 585 | + response.append(" <member>\n"); | ||
| 586 | + response.append(" <name>samp.hub-id</name>\n"); | ||
| 587 | + response.append(" <value>"+m_hub_id+"</value>\n"); | ||
| 588 | + response.append(" </member>\n"); | ||
| 589 | + response.append(" <member>\n"); | ||
| 590 | + response.append(" <name>samp.self-id</name>\n"); | ||
| 591 | + response.append(" <value>"+voclient.reference+"</value>\n"); | ||
| 592 | + response.append(" </member>\n"); | ||
| 593 | + response.append(" <member>\n"); | ||
| 594 | + response.append(" <name>samp.status</name>\n"); | ||
| 595 | + response.append(" <value>samp.ok</value>\n"); | ||
| 596 | + response.append(" </member>\n"); | ||
| 597 | + response.append(" <member>\n"); | ||
| 598 | + response.append(" <name>samp.url-translator</name>\n"); | ||
| 599 | + response.append(" <value>"+m_hub_url+"</value>\n"); | ||
| 600 | + response.append(" </member>\n"); | ||
| 601 | + response.append(" </struct></value></param>\n"); | ||
| 602 | + response.append("</params>\n"); | ||
| 603 | + response.append("</methodResponse>\n"); | ||
| 604 | + | ||
| 605 | + // Post response | ||
| 606 | + post_string(response, sock); | ||
| 607 | + | ||
| 608 | + // Send notifications | ||
| 609 | + send_notifications("samp.hub.event.register", voclient.reference); | ||
| 610 | + | ||
| 611 | + //Return | ||
| 612 | + return; | ||
| 613 | +} | ||
| 614 | + | ||
| 615 | + | ||
| 616 | +/***********************************************************************//** | ||
| 617 | + * @brief Handles unregistration requests | ||
| 618 | + * | ||
| 619 | + * @param[in] xml XML message sent by client. | ||
| 620 | + * @param[in] sock Socket. | ||
| 621 | + * | ||
| 622 | + * Handles all incoming unregistration requests. | ||
| 623 | + ***************************************************************************/ | ||
| 624 | +void GVOHub::request_unregister(const GXml& xml, const socklen_t& sock) | ||
| 625 | +{ | ||
| 626 | + // Optionally dump header | ||
| 627 | + #if defined(G_CONSOLE_DUMP) | ||
| 628 | + std::cout << "GVOHub::request_unregister" << std::endl; | ||
| 629 | + #endif | ||
| 630 | + | ||
| 631 | + // Get client index | ||
| 632 | + int i = get_client_index(xml); | ||
| 633 | + | ||
| 634 | + // Continue only if index is valid | ||
| 635 | + if (i != -1) { | ||
| 636 | + | ||
| 637 | + // Post void message | ||
| 638 | + post_samp_void(sock); | ||
| 639 | + | ||
| 640 | + // Send notifications | ||
| 641 | + send_notifications("samp.hub.event.unregister", | ||
| 642 | + m_clients[i].reference); | ||
| 643 | + | ||
| 644 | + // Remove client | ||
| 645 | + m_clients.erase(m_clients.begin()+i); | ||
| 646 | + | ||
| 647 | + } // endif: valid client found | ||
| 648 | + | ||
| 649 | + // Signal if the client was unknown | ||
| 650 | + #if defined(G_CONSOLE_DUMP) | ||
| 651 | + else { | ||
| 652 | + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; | ||
| 653 | + } | ||
| 654 | + #endif | ||
| 655 | + | ||
| 656 | + // Return | ||
| 657 | + return; | ||
| 658 | +} | ||
| 659 | + | ||
| 660 | + | ||
| 661 | +/***********************************************************************//** | ||
| 662 | + * @brief Handles metadata declaration requests | ||
| 663 | + * | ||
| 664 | + * @param[in] xml XML message sent by client. | ||
| 665 | + * @param[in] sock Socket. | ||
| 666 | + * | ||
| 667 | + * Handles all incoming metadata declaration requests. | ||
| 668 | + ***************************************************************************/ | ||
| 669 | +void GVOHub::request_declare_metadata(const GXml& xml, const socklen_t& sock) | ||
| 670 | +{ | ||
| 671 | + // Header | ||
| 672 | + #if defined(G_CONSOLE_DUMP) | ||
| 673 | + std::cout << "GVOHub::request_declare_metadata" << std::endl; | ||
| 674 | + #endif | ||
| 675 | + | ||
| 676 | + // Get client index | ||
| 677 | + int i = get_client_index(xml); | ||
| 678 | + | ||
| 679 | + // Continue only if index is valid | ||
| 680 | + if (i != -1) { | ||
| 681 | + | ||
| 682 | + // Store metadata | ||
| 683 | + m_clients[i].name = get_response_value(xml, "samp.name");; | ||
| 684 | + m_clients[i].description = get_response_value(xml, "samp.description.text"); | ||
| 685 | + m_clients[i].icon = get_response_value(xml, "samp.icon.url"); | ||
| 686 | + m_clients[i].documentation = get_response_value(xml, "samp.documentation.url"); | ||
| 687 | + m_clients[i].affiliation = get_response_value(xml, "author.affiliation"); | ||
| 688 | + m_clients[i].email = get_response_value(xml, "author.email"); | ||
| 689 | + m_clients[i].author_name = get_response_value(xml, "author.name"); | ||
| 690 | + m_clients[i].homepage = get_response_value(xml, "home.page"); | ||
| 691 | + | ||
| 692 | + // Post void message | ||
| 693 | + post_samp_void(sock); | ||
| 694 | + | ||
| 695 | + // Send notifications | ||
| 696 | + send_notifications("samp.hub.event.metadata", m_clients[i].reference); | ||
| 697 | + | ||
| 698 | + } // endif: client found | ||
| 699 | + | ||
| 700 | + // Signal if the client was unknown | ||
| 701 | + #if defined(G_CONSOLE_DUMP) | ||
| 702 | + else { | ||
| 703 | + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; | ||
| 704 | + } | ||
| 705 | + #endif | ||
| 706 | + | ||
| 707 | + // Return | ||
| 708 | + return; | ||
| 709 | +} | ||
| 710 | + | ||
| 711 | + | ||
| 712 | +/***********************************************************************//** | ||
| 713 | + * @brief Handles subscriptions declaration requests | ||
| 714 | + * | ||
| 715 | + * @param[in] xml XML message sent by client. | ||
| 716 | + * @param[in] sock Socket. | ||
| 717 | + * | ||
| 718 | + * Handles all incoming subscription declaration requests. | ||
| 719 | + ***************************************************************************/ | ||
| 720 | +void GVOHub::request_declare_subscriptions(const GXml& xml,const socklen_t& sock) | ||
| 721 | +{ | ||
| 722 | + // Header | ||
| 723 | + #if defined(G_CONSOLE_DUMP) | ||
| 724 | + std::cout << "GVOHub::request_declare_subscriptions" << std::endl; | ||
| 725 | + #endif | ||
| 726 | + | ||
| 727 | + // Get client index | ||
| 728 | + int i = get_client_index(xml); | ||
| 729 | + | ||
| 730 | + // Continue only if index is valid | ||
| 731 | + if (i != -1) { | ||
| 732 | + | ||
| 733 | + // Get subscriptions | ||
| 734 | + std::vector<std::string> subscriptions = get_subscriptions(xml); | ||
| 735 | + | ||
| 736 | + // Store subscriptions | ||
| 737 | + for (int k = 0; k < subscriptions.size(); ++k) { | ||
| 738 | + m_clients[i].subscriptions.push_back(subscriptions[k]); | ||
| 739 | + } | ||
| 740 | + | ||
| 741 | + // Post SAMP ok | ||
| 742 | + post_samp_ok(sock); | ||
| 743 | + | ||
| 744 | + } // endif: valid client found | ||
| 745 | + | ||
| 746 | + // Signal if the client was unknown | ||
| 747 | + #if defined(G_CONSOLE_DUMP) | ||
| 748 | + else { | ||
| 749 | + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; | ||
| 750 | + } | ||
| 751 | + #endif | ||
| 752 | + | ||
| 753 | + //Return | ||
| 754 | + return; | ||
| 755 | +} | ||
| 756 | + | ||
| 757 | + | ||
| 758 | +/***********************************************************************//** | ||
| 759 | + * @brief Handles XML-RPC callback setting requests | ||
| 760 | + * | ||
| 761 | + * @param[in] xml XML message sent by client. | ||
| 762 | + * @param[in] sock Socket. | ||
| 763 | + * | ||
| 764 | + * Handles all incoming XML-RPC callback setting requests. | ||
| 765 | + ***************************************************************************/ | ||
| 766 | +void GVOHub::request_set_xml_rpc_callback(const GXml& xml, | ||
| 767 | + const socklen_t& sock) | ||
| 768 | +{ | ||
| 769 | + // Header | ||
| 770 | + #if defined(G_CONSOLE_DUMP) | ||
| 771 | + std::cout << "GVOHub::request_set_xml_rpc_callback" << std::endl; | ||
| 772 | + #endif | ||
| 773 | + | ||
| 774 | + // Get client index | ||
| 775 | + int i = get_client_index(xml); | ||
| 776 | + | ||
| 777 | + // Continue only if index is valid | ||
| 778 | + if (i != -1) { | ||
| 779 | + | ||
| 780 | + // Get callback URL | ||
| 781 | + std::string client_url = get_callback_url(xml); | ||
| 782 | + | ||
| 783 | + // Set callback URL | ||
| 784 | + m_clients[i].url = get_callback_url(xml); | ||
| 785 | + | ||
| 786 | + // Post SAMP ok | ||
| 787 | + post_samp_ok(sock); | ||
| 788 | + | ||
| 789 | + } // endif: client found | ||
| 790 | + | ||
| 791 | + // Signal if the client was unknown | ||
| 792 | + #if defined(G_CONSOLE_DUMP) | ||
| 793 | + else { | ||
| 794 | + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; | ||
| 795 | + } | ||
| 796 | + #endif | ||
| 797 | + | ||
| 798 | + // Return | ||
| 799 | + return; | ||
| 800 | +} | ||
| 801 | + | ||
| 802 | + | ||
| 803 | +/***********************************************************************//** | ||
| 804 | + * @brief Handles subscriptions getting requests | ||
| 805 | + * | ||
| 806 | + * @param[in] xml XML message sent by client. | ||
| 807 | + * @param[in] sock Socket. | ||
| 808 | + * | ||
| 809 | + * Handles all incoming subscriptions getting requests. | ||
| 810 | + ***************************************************************************/ | ||
| 811 | +void GVOHub::request_get_subscriptions(const GXml& xml, const socklen_t& sock) | ||
| 812 | +{ | ||
| 813 | + // Header | ||
| 814 | + #if defined(G_CONSOLE_DUMP) | ||
| 815 | + std::cout << "GVOHub::request_get_subscriptions" << std::endl; | ||
| 816 | + #endif | ||
| 817 | + | ||
| 818 | + // Initialise client name | ||
| 819 | + std::string client_name = ""; | ||
| 820 | + | ||
| 821 | + // Get the client name | ||
| 822 | + const GXmlNode* node = xml.element("methodCall > params > param[1] > value"); | ||
| 823 | + if (node != NULL) { | ||
| 824 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 825 | + if (text != NULL) { | ||
| 826 | + client_name = text->text(); | ||
| 827 | + } | ||
| 828 | + } | ||
| 829 | + | ||
| 830 | + // Declare response | ||
| 831 | + std::string response = ""; | ||
| 832 | + | ||
| 833 | + // Set response | ||
| 834 | + response.append("<?xml version='1.0' encoding='UTF-8'?>\n"); | ||
| 835 | + response.append("<methodResponse>\n"); | ||
| 836 | + response.append("<params>\n"); | ||
| 837 | + response.append(" <param><value><struct>\n"); | ||
| 838 | + | ||
| 839 | + // If key is "gammalib_hub" then return some special information | ||
| 840 | + if (client_name == "gammalib_hub") { | ||
| 841 | + // Do nothing | ||
| 842 | + } | ||
| 843 | + | ||
| 844 | + // ... handle all other clients | ||
| 845 | + else { | ||
| 846 | + | ||
| 847 | + // Get client index | ||
| 848 | + int i = get_client_index(client_name); | ||
| 849 | + | ||
| 850 | + // Continue only if index is valid | ||
| 851 | + if (i != -1) { | ||
| 852 | + | ||
| 853 | + // Append all subscriptions | ||
| 854 | + for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) { | ||
| 855 | + response.append(" <member>\n"); | ||
| 856 | + response.append(" <name>"); | ||
| 857 | + response.append(m_clients[i].subscriptions[k]); | ||
| 858 | + response.append("</name>\n"); | ||
| 859 | + response.append(" <value></value>\n"); | ||
| 860 | + response.append(" </member>\n"); | ||
| 861 | + } | ||
| 862 | + | ||
| 863 | + } | ||
| 864 | + | ||
| 865 | + // Signal if the client was unknown | ||
| 866 | + #if defined(G_CONSOLE_DUMP) | ||
| 867 | + else { | ||
| 868 | + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; | ||
| 869 | + } | ||
| 870 | + #endif | ||
| 871 | + | ||
| 872 | + } | ||
| 873 | + | ||
| 874 | + // Finish response | ||
| 875 | + response.append(" </struct></value></param>\n"); | ||
| 876 | + response.append("</params>\n"); | ||
| 877 | + response.append("</methodResponse>\n"); | ||
| 878 | + | ||
| 879 | + // Post response | ||
| 880 | + post_string(response, sock); | ||
| 881 | + | ||
| 882 | + // Return | ||
| 883 | + return; | ||
| 884 | +} | ||
| 885 | + | ||
| 886 | + | ||
| 887 | +/***********************************************************************//** | ||
| 888 | + * @brief Handles registered client information requests | ||
| 889 | + * | ||
| 890 | + * @param[in] xml XML message sent by client. | ||
| 891 | + * @param[in] sock Socket. | ||
| 892 | + * | ||
| 893 | + * Handles all incoming registered client information requests. | ||
| 894 | + ***************************************************************************/ | ||
| 895 | +void GVOHub::request_get_registered_clients(const GXml& xml, const socklen_t& sock) | ||
| 896 | +{ | ||
| 897 | + // Header | ||
| 898 | + #if defined(G_CONSOLE_DUMP) | ||
| 899 | + std::cout << "GVOHub::request_get_registered_clients" << std::endl; | ||
| 900 | + #endif | ||
| 901 | + | ||
| 902 | + // Get client key | ||
| 903 | + std::string key = get_client_key(xml); | ||
| 904 | + | ||
| 905 | + // Declare message | ||
| 906 | + std::string msg = ""; | ||
| 907 | + // Set response | ||
| 908 | + msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); | ||
| 909 | + msg.append("<methodResponse>\n"); | ||
| 910 | + msg.append("<params>\n"); | ||
| 911 | + msg.append(" <param><value><array><data>\n"); | ||
| 912 | + msg.append(" <value>gammalib_hub</value>\n"); | ||
| 913 | + | ||
| 914 | + // Loop over all clients. Do not send back current client's registration | ||
| 915 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 916 | + if (m_clients[i].private_key != key) { | ||
| 917 | + msg.append(" <value>"); | ||
| 918 | + msg.append(m_clients[i].reference); | ||
| 919 | + msg.append("</value>\n"); | ||
| 920 | + } | ||
| 921 | + } | ||
| 922 | + | ||
| 923 | + // Finish response | ||
| 924 | + msg.append(" </data></array></value></param>\n"); | ||
| 925 | + msg.append("</params>\n"); | ||
| 926 | + msg.append("</methodResponse>\n"); | ||
| 927 | + // Post response | ||
| 928 | + post_string(msg, sock); | ||
| 929 | + | ||
| 930 | + // Return | ||
| 931 | + return; | ||
| 932 | + | ||
| 933 | +} | ||
| 934 | + | ||
| 935 | + | ||
| 936 | +/***********************************************************************//** | ||
| 937 | + * @brief Handles subscribed client information requests | ||
| 938 | + * | ||
| 939 | + * @param[in] xml XML message sent by client. | ||
| 940 | + * @param[in] sock Socket. | ||
| 941 | + * | ||
| 942 | + * Handles all incoming subscribed client information requests. | ||
| 943 | + ***************************************************************************/ | ||
| 944 | +void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& sock) | ||
| 945 | +{ | ||
| 946 | + // Header | ||
| 947 | + #if defined(G_CONSOLE_DUMP) | ||
| 948 | + std::cout << "GVOHub::request_get_subscribed_clients" << std::endl; | ||
| 949 | + #endif | ||
| 950 | + | ||
| 951 | + // Declare message | ||
| 952 | + std::string msg = ""; | ||
| 953 | + | ||
| 954 | + msg.append("<?xml version=\'1.0\' encoding=\"UTF-8\"?>\n"); | ||
| 955 | + msg.append("<methodResponse>\n"); | ||
| 956 | + msg.append("<params>\n"); | ||
| 957 | + msg.append(" <param><value><struct><member><name>c0</name><value><struct></struct></value></member><member><name>gammalib_hub</name><value><struct></struct></value></member></struct></value></param></params></methodResponse>"); | ||
| 958 | + | ||
| 959 | +/* | ||
| 960 | + std::string buffer; | ||
| 961 | + const int n = 1000; | ||
| 962 | + char line[n]; | ||
| 963 | + FILE* fptr = fopen("SAMP-registered.txt", "r"); | ||
| 964 | + if (fptr != NULL) { | ||
| 965 | + while (fgets(line, n, fptr) != NULL) { | ||
| 966 | + | ||
| 967 | + // Convert line to C++ string | ||
| 968 | + std::string cline = std::string(line); | ||
| 969 | + | ||
| 970 | + // Check for secret key | ||
| 971 | + if (cline.compare(0, 10, "Registered") == 0) { | ||
| 972 | + buffer = gammalib::strip_chars(cline.substr(10, std::string::npos), "\r\n"); | ||
| 973 | + } | ||
| 974 | + } | ||
| 975 | + | ||
| 976 | + // Closes file | ||
| 977 | + fclose(fptr); | ||
| 978 | +*/ | ||
| 979 | + | ||
| 980 | + // Post response | ||
| 981 | + post_string(msg, sock); | ||
| 982 | + // Post void message | ||
| 983 | + //post_samp_void(sock); | ||
| 984 | + | ||
| 985 | + // Return | ||
| 986 | + return; | ||
| 987 | +} | ||
| 988 | + | ||
| 989 | + | ||
| 990 | +/***********************************************************************//** | ||
| 991 | + * @brief Handles a metadata requests | ||
| 992 | + * | ||
| 993 | + * @param[in] xml XML message sent by client. | ||
| 994 | + * @param[in] sock Socket. | ||
| 995 | + * | ||
| 996 | + * Handles all metadata requests. | ||
| 997 | + ***************************************************************************/ | ||
| 998 | +void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock) | ||
| 999 | +{ | ||
| 1000 | + // Header | ||
| 1001 | + #if defined(G_CONSOLE_DUMP) | ||
| 1002 | + std::cout << "GVOHub::request_get_metadata" << std::endl; | ||
| 1003 | + #endif | ||
| 1004 | + | ||
| 1005 | + // Initialise client name | ||
| 1006 | + std::string client_name = ""; | ||
| 1007 | + | ||
| 1008 | + // Get the client name | ||
| 1009 | + const GXmlNode* node = xml.element("methodCall > params > param[1] > value"); | ||
| 1010 | + if (node != NULL) { | ||
| 1011 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 1012 | + if (text != NULL) { | ||
| 1013 | + client_name = text->text(); | ||
| 1014 | + } | ||
| 1015 | + } | ||
| 1016 | + | ||
| 1017 | + // Declare response | ||
| 1018 | + std::string response = ""; | ||
| 1019 | + | ||
| 1020 | + // Set response | ||
| 1021 | + response.append("<?xml version='1.0' encoding='UTF-8'?>\n"); | ||
| 1022 | + response.append("<methodResponse>\n"); | ||
| 1023 | + response.append("<params>\n"); | ||
| 1024 | + response.append(" <param><value><struct>\n"); | ||
| 1025 | + response.append(" <member>\n"); | ||
| 1026 | + response.append(" <name>samp.status</name>\n"); | ||
| 1027 | + response.append(" <value>samp.ok</value>\n"); | ||
| 1028 | + response.append(" </member>\n"); | ||
| 1029 | + | ||
| 1030 | + // If key is "gammalib_hub" then return some special information | ||
| 1031 | + if (client_name == "gammalib_hub") { | ||
| 1032 | + response.append(" <member>\n"); | ||
| 1033 | + response.append(" <name>samp.name</name>\n"); | ||
| 1034 | + response.append(" <value>gammalib_hub</value>\n"); | ||
| 1035 | + response.append(" </member>\n"); | ||
| 1036 | + response.append(" <member>\n"); | ||
| 1037 | + response.append(" <name>samp.description.text</name>\n"); | ||
| 1038 | + response.append(" <value>GammaLib VO Hub</value>\n"); | ||
| 1039 | + response.append(" </member>\n"); | ||
| 1040 | + response.append(" <member>\n"); | ||
| 1041 | + response.append(" <name>samp.icon.url</name>\n"); | ||
| 1042 | + response.append(" <value>http://a.fsdn.com/allura/p/gammalib/icon</value>\n"); | ||
| 1043 | + response.append(" </member>\n"); | ||
| 1044 | + response.append(" <member>\n"); | ||
| 1045 | + response.append(" <name>samp.documentation.url</name>\n"); | ||
| 1046 | + response.append(" <value>http://cta.irap.omp.eu/gammalib/user_manual/modules/vo.html</value>\n"); | ||
| 1047 | + response.append(" </member>\n"); | ||
| 1048 | + response.append(" <member>\n"); | ||
| 1049 | + response.append(" <name>author.affiliation</name>\n"); | ||
| 1050 | + response.append(" <value>IRAP, Toulouse, France</value>\n"); | ||
| 1051 | + response.append(" </member>\n"); | ||
| 1052 | + response.append(" <member>\n"); | ||
| 1053 | + response.append(" <name>author.email</name>\n"); | ||
| 1054 | + response.append(" <value>jurgen.knodlseder@irap.omp.eu</value>\n"); | ||
| 1055 | + response.append(" </member>\n"); | ||
| 1056 | + response.append(" <member>\n"); | ||
| 1057 | + response.append(" <name>author.name</name>\n"); | ||
| 1058 | + response.append(" <value>J. Knoedlseder, T. Louge</value>\n"); | ||
| 1059 | + response.append(" </member>\n"); | ||
| 1060 | + response.append(" <member>\n"); | ||
| 1061 | + response.append(" <name>home.page</name>\n"); | ||
| 1062 | + response.append(" <value>http://cta.irap.omp.eu/gammalib/</value>\n"); | ||
| 1063 | + response.append(" </member>\n"); | ||
| 1064 | + } | ||
| 1065 | + | ||
| 1066 | + // ... otherwise get the index | ||
| 1067 | + else { | ||
| 1068 | + | ||
| 1069 | + // Get client index | ||
| 1070 | + int i = get_client_index(client_name); | ||
| 1071 | + | ||
| 1072 | + // Continue only if index is valid | ||
| 1073 | + if (i != -1) { | ||
| 1074 | + | ||
| 1075 | + // Append response | ||
| 1076 | + response.append(" <member>\n"); | ||
| 1077 | + response.append(" <name>samp.name</name>\n"); | ||
| 1078 | + response.append(" <value>"+m_clients[i].name+"</value>\n"); | ||
| 1079 | + response.append(" </member>\n"); | ||
| 1080 | + response.append(" <member>\n"); | ||
| 1081 | + response.append(" <name>samp.description.text</name>\n"); | ||
| 1082 | + response.append(" <value>"+m_clients[i].description+"</value>\n"); | ||
| 1083 | + response.append(" </member>\n"); | ||
| 1084 | + response.append(" <member>\n"); | ||
| 1085 | + response.append(" <name>samp.icon.url</name>\n"); | ||
| 1086 | + response.append(" <value>"+m_clients[i].icon+"</value>\n"); | ||
| 1087 | + response.append(" </member>\n"); | ||
| 1088 | + response.append(" <member>\n"); | ||
| 1089 | + response.append(" <name>samp.documentation.url</name>\n"); | ||
| 1090 | + response.append(" <value>"+m_clients[i].documentation+"</value>\n"); | ||
| 1091 | + response.append(" </member>\n"); | ||
| 1092 | + response.append(" <member>\n"); | ||
| 1093 | + response.append(" <name>author.affiliation</name>\n"); | ||
| 1094 | + response.append(" <value>"+m_clients[i].affiliation+"</value>\n"); | ||
| 1095 | + response.append(" </member>\n"); | ||
| 1096 | + response.append(" <member>\n"); | ||
| 1097 | + response.append(" <name>author.email</name>\n"); | ||
| 1098 | + response.append(" <value>"+m_clients[i].email+"</value>\n"); | ||
| 1099 | + response.append(" </member>\n"); | ||
| 1100 | + response.append(" <member>\n"); | ||
| 1101 | + response.append(" <name>author.name</name>\n"); | ||
| 1102 | + response.append(" <value>"+m_clients[i].author_name+"</value>\n"); | ||
| 1103 | + response.append(" </member>\n"); | ||
| 1104 | + response.append(" <member>\n"); | ||
| 1105 | + response.append(" <name>home.page</name>\n"); | ||
| 1106 | + response.append(" <value>"+m_clients[i].homepage+"</value>\n"); | ||
| 1107 | + response.append(" </member>\n"); | ||
| 1108 | + | ||
| 1109 | + } // endif: index was valid | ||
| 1110 | + | ||
| 1111 | + } // endelse: client was not the hub | ||
| 1112 | + | ||
| 1113 | + // Finish response | ||
| 1114 | + response.append(" </struct></value></param>\n"); | ||
| 1115 | + response.append("</params>\n"); | ||
| 1116 | + response.append("</methodResponse>\n"); | ||
| 1117 | + | ||
| 1118 | + // Post response | ||
| 1119 | + post_string(response, sock); | ||
| 1120 | + | ||
| 1121 | + // Return | ||
| 1122 | + return; | ||
| 1123 | +} | ||
| 1124 | + | ||
| 1125 | +/***********************************************************************//** | ||
| 1126 | + * @brief Handles calls to specific client | ||
| 1127 | + * | ||
| 1128 | + * @param[in] xml XML message sent by client. | ||
| 1129 | + * @param[in] sock Socket. | ||
| 1130 | + * | ||
| 1131 | + * Handles all incoming cals for a specific client | ||
| 1132 | + ***************************************************************************/ | ||
| 1133 | +void GVOHub::request_call(const GXml& xml, const socklen_t& sock) | ||
| 1134 | +{ | ||
| 1135 | + // Header | ||
| 1136 | + #if defined(G_CONSOLE_DUMP) | ||
| 1137 | + std::cout << "GVOHub::request_get_registered_clients" << std::endl; | ||
| 1138 | + #endif | ||
| 1139 | + | ||
| 1140 | + // Get client key | ||
| 1141 | + std::string key = get_client_key(xml); | ||
| 1142 | + // Get message mtype | ||
| 1143 | + std::string mtype = get_mtype(xml); | ||
| 1144 | + // Get the key of client who is to be contacted with the message | ||
| 1145 | + // Declare message | ||
| 1146 | + std::string msg = ""; | ||
| 1147 | + // Determine which call has been invoqued | ||
| 1148 | + // Loop over all clients and send notification | ||
| 1149 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 1150 | + msg = ""; | ||
| 1151 | + | ||
| 1152 | + // Set response for table.load.votable | ||
| 1153 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 1154 | + msg.append("<methodCall><methodName>samp.client.receiveCall</methodName>\n"); | ||
| 1155 | + msg.append("<params>\n"); | ||
| 1156 | + msg.append(" <param><value>"); | ||
| 1157 | + msg.append(m_clients[i].private_key); | ||
| 1158 | + msg.append("</value></param>\n"); | ||
| 1159 | + msg.append(" <param><value>"+m_hub_id+"</value></param>\n"); | ||
| 1160 | + msg.append(" <param><value><struct>\n"); | ||
| 1161 | + msg.append(" <member>\n"); | ||
| 1162 | + msg.append(" <name>samp.mtype</name>\n"); | ||
| 1163 | + msg.append(" <value>table.load.votable</value>\n"); | ||
| 1164 | + msg.append(" </member>\n"); | ||
| 1165 | + msg.append(" <member>\n"); | ||
| 1166 | + msg.append(" <name>samp.params</name>\n"); | ||
| 1167 | + msg.append(" <value><struct>\n"); | ||
| 1168 | + msg.append(" <member>\n"); | ||
| 1169 | + msg.append(" <name>name</name>\n"); | ||
| 1170 | + msg.append(" <value>imagename</value>\n"); | ||
| 1171 | + msg.append(" </member>\n"); | ||
| 1172 | + msg.append(" <member>\n"); | ||
| 1173 | + msg.append(" <name>table-id</name>\n"); | ||
| 1174 | + msg.append(" <value>id of table</value>\n"); | ||
| 1175 | + msg.append(" </member>\n"); | ||
| 1176 | + msg.append(" <member>\n"); | ||
| 1177 | + msg.append(" <name>url</name>\n"); | ||
| 1178 | + msg.append(" <value>url to the table</value>\n"); | ||
| 1179 | + msg.append(" </member>\n"); | ||
| 1180 | + msg.append(" </struct></value>\n"); | ||
| 1181 | + msg.append(" </member>\n"); | ||
| 1182 | + msg.append(" </struct></value>\n"); | ||
| 1183 | + msg.append(" </param>\n"); | ||
| 1184 | + msg.append("</params>\n"); | ||
| 1185 | + msg.append("</methodCall>\n"); | ||
| 1186 | + | ||
| 1187 | + | ||
| 1188 | + // Post notification | ||
| 1189 | + notify(m_clients[i].url, msg); | ||
| 1190 | + } | ||
| 1191 | + | ||
| 1192 | + // Return | ||
| 1193 | + return; | ||
| 1194 | + | ||
| 1195 | +} | ||
| 1196 | + | ||
| 1197 | +/***********************************************************************//** | ||
| 1198 | + * @brief Handles Hub shutdown requests | ||
| 1199 | + * | ||
| 1200 | + * @param[in] sock Socket. | ||
| 1201 | + * | ||
| 1202 | + * Handles all incoming Hub shutdown requests. | ||
| 1203 | + ***************************************************************************/ | ||
| 1204 | +void GVOHub::request_shutdown(const socklen_t& sock) | ||
| 1205 | +{ | ||
| 1206 | + // Header | ||
| 1207 | + #if defined(G_CONSOLE_DUMP) | ||
| 1208 | + std::cout << "GVOHub::request_shutdown" << std::endl; | ||
| 1209 | + #endif | ||
| 1210 | + | ||
| 1211 | + // Set shutdown flag | ||
| 1212 | + m_shutdown = true; | ||
| 1213 | + | ||
| 1214 | + // Post SAMP ok | ||
| 1215 | + post_samp_ok(sock); | ||
| 1216 | + | ||
| 1217 | + // Return | ||
| 1218 | + return; | ||
| 1219 | +} | ||
| 1220 | + | ||
| 1221 | + | ||
| 1222 | +/***********************************************************************//** | ||
| 1223 | + * @brief Extract client key from XML request | ||
| 1224 | + * | ||
| 1225 | + * @param[in] xml XML message sent by client. | ||
| 1226 | + * | ||
| 1227 | + * Extracts the clients key from the XML request. | ||
| 1228 | + ***************************************************************************/ | ||
| 1229 | +std::string GVOHub::get_client_key(const GXml& xml) const | ||
| 1230 | +{ | ||
| 1231 | + // Header | ||
| 1232 | + #if defined(G_CONSOLE_DUMP) | ||
| 1233 | + std::cout << "GVOHub::get_client_key" << std::endl; | ||
| 1234 | + #endif | ||
| 1235 | + | ||
| 1236 | + // Initialise response | ||
| 1237 | + std::string client_key = ""; | ||
| 1238 | + | ||
| 1239 | + // Get the client's private key | ||
| 1240 | + const GXmlNode* node = xml.element("methodCall > params > param > value"); | ||
| 1241 | + if (node != NULL) { | ||
| 1242 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 1243 | + if (text != NULL) { | ||
| 1244 | + client_key = text->text(); | ||
| 1245 | + } | ||
| 1246 | + } | ||
| 1247 | + | ||
| 1248 | + // Return key | ||
| 1249 | + return client_key; | ||
| 1250 | +} | ||
| 1251 | + | ||
| 1252 | + | ||
| 1253 | +/***********************************************************************//** | ||
| 1254 | + * @brief Extract client index in shared memory from XML request | ||
| 1255 | + * | ||
| 1256 | + * @param[in] xml XML message sent by client. | ||
| 1257 | + * @return Client index (-1 if not found). | ||
| 1258 | + * | ||
| 1259 | + * Extracts the client index from the XML request. The method returns -1 if | ||
| 1260 | + * no client was found. | ||
| 1261 | + ***************************************************************************/ | ||
| 1262 | +int GVOHub::get_client_index(const GXml& xml) const | ||
| 1263 | +{ | ||
| 1264 | + // Header | ||
| 1265 | + #if defined(G_CONSOLE_DUMP) | ||
| 1266 | + std::cout << "GVOHub::get_client_index" << std::endl; | ||
| 1267 | + #endif | ||
| 1268 | + | ||
| 1269 | + // Initialise index | ||
| 1270 | + int index = -1; | ||
| 1271 | + | ||
| 1272 | + // Get the client's private key | ||
| 1273 | + std::string key = get_client_key(xml); | ||
| 1274 | + | ||
| 1275 | + // Continue only if string is not empty | ||
| 1276 | + if (!key.empty()) { | ||
| 1277 | + | ||
| 1278 | + // Searches for key in clients | ||
| 1279 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 1280 | + if (m_clients[i].private_key == key) { | ||
| 1281 | + index = i; | ||
| 1282 | + break; | ||
| 1283 | + } | ||
| 1284 | + } | ||
| 1285 | + | ||
| 1286 | + } // endif: key was not empty | ||
| 1287 | + | ||
| 1288 | + // Return index | ||
| 1289 | + return index; | ||
| 1290 | +} | ||
| 1291 | + | ||
| 1292 | + | ||
| 1293 | +/***********************************************************************//** | ||
| 1294 | + * @brief Extract client index in shared memory from XML request | ||
| 1295 | + * | ||
| 1296 | + * @param[in] reference Client reference. | ||
| 1297 | + * @return Client index (-1 if not found). | ||
| 1298 | + * | ||
| 1299 | + * Extracts the client index from the client reference. The method returns -1 | ||
| 1300 | + * if no client was found. | ||
| 1301 | + ***************************************************************************/ | ||
| 1302 | +int GVOHub::get_client_index(const std::string& reference) const | ||
| 1303 | +{ | ||
| 1304 | + // Header | ||
| 1305 | + #if defined(G_CONSOLE_DUMP) | ||
| 1306 | + std::cout << "GVOHub::get_client_index" << std::endl; | ||
| 1307 | + #endif | ||
| 1308 | + | ||
| 1309 | + // Initialise index | ||
| 1310 | + int index = -1; | ||
| 1311 | + | ||
| 1312 | + // Search for index | ||
| 1313 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 1314 | + if (m_clients[i].reference == reference) { | ||
| 1315 | + index = i; | ||
| 1316 | + break; | ||
| 1317 | + } | ||
| 1318 | + } | ||
| 1319 | + | ||
| 1320 | + // Return index | ||
| 1321 | + return index; | ||
| 1322 | +} | ||
| 1323 | + | ||
| 1324 | + | ||
| 1325 | +/***********************************************************************//** | ||
| 1326 | + * @brief Returns value for a SAMP client query parameter | ||
| 1327 | + * | ||
| 1328 | + * @param[in] xml client query XML document. | ||
| 1329 | + * @param[in] name Parameter name. | ||
| 1330 | + * @return Parameter value. | ||
| 1331 | + * | ||
| 1332 | + * Returns value for a SAMP client query parameter. If the specified | ||
| 1333 | + * parameter was not found or if the response structure is not compliant, | ||
| 1334 | + * an empty string is returned. | ||
| 1335 | + ***************************************************************************/ | ||
| 1336 | +std::string GVOHub::get_response_value(const GXml& xml, | ||
| 1337 | + const std::string& name) const | ||
| 1338 | +{ | ||
| 1339 | + // Declare value | ||
| 1340 | + std::string value = ""; | ||
| 1341 | + | ||
| 1342 | + // Get the client's private key | ||
| 1343 | + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct"); | ||
| 1344 | + if (node != NULL) { | ||
| 1345 | + int num = node->elements("member"); | ||
| 1346 | + for (int i = 0; i < num; ++i) { | ||
| 1347 | + const GXmlNode* member = node->element("member", i); | ||
| 1348 | + std::string one_name; | ||
| 1349 | + std::string one_value; | ||
| 1350 | + get_name_value_pair(member, one_name, one_value); | ||
| 1351 | + if (one_name == name) { | ||
| 1352 | + value = one_value; | ||
| 1353 | + break; | ||
| 1354 | + } | ||
| 1355 | + } | ||
| 1356 | + | ||
| 1357 | + } | ||
| 1358 | + | ||
| 1359 | + // Return value | ||
| 1360 | + return value; | ||
| 1361 | +} | ||
| 1362 | + | ||
| 1363 | + | ||
| 1364 | +/***********************************************************************//** | ||
| 1365 | + * @brief Extract name / value pair from XML node | ||
| 1366 | + * | ||
| 1367 | + * @param[in] node Pointer to XML node. | ||
| 1368 | + * @param[out] name Name string. | ||
| 1369 | + * @param[out] value Value string. | ||
| 1370 | + * | ||
| 1371 | + * Extracts a name / value pair from a XML node. If the XML node pointer is | ||
| 1372 | + * NULL, the name and value strings will be empty. | ||
| 1373 | + ***************************************************************************/ | ||
| 1374 | +void GVOHub::get_name_value_pair(const GXmlNode* node, | ||
| 1375 | + std::string& name, | ||
| 1376 | + std::string& value) const | ||
| 1377 | +{ | ||
| 1378 | + // Clear name and value strings | ||
| 1379 | + name.clear(); | ||
| 1380 | + value.clear(); | ||
| 1381 | + | ||
| 1382 | + // Continue only if node is valid | ||
| 1383 | + if (node != NULL) { | ||
| 1384 | + | ||
| 1385 | + // Get name node and extract text content | ||
| 1386 | + const GXmlNode* ptr = node->element("name", 0); | ||
| 1387 | + if (ptr != NULL) { | ||
| 1388 | + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]); | ||
| 1389 | + if (text != NULL) { | ||
| 1390 | + name = text->text(); | ||
| 1391 | + } | ||
| 1392 | + } | ||
| 1393 | + | ||
| 1394 | + // Get value node and extract text content | ||
| 1395 | + ptr = node->element("value", 0); | ||
| 1396 | + if (ptr != NULL) { | ||
| 1397 | + const GXmlText* text = static_cast<const GXmlText*>((*ptr)[0]); | ||
| 1398 | + if (text != NULL) { | ||
| 1399 | + value = text->text(); | ||
| 1400 | + } | ||
| 1401 | + } | ||
| 1402 | + } | ||
| 1403 | + | ||
| 1404 | + // Return | ||
| 1405 | + return; | ||
| 1406 | +} | ||
| 1407 | + | ||
| 1408 | + | ||
| 1409 | +/***********************************************************************//** | ||
| 1410 | + * @brief Returns subscriptions from XML document | ||
| 1411 | + * | ||
| 1412 | + * @param[in] xml client query XML document. | ||
| 1413 | + * @return List of subscriptions. | ||
| 1414 | + ***************************************************************************/ | ||
| 1415 | +std::vector<std::string> GVOHub::get_subscriptions(const GXml& xml) const | ||
| 1416 | +{ | ||
| 1417 | + // Declare subscriptions | ||
| 1418 | + std::vector<std::string> subscriptions; | ||
| 1419 | + | ||
| 1420 | + // Get the client's private key | ||
| 1421 | + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct"); | ||
| 1422 | + if (node != NULL) { | ||
| 1423 | + int num = node->elements("member"); | ||
| 1424 | + for (int i = 0; i < num; ++i) { | ||
| 1425 | + const GXmlNode* member = node->element("member", i); | ||
| 1426 | + if (member != NULL) { | ||
| 1427 | + const GXmlNode* name = member->element("name", 0); | ||
| 1428 | + if (name != NULL) { | ||
| 1429 | + const GXmlText* text = static_cast<const GXmlText*>((*name)[0]); | ||
| 1430 | + if (text != NULL) { | ||
| 1431 | + subscriptions.push_back(text->text()); | ||
| 1432 | + } | ||
| 1433 | + } | ||
| 1434 | + } | ||
| 1435 | + } | ||
| 1436 | + } | ||
| 1437 | + | ||
| 1438 | + // Return subscriptions | ||
| 1439 | + return subscriptions; | ||
| 1440 | +} | ||
| 1441 | + | ||
| 1442 | + | ||
| 1443 | +/***********************************************************************//** | ||
| 1444 | + * @brief Returns callback URL of client | ||
| 1445 | + * | ||
| 1446 | + * @param[in] xml client query XML document. | ||
| 1447 | + * @return Callback URL of client. | ||
| 1448 | + ***************************************************************************/ | ||
| 1449 | +std::string GVOHub::get_callback_url(const GXml& xml) const | ||
| 1450 | +{ | ||
| 1451 | + // Declare URL | ||
| 1452 | + std::string url; | ||
| 1453 | + | ||
| 1454 | + // Get the client's private key | ||
| 1455 | + const GXmlNode* node = xml.element("methodCall > params > param[1] > value"); | ||
| 1456 | + if (node != NULL) { | ||
| 1457 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 1458 | + if (text != NULL) { | ||
| 1459 | + url.append(text->text()); | ||
| 1460 | + } | ||
| 1461 | + } | ||
| 1462 | + | ||
| 1463 | + // Return URL | ||
| 1464 | + return url; | ||
| 1465 | +} | ||
| 1466 | + | ||
| 1467 | + | ||
| 1468 | +/***********************************************************************//** | ||
| 1469 | + * @brief Returns SAMP Hub lockfile URL | ||
| 1470 | + * | ||
| 1471 | + * @return SAMP Hub lockfile URL (empty if no lockfile was found). | ||
| 1472 | + * | ||
| 1473 | + * Implements IVOA standard REC-SAMP-1.3-20120411. | ||
| 1474 | + ***************************************************************************/ | ||
| 1475 | +std::string GVOHub::get_hub_lockfile(void) const | ||
| 1476 | +{ | ||
| 1477 | + // Initialise result | ||
| 1478 | + std::string url = ""; | ||
| 1479 | + | ||
| 1480 | + // Check for existence of the SAMP_HUB environment variable first | ||
| 1481 | + char* hub_ptr = std::getenv("SAMP_HUB"); | ||
| 1482 | + if (hub_ptr != NULL) { | ||
| 1483 | + | ||
| 1484 | + // Check for mandatory std-lockurl: prefix (no other prefixe is | ||
| 1485 | + // supported so far) | ||
| 1486 | + std::string lockurl = std::string(hub_ptr); | ||
| 1487 | + if (lockurl.compare(0, 12, "std-lockurl:") == 0) { | ||
| 1488 | + | ||
| 1489 | + // Extract URL | ||
| 1490 | + url = lockurl.substr(12, std::string::npos); | ||
| 1491 | + | ||
| 1492 | + } // endif: std-lockurl: prefix found | ||
| 1493 | + | ||
| 1494 | + } | ||
| 1495 | + | ||
| 1496 | + // ... otherwise the lockfile should be $HOME/.samp | ||
| 1497 | + else { | ||
| 1498 | + | ||
| 1499 | + // Get user's HOME directory path as the prefix of the full | ||
| 1500 | + // path. If the HOME environment variable is not set we | ||
| 1501 | + // expect that .samp is in the local directory. This is non | ||
| 1502 | + // standard, but prevents for creating an exception here. | ||
| 1503 | + std::string prefix = ""; | ||
| 1504 | + char* home_ptr = std::getenv("HOME"); | ||
| 1505 | + if (home_ptr != NULL) { | ||
| 1506 | + prefix = std::string(home_ptr) + "/"; | ||
| 1507 | + } | ||
| 1508 | + | ||
| 1509 | + // Set filename | ||
| 1510 | + url = prefix + ".samp"; | ||
| 1511 | + | ||
| 1512 | + } // endelse: no SAMP_HUB environment variable found | ||
| 1513 | + | ||
| 1514 | + // Return URL | ||
| 1515 | + return url; | ||
| 1516 | +} | ||
| 1517 | + | ||
| 1518 | + | ||
| 1519 | +/***********************************************************************//** | ||
| 1520 | + * @brief Send notifications | ||
| 1521 | + * | ||
| 1522 | + * @param[in] method Name of the method | ||
| 1523 | + * @param[in] client Reference of the client | ||
| 1524 | + * | ||
| 1525 | + * The method send notifications to all registered clients that request so. | ||
| 1526 | + ***************************************************************************/ | ||
| 1527 | +void GVOHub::send_notifications(const std::string& method, | ||
| 1528 | + const std::string& client) | ||
| 1529 | +{ | ||
| 1530 | + // Loop over all clients | ||
| 1531 | + for (int i = 0; i < m_clients.size(); ++i) { | ||
| 1532 | + | ||
| 1533 | + // Loop over all methods | ||
| 1534 | + for (int j = 0; j < m_clients[i].subscriptions.size(); ++j) { | ||
| 1535 | + | ||
| 1536 | + // Continue only if method matches | ||
| 1537 | + if (method == m_clients[i].subscriptions[j]) { | ||
| 1538 | + | ||
| 1539 | + // Declare notification | ||
| 1540 | + std::string msg = ""; | ||
| 1541 | + | ||
| 1542 | + // Register | ||
| 1543 | + if (method == "samp.hub.event.register") { | ||
| 1544 | + | ||
| 1545 | + // Set response for samp.hub.event.register | ||
| 1546 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 1547 | + msg.append("<methodCall>\n"); | ||
| 1548 | + msg.append("<methodName>samp.client.receiveNotification</methodName>\n"); | ||
| 1549 | + msg.append("<params>\n"); | ||
| 1550 | + msg.append(" <param><value>"); | ||
| 1551 | + msg.append(m_clients[i].private_key); | ||
| 1552 | + msg.append("</value></param>\n"); | ||
| 1553 | + msg.append(" <param><value>"+m_hub_id+"</value></param>\n"); | ||
| 1554 | + msg.append(" <param><value><struct>\n"); | ||
| 1555 | + msg.append(" <member>\n"); | ||
| 1556 | + msg.append(" <name>samp.mtype</name>\n"); | ||
| 1557 | + msg.append(" <value>samp.hub.event.register</value>\n"); | ||
| 1558 | + msg.append(" </member>\n"); | ||
| 1559 | + msg.append(" <member>\n"); | ||
| 1560 | + msg.append(" <name>samp.params</name>\n"); | ||
| 1561 | + msg.append(" <value><struct>\n"); | ||
| 1562 | + msg.append(" <member>\n"); | ||
| 1563 | + msg.append(" <name>id</name>\n"); | ||
| 1564 | + msg.append(" <value>"+client+"</value>\n"); | ||
| 1565 | + msg.append(" </member>\n"); | ||
| 1566 | + msg.append(" </struct></value>\n"); | ||
| 1567 | + msg.append(" </member>\n"); | ||
| 1568 | + msg.append(" </struct></value></param>\n"); | ||
| 1569 | + msg.append("</params>\n"); | ||
| 1570 | + msg.append("</methodCall>\n"); | ||
| 1571 | + | ||
| 1572 | + // Post notification | ||
| 1573 | + notify(m_clients[i].url, msg); | ||
| 1574 | + | ||
| 1575 | + } | ||
| 1576 | + | ||
| 1577 | + // Unregister | ||
| 1578 | + else if (method == "samp.hub.event.unregister") { | ||
| 1579 | + | ||
| 1580 | + // Set response for samp.hub.event.unregister | ||
| 1581 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 1582 | + msg.append("<methodCall>\n"); | ||
| 1583 | + msg.append("<methodName>samp.client.receiveNotification</methodName>\n"); | ||
| 1584 | + msg.append("<params>\n"); | ||
| 1585 | + msg.append(" <param><value>"); | ||
| 1586 | + msg.append(m_clients[i].private_key); | ||
| 1587 | + msg.append("</value></param>\n"); | ||
| 1588 | + msg.append(" <param><value>"); | ||
| 1589 | + msg.append(m_hub_id); | ||
| 1590 | + msg.append("</value></param>\n"); | ||
| 1591 | + msg.append(" <param><value><struct>\n"); | ||
| 1592 | + msg.append(" <member>\n"); | ||
| 1593 | + msg.append(" <name>samp.mtype</name>\n"); | ||
| 1594 | + msg.append(" <value>samp.hub.event.unregister</value>\n"); | ||
| 1595 | + msg.append(" </member>\n"); | ||
| 1596 | + msg.append(" <member>\n"); | ||
| 1597 | + msg.append(" <name>samp.params</name>\n"); | ||
| 1598 | + msg.append(" <value><struct>\n"); | ||
| 1599 | + msg.append(" <member>\n"); | ||
| 1600 | + msg.append(" <name>id</name>\n"); | ||
| 1601 | + msg.append(" <value>"+client+"</value>\n"); | ||
| 1602 | + msg.append(" </member>\n"); | ||
| 1603 | + msg.append(" </struct></value>\n"); | ||
| 1604 | + msg.append(" </member>\n"); | ||
| 1605 | + msg.append(" </struct></value></param>\n"); | ||
| 1606 | + msg.append("</params>\n"); | ||
| 1607 | + msg.append("</methodCall>\n"); | ||
| 1608 | + | ||
| 1609 | + // Post notification | ||
| 1610 | + notify(m_clients[i].url, msg); | ||
| 1611 | + | ||
| 1612 | + } | ||
| 1613 | + | ||
| 1614 | + // Metadata | ||
| 1615 | + else if (method == "samp.hub.event.metadata") { | ||
| 1616 | + | ||
| 1617 | + // Get index of client | ||
| 1618 | + int k; | ||
| 1619 | + for (k = 0; k < m_clients.size(); ++k) { | ||
| 1620 | + if (m_clients[k].reference == client) { | ||
| 1621 | + break; | ||
| 1622 | + } | ||
| 1623 | + } | ||
| 1624 | + | ||
| 1625 | + // Fall through if client index is not valid | ||
| 1626 | + if (k >= m_clients.size()) { | ||
| 1627 | + continue; | ||
| 1628 | + } | ||
| 1629 | + | ||
| 1630 | + // Set response for samp.hub.event.metadata | ||
| 1631 | + msg.append("<?xml version=\"1.0\"?>\n"); | ||
| 1632 | + msg.append("<methodCall><methodName>samp.client.receiveNotification</methodName>\n"); | ||
| 1633 | + msg.append("<params>\n"); | ||
| 1634 | + msg.append(" <param><value>"); | ||
| 1635 | + msg.append(m_clients[i].private_key); | ||
| 1636 | + msg.append("</value></param>\n"); | ||
| 1637 | + msg.append(" <param><value>"+m_hub_id+"</value></param>\n"); | ||
| 1638 | + msg.append(" <param><value><struct>\n"); | ||
| 1639 | + msg.append(" <member>\n"); | ||
| 1640 | + msg.append(" <name>samp.mtype</name>\n"); | ||
| 1641 | + msg.append(" <value>samp.hub.event.metadata</value>\n"); | ||
| 1642 | + msg.append(" </member>\n"); | ||
| 1643 | + msg.append(" <member>\n"); | ||
| 1644 | + msg.append(" <name>samp.params</name>\n"); | ||
| 1645 | + msg.append(" <value><struct>\n"); | ||
| 1646 | + msg.append(" <member>\n"); | ||
| 1647 | + msg.append(" <name>id</name>\n"); | ||
| 1648 | + msg.append(" <value>"+m_clients[k].reference+"</value>\n"); | ||
| 1649 | + msg.append(" </member>\n"); | ||
| 1650 | + msg.append(" <member>\n"); | ||
| 1651 | + msg.append(" <name>metadata</name>\n"); | ||
| 1652 | + msg.append(" <value><struct>\n"); | ||
| 1653 | + msg.append(" <member>\n"); | ||
| 1654 | + msg.append(" <name>samp.name</name>\n"); | ||
| 1655 | + msg.append(" <value>"+m_clients[k].name+"</value>\n"); | ||
| 1656 | + msg.append(" </member>\n"); | ||
| 1657 | + msg.append(" <member>\n"); | ||
| 1658 | + msg.append(" <name>samp.description.text</name>\n"); | ||
| 1659 | + msg.append(" <value>"+m_clients[k].description+"</value>\n"); | ||
| 1660 | + msg.append(" </member>\n"); | ||
| 1661 | + msg.append(" <member>\n"); | ||
| 1662 | + msg.append(" <name>samp.icon.url</name>\n"); | ||
| 1663 | + msg.append(" <value>"+m_clients[k].icon+"</value>\n"); | ||
| 1664 | + msg.append(" </member>\n"); | ||
| 1665 | + msg.append(" <member>\n"); | ||
| 1666 | + msg.append(" <name>samp.documentation.url</name>\n"); | ||
| 1667 | + msg.append(" <value>"+m_clients[k].documentation+"</value>\n"); | ||
| 1668 | + msg.append(" </member>\n"); | ||
| 1669 | + msg.append(" <member>\n"); | ||
| 1670 | + msg.append(" <name>author.affiliation</name>\n"); | ||
| 1671 | + msg.append(" <value>"+m_clients[k].affiliation+"</value>\n"); | ||
| 1672 | + msg.append(" </member>\n"); | ||
| 1673 | + msg.append(" <member>\n"); | ||
| 1674 | + msg.append(" <name>author.name</name>\n"); | ||
| 1675 | + msg.append(" <value>"+m_clients[k].author_name+"</value>\n"); | ||
| 1676 | + msg.append(" </member>\n"); | ||
| 1677 | + msg.append(" <member>\n"); | ||
| 1678 | + msg.append(" <name>author.email</name>\n"); | ||
| 1679 | + msg.append(" <value>"+m_clients[k].email+"</value>\n"); | ||
| 1680 | + msg.append(" </member>\n"); | ||
| 1681 | + msg.append(" <member>\n"); | ||
| 1682 | + msg.append(" <name>home.page</name>\n"); | ||
| 1683 | + msg.append(" <value>"+m_clients[k].homepage+"</value>\n"); | ||
| 1684 | + msg.append(" </member>\n"); | ||
| 1685 | + msg.append(" </struct></value>\n"); | ||
| 1686 | + msg.append(" </member>\n"); | ||
| 1687 | + msg.append(" </struct></value>\n"); | ||
| 1688 | + msg.append(" </member>\n"); | ||
| 1689 | + msg.append(" </struct></value></param>\n"); | ||
| 1690 | + msg.append("</params>\n"); | ||
| 1691 | + msg.append("</methodCall>\n"); | ||
| 1692 | + | ||
| 1693 | + // Post notification | ||
| 1694 | + notify(m_clients[i].url, msg); | ||
| 1695 | + | ||
| 1696 | + } // endelse: metadata | ||
| 1697 | + | ||
| 1698 | + } // endif: method was requested one | ||
| 1699 | + | ||
| 1700 | + } // endfor: looped over all methods | ||
| 1701 | + | ||
| 1702 | + } // endfor: looped over all clients | ||
| 1703 | + | ||
| 1704 | + // Return | ||
| 1705 | + return; | ||
| 1706 | +} | ||
| 1707 | + | ||
| 1708 | + | ||
| 1709 | +/***********************************************************************//** | ||
| 1710 | + * @brief Creates the lockfile, fill it | ||
| 1711 | + * | ||
| 1712 | + * Implements IVOA standard REC-SAMP-1.3-20120411. | ||
| 1713 | + ***************************************************************************/ | ||
| 1714 | +void GVOHub::create_samp_file(void) const | ||
| 1715 | +{ | ||
| 1716 | + // Get lockfile URL | ||
| 1717 | + std::string lockurl = get_hub_lockfile(); | ||
| 1718 | + | ||
| 1719 | + // Open SAMP lockfile. Continue only if opening was successful | ||
| 1720 | + FILE* fptr = fopen(lockurl.c_str(), "w"); | ||
| 1721 | + | ||
| 1722 | + // Successful? | ||
| 1723 | + if (fptr != NULL) { | ||
| 1724 | + | ||
| 1725 | + // Write lockfile | ||
| 1726 | + fprintf(fptr, "# SAMP lockfile\n"); | ||
| 1727 | + fprintf(fptr, "# Required keys:\n"); | ||
| 1728 | + fprintf(fptr, "samp.secret=%s\n", m_secret.c_str()); | ||
| 1729 | + fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", m_hub_url.c_str()); | ||
| 1730 | + fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str()); | ||
| 1731 | + fprintf(fptr, "# Info stored by hub for some private reason:\n"); | ||
| 1732 | + fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str()); | ||
| 1733 | + | ||
| 1734 | + // Close lockfile | ||
| 1735 | + fclose(fptr); | ||
| 1736 | + | ||
| 1737 | + } | ||
| 1738 | + | ||
| 1739 | + // Return | ||
| 1740 | + return; | ||
| 1741 | +} | ||
| 1742 | + | ||
| 1743 | + | ||
| 1744 | +/***********************************************************************//** | ||
| 1745 | + * @brief Post string content to client | ||
| 1746 | + * | ||
| 1747 | + * @param[in] content String content to post. | ||
| 1748 | + * @param[in] sock Socket. | ||
| 1749 | + * | ||
| 1750 | + * Posts the content of a string to a client. | ||
| 1751 | + ***************************************************************************/ | ||
| 1752 | +void GVOHub::post_string(const std::string& content, const socklen_t& sock) const | ||
| 1753 | +{ | ||
| 1754 | + // Continue only if socket is valid | ||
| 1755 | + if (sock != -1) { | ||
| 1756 | + | ||
| 1757 | + // Determine content length | ||
| 1758 | + int length = content.length(); | ||
| 1759 | + | ||
| 1760 | + // Set prefix (note that the response has no POST!) | ||
| 1761 | + std::string prefix = "HTTP/1.1 200 OK\n" | ||
| 1762 | + "Connection: close\n" | ||
| 1763 | + "Content-Type: text/xml\n" | ||
| 1764 | + "Content-Length: "+gammalib::str(length)+"\n\n"; | ||
| 1765 | + | ||
| 1766 | + | ||
| 1767 | + // Build post string | ||
| 1768 | + std::string post = prefix + content; | ||
| 1769 | + | ||
| 1770 | + // Dump message to post | ||
| 1771 | + #if defined(G_SHOW_MESSAGE) | ||
| 1772 | + std::cout << std::endl; | ||
| 1773 | + std::cout << "GVOHub response:" << std::endl; | ||
| 1774 | + std::cout << "================" << std::endl; | ||
| 1775 | + std::cout << post << std::endl; | ||
| 1776 | + #endif | ||
| 1777 | + | ||
| 1778 | + // Send content to socket | ||
| 1779 | + bool done = false; | ||
| 1780 | + do { | ||
| 1781 | + int length = post.length(); | ||
| 1782 | + int sent_length = send(sock, post.c_str(), length, 0); | ||
| 1783 | + if (sent_length < length) { | ||
| 1784 | + post = post.substr(sent_length, std::string::npos); | ||
| 1785 | + } | ||
| 1786 | + else { | ||
| 1787 | + done = true; | ||
| 1788 | + } | ||
| 1789 | + } while (!done); | ||
| 1790 | + | ||
| 1791 | + } // endif: socket was valid | ||
| 1792 | + | ||
| 1793 | + // Return | ||
| 1794 | + return; | ||
| 1795 | +} | ||
| 1796 | + | ||
| 1797 | + | ||
| 1798 | +/***********************************************************************//** | ||
| 1799 | + * @brief Post SAMP ok massage to client | ||
| 1800 | + * | ||
| 1801 | + * @param[in] sock Socket. | ||
| 1802 | + * | ||
| 1803 | + * Posts a SAMP OK message to a client. | ||
| 1804 | + ***************************************************************************/ | ||
| 1805 | +void GVOHub::post_samp_ok(const socklen_t& sock) const | ||
| 1806 | +{ | ||
| 1807 | + // Declare response | ||
| 1808 | + std::string response = ""; | ||
| 1809 | + | ||
| 1810 | + // Compose response | ||
| 1811 | + response.append("<?xml version='1.0' encoding='UTF-8'?>\n"); | ||
| 1812 | + response.append("<methodResponse>\n"); | ||
| 1813 | + response.append("<params>\n"); | ||
| 1814 | + response.append(" <param><value><struct>\n"); | ||
| 1815 | + response.append(" <member>\n"); | ||
| 1816 | + response.append(" <name>samp.status</name>\n"); | ||
| 1817 | + response.append(" <value>samp.ok</value>\n"); | ||
| 1818 | + response.append(" </member>\n"); | ||
| 1819 | + response.append(" </struct></value></param>\n"); | ||
| 1820 | + response.append("</params>\n"); | ||
| 1821 | + response.append("</methodResponse>\n"); | ||
| 1822 | + | ||
| 1823 | + // Post string | ||
| 1824 | + post_string(response, sock); | ||
| 1825 | + | ||
| 1826 | + // Return | ||
| 1827 | + return; | ||
| 1828 | +} | ||
| 1829 | + | ||
| 1830 | + | ||
| 1831 | +/***********************************************************************//** | ||
| 1832 | + * @brief Post SAMP void massage to client | ||
| 1833 | + * | ||
| 1834 | + * @param[in] sock Socket. | ||
| 1835 | + * | ||
| 1836 | + * Posts a void SAMP message to a client. Void messages can typically be | ||
| 1837 | + * discared by the client. | ||
| 1838 | + ***************************************************************************/ | ||
| 1839 | +void GVOHub::post_samp_void(const socklen_t& sock) const | ||
| 1840 | +{ | ||
| 1841 | + // Declare response | ||
| 1842 | + std::string response = ""; | ||
| 1843 | + | ||
| 1844 | + // Compose response | ||
| 1845 | + response.append("<?xml version='1.0' encoding='UTF-8'?>\n"); | ||
| 1846 | + response.append("<methodResponse>\n"); | ||
| 1847 | + response.append(" <params>\n"); | ||
| 1848 | + response.append(" <param>\n"); | ||
| 1849 | + response.append(" <value/>\n"); | ||
| 1850 | + response.append(" </param>\n"); | ||
| 1851 | + response.append(" </params>\n"); | ||
| 1852 | + response.append("</methodResponse>\n"); | ||
| 1853 | + | ||
| 1854 | + // Post string | ||
| 1855 | + post_string(response, sock); | ||
| 1856 | + | ||
| 1857 | + // Return | ||
| 1858 | + return; | ||
| 1859 | +} | ||
| 1860 | + | ||
| 1861 | + | ||
| 1862 | +/***********************************************************************//** | ||
| 1863 | + * @brief Send notification to client | ||
| 1864 | + * | ||
| 1865 | + * @param[in] url URL. | ||
| 1866 | + * @param[in] notification Notification. | ||
| 1867 | + * | ||
| 1868 | + * Send a @p notification to a @p url. | ||
| 1869 | + ***************************************************************************/ | ||
| 1870 | +void GVOHub::notify(const std::string& url, | ||
| 1871 | + const std::string& notification) const | ||
| 1872 | +{ | ||
| 1873 | + // Initalise socket | ||
| 1874 | + int socket = -1; | ||
| 1875 | + | ||
| 1876 | + // Extract host, port and path from URL | ||
| 1877 | + std::string host = "127.0.0.1"; | ||
| 1878 | + std::string port = "2525"; | ||
| 1879 | + std::string path = "xmlrpc"; | ||
| 1880 | + if (url.compare(0, 7, "http://") == 0) { | ||
| 1881 | + size_t length; | ||
| 1882 | + size_t start = 7; | ||
| 1883 | + size_t stop = url.find(":", start); | ||
| 1884 | + size_t end = std::string::npos; | ||
| 1885 | + if (stop != std::string::npos) { | ||
| 1886 | + length = stop - start; | ||
| 1887 | + } | ||
| 1888 | + else { | ||
| 1889 | + length = std::string::npos; | ||
| 1890 | + } | ||
| 1891 | + host = url.substr(start, length); | ||
| 1892 | + if (stop != std::string::npos) { | ||
| 1893 | + stop++; | ||
| 1894 | + end = url.find("/", stop); | ||
| 1895 | + if (end != std::string::npos) { | ||
| 1896 | + length = end - stop; | ||
| 1897 | + } | ||
| 1898 | + else { | ||
| 1899 | + length = std::string::npos; | ||
| 1900 | + } | ||
| 1901 | + port = url.substr(stop, length); | ||
| 1902 | + } | ||
| 1903 | + if (end != std::string::npos) { | ||
| 1904 | + end++; | ||
| 1905 | + length = url.length() - end; | ||
| 1906 | + path = url.substr(end, length); | ||
| 1907 | + } | ||
| 1908 | + } | ||
| 1909 | + | ||
| 1910 | + // Set hints | ||
| 1911 | + struct addrinfo hints; | ||
| 1912 | + std::memset(&hints, 0, sizeof(hints)); | ||
| 1913 | + hints.ai_family = AF_INET; | ||
| 1914 | + hints.ai_socktype = SOCK_STREAM; | ||
| 1915 | + | ||
| 1916 | + // Get server information | ||
| 1917 | + struct addrinfo* servinfo; | ||
| 1918 | + if (getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo) == 0) { | ||
| 1919 | + | ||
| 1920 | + // Loop through all the results and connect to the first we can | ||
| 1921 | + for (struct addrinfo* ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) { | ||
| 1922 | + | ||
| 1923 | + // Create socket | ||
| 1924 | + socket = ::socket(ptr->ai_family, | ||
| 1925 | + ptr->ai_socktype, | ||
| 1926 | + ptr->ai_protocol); | ||
| 1927 | + | ||
| 1928 | + // Connect to socket if socket is valid | ||
| 1929 | + if (socket != -1) { | ||
| 1930 | + if (::connect(socket, | ||
| 1931 | + ptr->ai_addr, | ||
| 1932 | + ptr->ai_addrlen) == -1) { | ||
| 1933 | + close(socket); | ||
| 1934 | + socket = -1; | ||
| 1935 | + } | ||
| 1936 | + else { | ||
| 1937 | + // Socket connection successful, break now | ||
| 1938 | + break; | ||
| 1939 | + } | ||
| 1940 | + } | ||
| 1941 | + | ||
| 1942 | + } // endfor: looped through all results | ||
| 1943 | + | ||
| 1944 | + } // endif: server information was valid | ||
| 1945 | + | ||
| 1946 | + // Continue only if socket is valid | ||
| 1947 | + if (socket != -1) { | ||
| 1948 | + | ||
| 1949 | + // Determine notification length | ||
| 1950 | + int length = notification.length(); | ||
| 1951 | + | ||
| 1952 | + // Set prefix | ||
| 1953 | + std::string prefix = "POST /"+path+" HTTP/1.0\n" | ||
| 1954 | + "Connection: close\n" | ||
| 1955 | + "User-Agent: GammaLib\n" | ||
| 1956 | + "Content-Type: text/xml\n" | ||
| 1957 | + "Content-Length: "+gammalib::str(length)+"\n\n"; | ||
| 1958 | + | ||
| 1959 | + // Build post string | ||
| 1960 | + std::string post = prefix + notification; | ||
| 1961 | + | ||
| 1962 | + // Dump message to post | ||
| 1963 | + #if defined(G_SHOW_MESSAGE) | ||
| 1964 | + std::cout << std::endl; | ||
| 1965 | + std::cout << "GVOHub sends following notification:" << std::endl; | ||
| 1966 | + std::cout << "====================================" << std::endl; | ||
| 1967 | + std::cout << post << std::endl; | ||
| 1968 | + #endif | ||
| 1969 | + | ||
| 1970 | + // Send content to socket | ||
| 1971 | + bool done = false; | ||
| 1972 | + do { | ||
| 1973 | + int length = post.length() + 1; // +1 for terminating 0 | ||
| 1974 | + int sent_length = send(socket, post.c_str(), length, 0); | ||
| 1975 | + if (sent_length < length) { | ||
| 1976 | + post = post.substr(sent_length, std::string::npos); | ||
| 1977 | + } | ||
| 1978 | + else { | ||
| 1979 | + done = true; | ||
| 1980 | + } | ||
| 1981 | + } while (!done); | ||
| 1982 | + | ||
| 1983 | + /* | ||
| 1984 | + // Declare response | ||
| 1985 | + std::string response = ""; | ||
| 1986 | + | ||
| 1987 | + // Read buffer until it is empty | ||
| 1988 | + char buffer[1001]; | ||
| 1989 | + int timeout = 1000; // Initial timeout is 1 sec | ||
| 1990 | + int n = 0; | ||
| 1991 | + do { | ||
| 1992 | + n = gammalib::recv(socket, buffer, 1000, 0, timeout); | ||
| 1993 | + if (n > 0) { | ||
| 1994 | + buffer[n+1] = '\0'; | ||
| 1995 | + response.append(std::string(buffer)); | ||
| 1996 | + } | ||
| 1997 | + timeout = 10; // The timeout now is 0.01 sec | ||
| 1998 | + } while (n > 0); | ||
| 1999 | + */ | ||
| 2000 | + | ||
| 2001 | + // Close socket | ||
| 2002 | + close(socket); | ||
| 2003 | + | ||
| 2004 | + } | ||
| 2005 | + | ||
| 2006 | + // Return | ||
| 2007 | + return; | ||
| 2008 | +} | ||
| 2009 | + | ||
| 2010 | + | ||
| 2011 | +/***********************************************************************//** | ||
| 2012 | + * @brief Generates random string of characters | ||
| 2013 | + * | ||
| 2014 | + * @param[in] length Length of random string | ||
| 2015 | + ***************************************************************************/ | ||
| 2016 | +std::string GVOHub::random_string(const size_t& length) const | ||
| 2017 | +{ | ||
| 2018 | + srand(time(0)); | ||
| 2019 | + std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
| 2020 | + int pos; | ||
| 2021 | + while(str.size() != length) { | ||
| 2022 | + pos = ((rand() % (str.size() - 1))); | ||
| 2023 | + str.erase (pos, 1); | ||
| 2024 | + } | ||
| 2025 | + | ||
| 2026 | + // Return string | ||
| 2027 | + return str; | ||
| 2028 | +} | ||
| 2029 | +/***********************************************************************//** | ||
| 2030 | + * @brief Extract mtype from XML request | ||
| 2031 | + * | ||
| 2032 | + * @param[in] xml XML message sent by client. | ||
| 2033 | + * | ||
| 2034 | + * Extracts the mtype identifying calling message from the XML request. | ||
| 2035 | + ***************************************************************************/ | ||
| 2036 | +std::string GVOHub::get_mtype(const GXml& xml) const | ||
| 2037 | +{ | ||
| 2038 | + // Header | ||
| 2039 | + #if defined(G_CONSOLE_DUMP) | ||
| 2040 | + std::cout << "GVOHub::get_mtype" << std::endl; | ||
| 2041 | + #endif | ||
| 2042 | + | ||
| 2043 | + // Initialise response | ||
| 2044 | + std::string client_key = ""; | ||
| 2045 | + | ||
| 2046 | + // Get the client's private key | ||
| 2047 | + const GXmlNode* node = xml.element("methodCall > params > param > value"); | ||
| 2048 | + if (node != NULL) { | ||
| 2049 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 2050 | + if (text != NULL) { | ||
| 2051 | + client_key = text->text(); | ||
| 2052 | + } | ||
| 2053 | + } | ||
| 2054 | + | ||
| 2055 | + // Return key | ||
| 2056 | + return client_key; | ||
| 2057 | +} | ||
| 2058 | +/***********************************************************************//** | ||
| 2059 | + * @brief Extract client destination from XML request | ||
| 2060 | + * | ||
| 2061 | + * @param[in] xml XML message sent by client. | ||
| 2062 | + * | ||
| 2063 | + * Extracts identifier of destination client from the XML request. | ||
| 2064 | + ***************************************************************************/ | ||
| 2065 | +std::string GVOHub::get_destination(const GXml& xml) const | ||
| 2066 | +{ | ||
| 2067 | + // Header | ||
| 2068 | + #if defined(G_CONSOLE_DUMP) | ||
| 2069 | + std::cout << "GVOHub::get_mtype" << std::endl; | ||
| 2070 | + #endif | ||
| 2071 | + | ||
| 2072 | + // Initialise response | ||
| 2073 | + std::string client_key = ""; | ||
| 2074 | + | ||
| 2075 | + // Get the client's private key | ||
| 2076 | + const GXmlNode* node = xml.element("methodCall > params > param > value"); | ||
| 2077 | + if (node != NULL) { | ||
| 2078 | + const GXmlText* text = static_cast<const GXmlText*>((*node)[0]); | ||
| 2079 | + if (text != NULL) { | ||
| 2080 | + client_key = text->text(); | ||
| 2081 | + } | ||
| 2082 | + } | ||
| 2083 | + | ||
| 2084 | + // Return key | ||
| 2085 | + return client_key; | ||
| 2086 | +} |
src/vo/GVOTable.cpp
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOTable.cpp - VO Table composition class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2015 by Thierry Louge * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOTable.cpp | ||
| 23 | + * @brief VO Table composition class | ||
| 24 | + * @author Thierry Louge | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#endif | ||
| 31 | +#include <cstdlib> // std::getenv() function | ||
| 32 | +#include <cstdio> // std::fopen(), etc. functions | ||
| 33 | +#include <cstring> // std::memset() function | ||
| 34 | +#include <csignal> // signal() function | ||
| 35 | +#include <cerrno> // errno | ||
| 36 | +#include <unistd.h> // close() function | ||
| 37 | +#include <netdb.h> // getaddrinfo() function | ||
| 38 | +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons | ||
| 39 | +#include <fstream> | ||
| 40 | +#include <sys/shm.h> | ||
| 41 | +#include <sys/socket.h> // socket(), connect() functions | ||
| 42 | +#include <sys/wait.h> // waitpid() function | ||
| 43 | +#include <arpa/inet.h> // inet_addr() function | ||
| 44 | +#include "GVOTable.hpp" | ||
| 45 | +#include "GException.hpp" | ||
| 46 | +#include "GTools.hpp" | ||
| 47 | + | ||
| 48 | +/* __ Method name definitions ____________________________________________ */ | ||
| 49 | + | ||
| 50 | +/* __ Macros _____________________________________________________________ */ | ||
| 51 | + | ||
| 52 | +/* __ Coding definitions _________________________________________________ */ | ||
| 53 | + | ||
| 54 | +/* __ Debug definitions __________________________________________________ */ | ||
| 55 | +//#define G_CONSOLE_DUMP | ||
| 56 | +#define G_SHOW_MESSAGE | ||
| 57 | + | ||
| 58 | + | ||
| 59 | +/*========================================================================== | ||
| 60 | + = = | ||
| 61 | + = Constructors/destructors = | ||
| 62 | + = = | ||
| 63 | + ==========================================================================*/ | ||
| 64 | + | ||
| 65 | +/***********************************************************************//** | ||
| 66 | + * @brief Void constructor | ||
| 67 | + ***************************************************************************/ | ||
| 68 | +GVOTable::GVOTable(void) | ||
| 69 | +{ | ||
| 70 | + // Initialise members | ||
| 71 | + init_members(); | ||
| 72 | + | ||
| 73 | + // Return | ||
| 74 | + return; | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +/***********************************************************************//** | ||
| 79 | + * @brief Copy constructor | ||
| 80 | + * | ||
| 81 | + * @param[in] VOTable | ||
| 82 | + ***************************************************************************/ | ||
| 83 | +GVOTable::GVOTable(const GVOTable& votable) | ||
| 84 | +{ | ||
| 85 | + // Initialise members | ||
| 86 | + init_members(); | ||
| 87 | + | ||
| 88 | + // Copy members | ||
| 89 | + copy_members(votable); | ||
| 90 | + | ||
| 91 | + // Return | ||
| 92 | + return; | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | + | ||
| 96 | +/***********************************************************************//** | ||
| 97 | + * @brief Destructor | ||
| 98 | + ***************************************************************************/ | ||
| 99 | +GVOTable::~GVOTable(void) | ||
| 100 | +{ | ||
| 101 | + // Free members | ||
| 102 | + free_members(); | ||
| 103 | + | ||
| 104 | + // Return | ||
| 105 | + return; | ||
| 106 | +} | ||
| 107 | + | ||
| 108 | + | ||
| 109 | +/*========================================================================== | ||
| 110 | + = = | ||
| 111 | + = Operators = | ||
| 112 | + = = | ||
| 113 | + ==========================================================================*/ | ||
| 114 | + | ||
| 115 | +/***********************************************************************//** | ||
| 116 | + * @brief Assignment operator | ||
| 117 | + * | ||
| 118 | + * @param[in] VO table. | ||
| 119 | + * @return VO table. | ||
| 120 | + ***************************************************************************/ | ||
| 121 | +GVOTable& GVOTable::operator=(const GVOTable& votable) | ||
| 122 | +{ | ||
| 123 | + // Execute only if object is not identical | ||
| 124 | + if (this != &votable) { | ||
| 125 | + | ||
| 126 | + // Free members | ||
| 127 | + free_members(); | ||
| 128 | + | ||
| 129 | + // Initialise members | ||
| 130 | + init_members(); | ||
| 131 | + | ||
| 132 | + // Copy members | ||
| 133 | + copy_members(votable); | ||
| 134 | + | ||
| 135 | + } // endif: object was not identical | ||
| 136 | + | ||
| 137 | + // Return | ||
| 138 | + return *this; | ||
| 139 | +} | ||
| 140 | + | ||
| 141 | + | ||
| 142 | +/*========================================================================== | ||
| 143 | + = = | ||
| 144 | + = Public methods = | ||
| 145 | + = = | ||
| 146 | + ==========================================================================*/ | ||
| 147 | + | ||
| 148 | +/***********************************************************************//** | ||
| 149 | + * @brief Clear object. | ||
| 150 | + * | ||
| 151 | + * Reset object to a clean initial state. | ||
| 152 | + ***************************************************************************/ | ||
| 153 | +void GVOTable::clear(void) | ||
| 154 | +{ | ||
| 155 | + // Free members | ||
| 156 | + free_members(); | ||
| 157 | + | ||
| 158 | + // Initialise members | ||
| 159 | + init_members(); | ||
| 160 | + | ||
| 161 | + // Return | ||
| 162 | + return; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | + | ||
| 166 | +/***********************************************************************//** | ||
| 167 | + * @brief Clone object | ||
| 168 | + ***************************************************************************/ | ||
| 169 | +GVOTable* GVOTable::clone(void) const | ||
| 170 | +{ | ||
| 171 | + // Clone client | ||
| 172 | + return new GVOTable(*this); | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | + | ||
| 176 | +/***********************************************************************//** | ||
| 177 | + * @brief Print VO hub information | ||
| 178 | + * | ||
| 179 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 180 | + * @return String containing VO table information | ||
| 181 | + ***************************************************************************/ | ||
| 182 | +std::string GVOTable::print(const GChatter& chatter) const | ||
| 183 | +{ | ||
| 184 | + // Initialise result string | ||
| 185 | + std::string result; | ||
| 186 | + | ||
| 187 | + // Continue only if chatter is not silent | ||
| 188 | + if (chatter != SILENT) { | ||
| 189 | + | ||
| 190 | + // Append header | ||
| 191 | + result.append("=== GVOTable ==="); | ||
| 192 | + | ||
| 193 | + // Append table information | ||
| 194 | + | ||
| 195 | + } // endif: chatter was not silent | ||
| 196 | + | ||
| 197 | + // Return result | ||
| 198 | + return result; | ||
| 199 | +} | ||
| 200 | +/***********************************************************************//** | ||
| 201 | + * @brief Creates the VO table, fill it | ||
| 202 | + * | ||
| 203 | + * Implements IVOA standard <standard id> | ||
| 204 | + ***************************************************************************/ | ||
| 205 | +void GVOTable::create_votable(void) | ||
| 206 | +{ | ||
| 207 | + std::string header = ""; | ||
| 208 | + header.append("<?xml version=\"1.0\"?>\n"); | ||
| 209 | + header.append("<VOTABLE version=\"1.3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); | ||
| 210 | + header.append("xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\"\n"); | ||
| 211 | + //Change this with relevant datamodel | ||
| 212 | + header.append("xmlns:stc=\"http://www.ivoa.net/xml/STC/v1.30\">\n"); | ||
| 213 | + header.append("\t<RESOURCE name=\"GammalibSkymap\">\n"); | ||
| 214 | + header.append("\t\t<TABLE name=\"skymap\">\n"); | ||
| 215 | + header.append("\t\t\t<DESCRIPTION>Skymap coming from gammalib</DESCRIPTION>\n"); | ||
| 216 | + //Only for testing, we close the document. | ||
| 217 | + header.append("\t\t</TABLE>\n"); | ||
| 218 | + header.append("\t</RESOURCE>\n"); | ||
| 219 | + header.append("</VOTABLE>\n"); | ||
| 220 | + | ||
| 221 | + m_tablexml = GXml(header); | ||
| 222 | + m_tablexml.print(NORMAL,0); | ||
| 223 | + // Return | ||
| 224 | + return; | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | + | ||
| 228 | +/***********************************************************************//** | ||
| 229 | + * @brief Fills content of the VO table | ||
| 230 | + * | ||
| 231 | + * Implements IVOA standard <standard id> | ||
| 232 | + ***************************************************************************/ | ||
| 233 | +void GVOTable::fill_content(const std::string& data) const | ||
| 234 | +{ | ||
| 235 | + | ||
| 236 | + // Return | ||
| 237 | + return; | ||
| 238 | +} | ||
| 239 | + | ||
| 240 | +/*========================================================================== | ||
| 241 | + = = | ||
| 242 | + = Private methods = | ||
| 243 | + = = | ||
| 244 | + ==========================================================================*/ | ||
| 245 | + | ||
| 246 | +/***********************************************************************//** | ||
| 247 | + * @brief Initialise class members | ||
| 248 | + ***************************************************************************/ | ||
| 249 | +void GVOTable::init_members(void) | ||
| 250 | +{ | ||
| 251 | + // Initialise members | ||
| 252 | + | ||
| 253 | + // Return | ||
| 254 | + return; | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | + | ||
| 258 | +/***********************************************************************//** | ||
| 259 | + * @brief Copy class members | ||
| 260 | + * | ||
| 261 | + * @param[in] hub VO hub. | ||
| 262 | + ***************************************************************************/ | ||
| 263 | +void GVOTable::copy_members(const GVOTable& hub) | ||
| 264 | +{ | ||
| 265 | + // Copy members | ||
| 266 | + | ||
| 267 | + // Return | ||
| 268 | + return; | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | + | ||
| 272 | +/***********************************************************************//** | ||
| 273 | + * @brief Delete class members | ||
| 274 | + ***************************************************************************/ | ||
| 275 | +void GVOTable::free_members(void) | ||
| 276 | +{ | ||
| 277 | + | ||
| 278 | + // Return | ||
| 279 | + return; | ||
| 280 | +} | ||
| 281 | + |
src/vo/GVOTable.cpp~
0 → 100644
| 1 | +/*************************************************************************** | ||
| 2 | + * GVOTable.cpp - VO Table composition class * | ||
| 3 | + * ----------------------------------------------------------------------- * | ||
| 4 | + * copyright (C) 2015 by Thierry Louge * | ||
| 5 | + * ----------------------------------------------------------------------- * | ||
| 6 | + * * | ||
| 7 | + * This program is free software: you can redistribute it and/or modify * | ||
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 19 | + * * | ||
| 20 | + ***************************************************************************/ | ||
| 21 | +/** | ||
| 22 | + * @file GVOTable.cpp | ||
| 23 | + * @brief VO Table composition class | ||
| 24 | + * @author Thierry Louge | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +/* __ Includes ___________________________________________________________ */ | ||
| 28 | +#ifdef HAVE_CONFIG_H | ||
| 29 | +#include <config.h> | ||
| 30 | +#endif | ||
| 31 | +#include <cstdlib> // std::getenv() function | ||
| 32 | +#include <cstdio> // std::fopen(), etc. functions | ||
| 33 | +#include <cstring> // std::memset() function | ||
| 34 | +#include <csignal> // signal() function | ||
| 35 | +#include <cerrno> // errno | ||
| 36 | +#include <unistd.h> // close() function | ||
| 37 | +#include <netdb.h> // getaddrinfo() function | ||
| 38 | +#include <netinet/in.h> // sockaddr_in, INADDR_ANY, htons | ||
| 39 | +#include <fstream> | ||
| 40 | +#include <sys/shm.h> | ||
| 41 | +#include <sys/socket.h> // socket(), connect() functions | ||
| 42 | +#include <sys/wait.h> // waitpid() function | ||
| 43 | +#include <arpa/inet.h> // inet_addr() function | ||
| 44 | +#include "GVOTable.hpp" | ||
| 45 | +#include "GException.hpp" | ||
| 46 | +#include "GTools.hpp" | ||
| 47 | + | ||
| 48 | +/* __ Method name definitions ____________________________________________ */ | ||
| 49 | + | ||
| 50 | +/* __ Macros _____________________________________________________________ */ | ||
| 51 | + | ||
| 52 | +/* __ Coding definitions _________________________________________________ */ | ||
| 53 | + | ||
| 54 | +/* __ Debug definitions __________________________________________________ */ | ||
| 55 | +//#define G_CONSOLE_DUMP | ||
| 56 | +#define G_SHOW_MESSAGE | ||
| 57 | + | ||
| 58 | + | ||
| 59 | +/*========================================================================== | ||
| 60 | + = = | ||
| 61 | + = Constructors/destructors = | ||
| 62 | + = = | ||
| 63 | + ==========================================================================*/ | ||
| 64 | + | ||
| 65 | +/***********************************************************************//** | ||
| 66 | + * @brief Void constructor | ||
| 67 | + ***************************************************************************/ | ||
| 68 | +GVOTable::GVOTable(void) | ||
| 69 | +{ | ||
| 70 | + // Initialise members | ||
| 71 | + init_members(); | ||
| 72 | + | ||
| 73 | + // Return | ||
| 74 | + return; | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +/***********************************************************************//** | ||
| 79 | + * @brief Copy constructor | ||
| 80 | + * | ||
| 81 | + * @param[in] VOTable | ||
| 82 | + ***************************************************************************/ | ||
| 83 | +GVOTable::GVOTable(const GVOTable& votable) | ||
| 84 | +{ | ||
| 85 | + // Initialise members | ||
| 86 | + init_members(); | ||
| 87 | + | ||
| 88 | + // Copy members | ||
| 89 | + copy_members(votable); | ||
| 90 | + | ||
| 91 | + // Return | ||
| 92 | + return; | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | + | ||
| 96 | +/***********************************************************************//** | ||
| 97 | + * @brief Destructor | ||
| 98 | + ***************************************************************************/ | ||
| 99 | +GVOTable::~GVOTable(void) | ||
| 100 | +{ | ||
| 101 | + // Free members | ||
| 102 | + free_members(); | ||
| 103 | + | ||
| 104 | + // Return | ||
| 105 | + return; | ||
| 106 | +} | ||
| 107 | + | ||
| 108 | + | ||
| 109 | +/*========================================================================== | ||
| 110 | + = = | ||
| 111 | + = Operators = | ||
| 112 | + = = | ||
| 113 | + ==========================================================================*/ | ||
| 114 | + | ||
| 115 | +/***********************************************************************//** | ||
| 116 | + * @brief Assignment operator | ||
| 117 | + * | ||
| 118 | + * @param[in] VO table. | ||
| 119 | + * @return VO table. | ||
| 120 | + ***************************************************************************/ | ||
| 121 | +GVOTable& GVOTable::operator=(const GVOTable& votable) | ||
| 122 | +{ | ||
| 123 | + // Execute only if object is not identical | ||
| 124 | + if (this != &votable) { | ||
| 125 | + | ||
| 126 | + // Free members | ||
| 127 | + free_members(); | ||
| 128 | + | ||
| 129 | + // Initialise members | ||
| 130 | + init_members(); | ||
| 131 | + | ||
| 132 | + // Copy members | ||
| 133 | + copy_members(votable); | ||
| 134 | + | ||
| 135 | + } // endif: object was not identical | ||
| 136 | + | ||
| 137 | + // Return | ||
| 138 | + return *this; | ||
| 139 | +} | ||
| 140 | + | ||
| 141 | + | ||
| 142 | +/*========================================================================== | ||
| 143 | + = = | ||
| 144 | + = Public methods = | ||
| 145 | + = = | ||
| 146 | + ==========================================================================*/ | ||
| 147 | + | ||
| 148 | +/***********************************************************************//** | ||
| 149 | + * @brief Clear object. | ||
| 150 | + * | ||
| 151 | + * Reset object to a clean initial state. | ||
| 152 | + ***************************************************************************/ | ||
| 153 | +void GVOTable::clear(void) | ||
| 154 | +{ | ||
| 155 | + // Free members | ||
| 156 | + free_members(); | ||
| 157 | + | ||
| 158 | + // Initialise members | ||
| 159 | + init_members(); | ||
| 160 | + | ||
| 161 | + // Return | ||
| 162 | + return; | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | + | ||
| 166 | +/***********************************************************************//** | ||
| 167 | + * @brief Clone object | ||
| 168 | + ***************************************************************************/ | ||
| 169 | +GVOTable* GVOTable::clone(void) const | ||
| 170 | +{ | ||
| 171 | + // Clone client | ||
| 172 | + return new GVOTable(*this); | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | + | ||
| 176 | +/***********************************************************************//** | ||
| 177 | + * @brief Print VO hub information | ||
| 178 | + * | ||
| 179 | + * @param[in] chatter Chattiness (defaults to NORMAL). | ||
| 180 | + * @return String containing VO table information | ||
| 181 | + ***************************************************************************/ | ||
| 182 | +std::string GVOTable::print(const GChatter& chatter) const | ||
| 183 | +{ | ||
| 184 | + // Initialise result string | ||
| 185 | + std::string result; | ||
| 186 | + | ||
| 187 | + // Continue only if chatter is not silent | ||
| 188 | + if (chatter != SILENT) { | ||
| 189 | + | ||
| 190 | + // Append header | ||
| 191 | + result.append("=== GVOTable ==="); | ||
| 192 | + | ||
| 193 | + // Append table information | ||
| 194 | + | ||
| 195 | + } // endif: chatter was not silent | ||
| 196 | + | ||
| 197 | + // Return result | ||
| 198 | + return result; | ||
| 199 | +} | ||
| 200 | +/***********************************************************************//** | ||
| 201 | + * @brief Creates the VO table, fill it | ||
| 202 | + * | ||
| 203 | + * Implements IVOA standard <standard id> | ||
| 204 | + ***************************************************************************/ | ||
| 205 | +void GVOTable::create_votable(void) | ||
| 206 | +{ | ||
| 207 | + std::string header = ""; | ||
| 208 | + header.append("<?xml version=\"1.0\"?>\n"); | ||
| 209 | + header.append("<VOTABLE version=\"1.3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); | ||
| 210 | + header.append("xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\"\n"); | ||
| 211 | + //Change this with relevant datamodel | ||
| 212 | + header.append("xmlns:stc=\"http://www.ivoa.net/xml/STC/v1.30\">\n"); | ||
| 213 | + header.append("\t<RESOURCE name=\"GammalibSkymap\">\n"); | ||
| 214 | + header.append("\t\t<TABLE name=\"skymap\">\n"); | ||
| 215 | + header.append("\t\t\t<DESCRIPTION>Sloaded_map = skymap.load("kymap coming from gammalib</DESCRIPTION>\n"); | ||
| 216 | + //Only for testing, we close the document. | ||
| 217 | + header.append("\t\t</TABLE>\n"); | ||
| 218 | + header.append("\t</RESOURCE>\n"); | ||
| 219 | + header.append("</VOTABLE>\n"); | ||
| 220 | + | ||
| 221 | + m_tablexml = GXml(header); | ||
| 222 | + m_tablexml.print(NORMAL,0); | ||
| 223 | + // Return | ||
| 224 | + return; | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | + | ||
| 228 | +/***********************************************************************//** | ||
| 229 | + * @brief Fills content of the VO table | ||
| 230 | + * | ||
| 231 | + * Implements IVOA standard <standard id> | ||
| 232 | + ***************************************************************************/ | ||
| 233 | +void GVOTable::fill_content(const std::string& data) const | ||
| 234 | +{ | ||
| 235 | + | ||
| 236 | + // Return | ||
| 237 | + return; | ||
| 238 | +} | ||
| 239 | + | ||
| 240 | +/*========================================================================== | ||
| 241 | + = = | ||
| 242 | + = Private methods = | ||
| 243 | + = = | ||
| 244 | + ==========================================================================*/ | ||
| 245 | + | ||
| 246 | +/***********************************************************************//** | ||
| 247 | + * @brief Initialise class members | ||
| 248 | + ***************************************************************************/ | ||
| 249 | +void GVOTable::init_members(void) | ||
| 250 | +{ | ||
| 251 | + // Initialise members | ||
| 252 | + | ||
| 253 | + // Return | ||
| 254 | + return; | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | + | ||
| 258 | +/***********************************************************************//** | ||
| 259 | + * @brief Copy class members | ||
| 260 | + * | ||
| 261 | + * @param[in] hub VO hub. | ||
| 262 | + ***************************************************************************/ | ||
| 263 | +void GVOTable::copy_members(const GVOTable& hub) | ||
| 264 | +{ | ||
| 265 | + // Copy members | ||
| 266 | + | ||
| 267 | + // Return | ||
| 268 | + return; | ||
| 269 | +} | ||
| 270 | + | ||
| 271 | + | ||
| 272 | +/***********************************************************************//** | ||
| 273 | + * @brief Delete class members | ||
| 274 | + ***************************************************************************/ | ||
| 275 | +void GVOTable::free_members(void) | ||
| 276 | +{ | ||
| 277 | + | ||
| 278 | + // Return | ||
| 279 | + return; | ||
| 280 | +} | ||
| 281 | + |
src/vo/Makefile.am
| @@ -7,7 +7,8 @@ INCLUDES = -I$(top_srcdir)/include \ | @@ -7,7 +7,8 @@ INCLUDES = -I$(top_srcdir)/include \ | ||
| 7 | 7 | ||
| 8 | # Define sources for this directory | 8 | # Define sources for this directory |
| 9 | sources = GVOClient.cpp \ | 9 | sources = GVOClient.cpp \ |
| 10 | - GVOHub.cpp | 10 | + GVOHub.cpp \ |
| 11 | + GVOTable.cpp | ||
| 11 | 12 | ||
| 12 | # Build libtool library | 13 | # Build libtool library |
| 13 | noinst_LTLIBRARIES = libvo.la | 14 | noinst_LTLIBRARIES = libvo.la |