| 1 | // ************************************************************************** | 
|---|
| 2 | /** @class DimDescriptionService | 
|---|
| 3 |  | 
|---|
| 4 | @brief A DimService which broadcasts descriptions for services and commands | 
|---|
| 5 |  | 
|---|
| 6 | The DimDescriptionService creates a service with the name of the server like | 
|---|
| 7 | SERVER/SERVICE_DESC. This is meant in addition to the SERVICE_LIST service | 
|---|
| 8 | of each node to contain a description of the service and its arguments. | 
|---|
| 9 |  | 
|---|
| 10 | Assume you have created a service (or command) with the format I:2;F:1 | 
|---|
| 11 | a valid description string would look like | 
|---|
| 12 |  | 
|---|
| 13 | Description|int[addr]:Address range (from - to)|val[byte]:Value to be set | 
|---|
| 14 |  | 
|---|
| 15 | Description is a general description of the command or service itself, | 
|---|
| 16 | int and val are the names of the arguments (e.g. names of FITS columns), | 
|---|
| 17 | addr and byte have the meaning of a unit (e.g. unit of FITS column) | 
|---|
| 18 | and the text after the colon is a description of the arguments | 
|---|
| 19 | (e.g. comment of a FITS column). The description must not contain a | 
|---|
| 20 | line-break character \n. | 
|---|
| 21 |  | 
|---|
| 22 | You can omit either the name, the unit or the comment or any combination of them. | 
|---|
| 23 | The descriptions of the individual format strings are separated by a vertical line. | 
|---|
| 24 |  | 
|---|
| 25 | The description should contain as many descriptions as format chunks, e.g. | 
|---|
| 26 |  | 
|---|
| 27 | - I:1          should contain one description chunks | 
|---|
| 28 | - I:1;F:1      should contain two description chunks | 
|---|
| 29 | - I:2;F:1      should contain two description chunks | 
|---|
| 30 | - I:2;I:1;F:1  should contain three description chunks | 
|---|
| 31 |  | 
|---|
| 32 | */ | 
|---|
| 33 | // ************************************************************************** | 
|---|
| 34 | #include "DimDescriptionService.h" | 
|---|
| 35 |  | 
|---|
| 36 | #include <stdexcept> | 
|---|
| 37 |  | 
|---|
| 38 | #include "dis.hxx" | 
|---|
| 39 | #include "Time.h" | 
|---|
| 40 |  | 
|---|
| 41 | using namespace std; | 
|---|
| 42 |  | 
|---|
| 43 | DimService *DimDescriptionService::fService = 0; | 
|---|
| 44 | int         DimDescriptionService::fCount   = 0; | 
|---|
| 45 | std::string DimDescriptionService::fData    = ""; | 
|---|
| 46 |  | 
|---|
| 47 | // -------------------------------------------------------------------------- | 
|---|
| 48 | // | 
|---|
| 49 | //! When the constructor is first called, a service with the name | 
|---|
| 50 | //! SERVER/SERVICE_DESC is created. The server name SERVER is retrieved | 
|---|
| 51 | //! from DimServer::itsName. If DimServer::itsName is empty, the | 
|---|
| 52 | //! server name is extracted from the given name as the part before the | 
|---|
| 53 | //! first '/'. A string "name=format\n" is added to fData and stored | 
|---|
| 54 | //! in fDescription. | 
|---|
| 55 | //! | 
|---|
| 56 | //! A counter fCount for the number of instantiations is increased. | 
|---|
| 57 | //! | 
|---|
| 58 | //! @param name | 
|---|
| 59 | //!     The name of the service or command to be described, e.g. SERVER/COMMAND | 
|---|
| 60 | //! | 
|---|
| 61 | //! @param desc | 
|---|
| 62 | //!     A description string. For details see class reference | 
|---|
| 63 | //! | 
|---|
| 64 | //! @throws | 
|---|
| 65 | //!     If a server name couldn't be reliably determined a logic_error | 
|---|
| 66 | //!     exception is thrown; if the given description contains a '\n' | 
|---|
| 67 | //!     also a logic_error is thrown. | 
|---|
| 68 | // | 
|---|
| 69 | DimDescriptionService::DimDescriptionService(const std::string &name, const std::string &desc) | 
|---|
| 70 | { | 
|---|
| 71 | string server = DimServer::itsName ? DimServer::itsName : ""; | 
|---|
| 72 | if (server.empty()) | 
|---|
| 73 | { | 
|---|
| 74 | const size_t p = name.find_first_of('/'); | 
|---|
| 75 | if (p==string::npos) | 
|---|
| 76 | throw logic_error("Could not determine server name"); | 
|---|
| 77 |  | 
|---|
| 78 | server = name.substr(0, p); | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | if (desc.find_first_of('\n')!=string::npos) | 
|---|
| 82 | throw logic_error("Description for "+name+" contains '\\n'"); | 
|---|
| 83 |  | 
|---|
| 84 | if (!fService) | 
|---|
| 85 | { | 
|---|
| 86 | fService = new DimService((server+"/SERVICE_DESC").c_str(), const_cast<char*>("")); | 
|---|
| 87 | fData = | 
|---|
| 88 | server + "/SERVICE_DESC" | 
|---|
| 89 | "=Descriptions of services or commands and there arguments" | 
|---|
| 90 | "|Description[string]:For a detailed " | 
|---|
| 91 | "explanation of the descriptive string see the class reference " | 
|---|
| 92 | "of DimDescriptionService.\n" + | 
|---|
| 93 | server + "/CLIENT_LIST" | 
|---|
| 94 | "=Native Dim service: A list of all connected clients\n" + | 
|---|
| 95 | server + "/VERSION_NUMBER" | 
|---|
| 96 | "=Native Dim service: Version number of Dim in use" | 
|---|
| 97 | "|DimVer[int]:Version*100+Release (e.g. V19r17 = 1917)\n" + | 
|---|
| 98 | server + "/EXIT" | 
|---|
| 99 | "=This is a native Dim command: Exit program" | 
|---|
| 100 | "remotely. FACT++ programs use the given number as return code." | 
|---|
| 101 | "|Rc[int]:Return code, under normal circumstances this should be 0 or 1 (42 will call exit() directly, 0x42 will call abort() directly.\n" + | 
|---|
| 102 | server + "/SERVICE_LIST" | 
|---|
| 103 | "=Native Dim service: List of services, commands and formats" | 
|---|
| 104 | "|ServiceList[string]:For details see the Dim manual.\n"; | 
|---|
| 105 | } | 
|---|
| 106 |  | 
|---|
| 107 |  | 
|---|
| 108 | fCount++; | 
|---|
| 109 |  | 
|---|
| 110 | fDescription = name + '=' + desc; | 
|---|
| 111 |  | 
|---|
| 112 | if (fData.find(fDescription+'\n')!=std::string::npos) | 
|---|
| 113 | return; | 
|---|
| 114 |  | 
|---|
| 115 | fData += fDescription + '\n'; | 
|---|
| 116 |  | 
|---|
| 117 | const Time t; | 
|---|
| 118 | fService->setTimestamp(t.Time_t(), t.ms()); | 
|---|
| 119 | fService->setData(const_cast<char*>(fData.c_str())); | 
|---|
| 120 | fService->updateService(); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 |  | 
|---|
| 124 | // -------------------------------------------------------------------------- | 
|---|
| 125 | // | 
|---|
| 126 | //! If fDescription is found in fData it is removed from fData. | 
|---|
| 127 | //! The counter fCount is decreased and fService deleted if the counter | 
|---|
| 128 | //! reached 0. | 
|---|
| 129 | // | 
|---|
| 130 | DimDescriptionService::~DimDescriptionService() | 
|---|
| 131 | { | 
|---|
| 132 | const size_t pos = fData.find(fDescription+'\n'); | 
|---|
| 133 | if (pos!=std::string::npos) | 
|---|
| 134 | fData.replace(pos, fDescription.size()+1, ""); | 
|---|
| 135 |  | 
|---|
| 136 | if (--fCount>0) | 
|---|
| 137 | return; | 
|---|
| 138 |  | 
|---|
| 139 | delete fService; | 
|---|
| 140 | fService=0; | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | void DimDescribedService::setTime(const Time &t) | 
|---|
| 144 | { | 
|---|
| 145 | setTimestamp(t.Time_t(), t.ms()); | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | void DimDescribedService::setTime() | 
|---|
| 149 | { | 
|---|
| 150 | setTime(Time()); | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | int DimDescribedService::Update(const Time &t) | 
|---|
| 154 | { | 
|---|
| 155 | setTime(t); | 
|---|
| 156 | return updateService(); | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | int DimDescribedService::Update() | 
|---|
| 160 | { | 
|---|
| 161 | return Update(Time()); | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | int DimDescribedService::Update(const string &data) | 
|---|
| 165 | { | 
|---|
| 166 | return Update(data.data()); | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | int DimDescribedService::Update(const char *data) | 
|---|
| 170 | { | 
|---|
| 171 | DimService::setData(const_cast<char*>(data)); | 
|---|
| 172 | return Update(); | 
|---|
| 173 | } | 
|---|