1 /* $Id: nc_utils.cpp 542160 2017-07-27 14:36:24Z gouriano $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Pavel Ivanov
27 *
28 */
29
30 #include "nc_pch.hpp"
31
32 #include "nc_utils.hpp"
33
34
35 BEGIN_NCBI_SCOPE;
36
37
38 static
39 map<EHTTPStatus, string> s_MsgForStatus;
40 static
41 map<string, EHTTPStatus> s_StatusForMsg;
42
43
44 struct SStatusMsg
45 {
46 EHTTPStatus status;
47 const char* msg;
48 };
49
50
51 static string s_UnkStatus = "ERR: Unknown status";
52 static SStatusMsg s_StatusMessages[] =
53 {
54 {eStatus_JustStarted, "ERR:Caching is not completed"},
55 {eStatus_Disabled, "ERR:Cache is disabled"},
56 {eStatus_NotAllowed, "ERR:Password in the command doesn't match server settings"},
57 {eStatus_NoDiskSpace, "ERR:Not enough disk space"},
58 {eStatus_BadPassword, "ERR:Access denied."},
59 {eStatus_NotFound, "ERR:BLOB not found."},
60 {eStatus_CondFailed, "ERR:Precondition failed"},
61 {eStatus_NoImpl, "ERR:Not implemented"},
62 {eStatus_ShuttingDown,"ERR:Service unavailable"},
63 {eStatus_BlobTooBig, "ERR:Blob size exceeds the allowed maximum"},
64 {eStatus_NeedAdmin, "ERR:Command requires administrative privileges"},
65 {eStatus_CmdAborted, "ERR:Stale synchronization"},
66 {eStatus_PrematureClose, "ERR:Connection closed too early"},
67 {eStatus_CmdTimeout, "ERR:Command timeout"},
68 {eStatus_BadPeer, "ERR:Protocol error"}
69 };
70
71
72
73 void
InitClientMessages(void)74 InitClientMessages(void)
75 {
76 size_t num_elems = sizeof(s_StatusMessages) / sizeof(s_StatusMessages[0]);
77 for (size_t i = 0; i < num_elems; ++i) {
78 SStatusMsg& stat_msg = s_StatusMessages[i];
79 s_MsgForStatus[stat_msg.status] = stat_msg.msg;
80 s_StatusForMsg[stat_msg.msg] = stat_msg.status;
81 }
82 }
83
GetStatusByMessage(const string & msg,EHTTPStatus def)84 EHTTPStatus GetStatusByMessage(const string& msg, EHTTPStatus def)
85 {
86 if (!msg.empty() && NStr::StartsWith(msg, "ERR:")) {
87 for (map<string, EHTTPStatus>::const_iterator i = s_StatusForMsg.begin();
88 i != s_StatusForMsg.end(); ++i) {
89 if (NStr::StartsWith(msg, i->first)) {
90 return i->second;
91 }
92 }
93 }
94 return def;
95 }
96
GetMessageByStatus(EHTTPStatus sts)97 const string& GetMessageByStatus(EHTTPStatus sts)
98 {
99 map<EHTTPStatus, string>::const_iterator m = s_MsgForStatus.find(sts);
100 return m != s_MsgForStatus.end() ? m->second : s_UnkStatus;
101 }
102
103 /////////////////////////////////////////////////////////////////////////////
104 // alerts
105
106
107 class NCAlertData
108 {
109 public:
NCAlertData(const string & name,const string & message)110 NCAlertData(const string& name, const string& message) :
111 m_LastDetectedTimestamp(CSrvTime::Current()),
112 m_Name(name), m_Message(message),
113 m_TotalCount(1), m_ThisCount(1), m_On(true) {
114 }
Update(const string & message)115 void Update(const string& message) {
116 m_LastDetectedTimestamp = CSrvTime::Current();
117 m_Message = message;
118 ++m_TotalCount;
119 m_On ? ++m_ThisCount : (m_ThisCount = 1);
120 m_On = true;
121 }
Acknowledge(const string & user)122 void Acknowledge(const string& user) {
123 m_AcknowledgedTimestamp = CSrvTime::Current();
124 m_User = user;
125 m_On = false;
126 }
IsOn(void) const127 bool IsOn(void) const {
128 return m_On;
129 }
130 void Report(CSrvSocketTask& task);
131 private:
132 CSrvTime m_LastDetectedTimestamp;
133 CSrvTime m_AcknowledgedTimestamp;
134 string m_Name;
135 string m_Message;
136 string m_User;
137 size_t m_TotalCount;
138 size_t m_ThisCount;
139 bool m_On;
140 };
141 static CMiniMutex s_Lock;
142 static map< CNCAlerts::EAlertType, NCAlertData > s_Alerts;
143
144
Report(CSrvSocketTask & task)145 void NCAlertData::Report(CSrvSocketTask& task)
146 {
147 char time_buf[50];
148 string is("\": "),iss("\": \""), eol(",\n\""), eos("\"");
149
150 task.WriteText("{\n");
151 task.WriteText(eos).WriteText("name" ).WriteText(iss).WriteText(m_Name).WriteText(eos);
152 task.WriteText(eol).WriteText("message" ).WriteText(iss).WriteText(m_Message).WriteText(eos);
153 m_LastDetectedTimestamp.Print(time_buf, CSrvTime::eFmtHumanSeconds);
154 task.WriteText(eol).WriteText("on" ).WriteText(is).WriteText(m_On? "true" : "false");
155 task.WriteText(eol).WriteText("count" ).WriteText(is).WriteNumber(m_ThisCount);
156 task.WriteText(eol).WriteText("lifetime_count" ).WriteText(is).WriteNumber(m_TotalCount);
157 task.WriteText(eol).WriteText("last_detected_time" ).WriteText(iss).WriteText(time_buf).WriteText(eos);
158 task.WriteText(eol).WriteText("acknowledged_time" );
159 if (m_AcknowledgedTimestamp.Compare(CSrvTime()) == 0) {
160 task.WriteText("\": null");
161 task.WriteText(eol).WriteText("user" ).WriteText("\": null");;
162 } else {
163 m_AcknowledgedTimestamp.Print(time_buf, CSrvTime::eFmtHumanSeconds);
164 task.WriteText(iss).WriteText(time_buf).WriteText(eos);
165 task.WriteText(eol).WriteText("user" ).WriteText(iss).WriteText(m_User).WriteText(eos);
166 }
167 task.WriteText("\n}");
168 }
169
Report(CSrvSocketTask & task,bool report_all)170 void CNCAlerts::Report(CSrvSocketTask& task, bool report_all)
171 {
172 s_Lock.Lock();
173 task.WriteText(",\n\"alerts\": [");
174 bool first = true;
175 for(map< EAlertType, NCAlertData >::iterator it = s_Alerts.begin(); it != s_Alerts.end(); ++it) {
176 if (report_all || it->second.IsOn()) {
177 if (!first) {
178 task.WriteText(",");
179 }
180 it->second.Report(task);
181 first = false;
182 }
183 }
184 task.WriteText("]");
185 s_Lock.Unlock();
186 }
187
Register(EAlertType alert_type,const string & message)188 void CNCAlerts::Register(EAlertType alert_type, const string& message)
189 {
190 s_Lock.Lock();
191 map< EAlertType, NCAlertData >::iterator found = s_Alerts.find(alert_type);
192 if (found != s_Alerts.end()) {
193 found->second.Update(message);
194 } else {
195 s_Alerts.insert( make_pair(alert_type, NCAlertData(x_TypeToId(alert_type), message)));
196 }
197 s_Lock.Unlock();
198 }
199
Acknowledge(const string & alert_id,const string & user)200 CNCAlerts::EAlertAckResult CNCAlerts::Acknowledge(const string& alert_id,
201 const string& user)
202 {
203 EAlertType alert_type = x_IdToType(alert_id);
204 s_Lock.Lock();
205 CNCAlerts::EAlertAckResult res = CNCAlerts::eNotFound;
206 map< EAlertType, NCAlertData >::iterator found = s_Alerts.find(alert_type);
207 if (found != s_Alerts.end()) {
208 found->second.Acknowledge(user);
209 res = CNCAlerts::eAcknowledged;
210 }
211 s_Lock.Unlock();
212 return res;
213 }
214
215
216 struct AlertToId
217 {
218 CNCAlerts::EAlertType type;
219 string id;
220 };
221
222 static const AlertToId s_alertToIdMap[] = {
223 {CNCAlerts::eUnknown, "Unknown"},
224 #ifdef _DEBUG
225 {CNCAlerts::eDebugOrphanRecordFound, "eDebugOrphanRecordFound"},
226 {CNCAlerts::eDebugOrphanRecordFound2, "eDebugOrphanRecordFound2"},
227 {CNCAlerts::eDebugWriteBlobInfoFailed, "eDebugWriteBlobInfoFailed"},
228 {CNCAlerts::eDebugReadBlobInfoFailed0, "eDebugReadBlobInfoFailed0"},
229 {CNCAlerts::eDebugReadBlobInfoFailed1, "eDebugReadBlobInfoFailed1"},
230 {CNCAlerts::eDebugReadBlobInfoFailed2, "eDebugReadBlobInfoFailed2"},
231 {CNCAlerts::eDebugUpdateUpCoords1, "eDebugUpdateUpCoords1"},
232 {CNCAlerts::eDebugUpdateUpCoords2, "eDebugUpdateUpCoords2"},
233 {CNCAlerts::eDebugWriteBlobInfo1, "eDebugWriteBlobInfo1"},
234 {CNCAlerts::eDebugWriteBlobInfo2, "eDebugWriteBlobInfo2"},
235 {CNCAlerts::eDebugWriteBlobInfo3, "eDebugWriteBlobInfo3"},
236 {CNCAlerts::eDebugWriteBlobInfo4, "eDebugWriteBlobInfo4"},
237 {CNCAlerts::eDebugMoveDataToGarbage, "eDebugMoveDataToGarbage"},
238 {CNCAlerts::eDebugReadMapInfo1, "eDebugReadMapInfo1"},
239 {CNCAlerts::eDebugReadMapInfo2, "eDebugReadMapInfo2"},
240 {CNCAlerts::eDebugReadChunkData1, "eDebugReadChunkData1"},
241 {CNCAlerts::eDebugReadChunkData2, "eDebugReadChunkData2"},
242 {CNCAlerts::eDebugReadChunkData3, "eDebugReadChunkData3"},
243 {CNCAlerts::eDebugReadChunkData4, "eDebugReadChunkData4"},
244 {CNCAlerts::eDebugDeleteNextData1, "eDebugDeleteNextData1"},
245 {CNCAlerts::eDebugDeleteNextData2, "eDebugDeleteNextData2"},
246 {CNCAlerts::eDebugDeleteVersionData, "eDebugDeleteVersionData"},
247 {CNCAlerts::eDebugSaveOneMapImpl1, "eDebugSaveOneMapImpl1"},
248 {CNCAlerts::eDebugSaveOneMapImpl2, "eDebugSaveOneMapImpl2"},
249 {CNCAlerts::eDebugWriteChunkData1, "eDebugWriteChunkData1"},
250 {CNCAlerts::eDebugWriteChunkData2, "eDebugWriteChunkData2"},
251 {CNCAlerts::eDebugMoveRecord0, "eDebugMoveRecord0"},
252 {CNCAlerts::eDebugMoveRecord1, "eDebugMoveRecord1"},
253 {CNCAlerts::eDebugMoveRecord2, "eDebugMoveRecord2"},
254 {CNCAlerts::eDebugMoveRecord3, "eDebugMoveRecord3"},
255 {CNCAlerts::eDebugReleaseCacheData1, "eDebugReleaseCacheData1"},
256 {CNCAlerts::eDebugReleaseCacheData2, "eDebugReleaseCacheData2"},
257 {CNCAlerts::eDebugDeleteFile, "eDebugDeleteFile"},
258 {CNCAlerts::eDebugDeleteSNCBlobVerData, "eDebugDeleteSNCBlobVerData"},
259 {CNCAlerts::eDebugDeleteCNCBlobVerManager, "eDebugDeleteCNCBlobVerManager"},
260 {CNCAlerts::eDebugExtraWrite, "eDebugExtraWrite"},
261 {CNCAlerts::eDebugCacheDeleted1, "eDebugCacheDeleted1"},
262 {CNCAlerts::eDebugCacheDeleted2, "eDebugCacheDeleted2"},
263 {CNCAlerts::eDebugCacheDeleted3, "eDebugCacheDeleted3"},
264 {CNCAlerts::eDebugCacheDeleted4, "eDebugCacheDeleted4"},
265 {CNCAlerts::eDebugCacheFailedMgrAttach, "eDebugCacheFailedMgrAttach"},
266 {CNCAlerts::eDebugCacheFailedMgrDetach, "eDebugCacheFailedMgrDetach"},
267 {CNCAlerts::eDebugCacheWrongMgr, "eDebugCacheWrongMgr"},
268 {CNCAlerts::eDebugCacheWrong, "eDebugCacheWrong"},
269 {CNCAlerts::eDebugWrongCacheFound1, "eDebugWrongCacheFound1"},
270 {CNCAlerts::eDebugWrongCacheFound2, "eDebugWrongCacheFound2"},
271 {CNCAlerts::eDebugSyncAborted1, "eDebugSyncAborted1"},
272 {CNCAlerts::eDebugSyncAborted2, "eDebugSyncAborted2"},
273 {CNCAlerts::eDebugConnAdjusted1, "eDebugConnAdjusted1"},
274 {CNCAlerts::eDebugConnAdjusted2, "eDebugConnAdjusted2"},
275 {CNCAlerts::eDebugDbFileNotFound, "eDebugDbFileNotFound"},
276 #endif
277 {CNCAlerts::eStartupConfigChanged, "StartupConfigChanged"},
278 {CNCAlerts::ePidFileFailed, "PidFileFailed"},
279 {CNCAlerts::eStartAfterCrash, "StartAfterCrash"},
280 {CNCAlerts::eStorageReinit, "StorageReinit"},
281 {CNCAlerts::eAccessDenied, "AccessDenied"},
282 {CNCAlerts::eSyncFailed, "SyncFailed"},
283 {CNCAlerts::ePeerIpChanged, "PeerIpChanged"},
284 {CNCAlerts::eDiskSpaceNormal, "DiskSpaceNormal"},
285 {CNCAlerts::eDatabaseTooLarge, "DatabaseTooLarge"},
286 {CNCAlerts::eDatabaseOverLimit, "DatabaseOverLimit"},
287 {CNCAlerts::eDiskSpaceLow, "DiskSpaceLow"},
288 {CNCAlerts::eDiskSpaceCritical, "DiskSpaceCritical"}
289 };
290 static const size_t s_alertToIdMapSize = sizeof(s_alertToIdMap) / sizeof(AlertToId);
291
x_IdToType(const string & alert_id)292 CNCAlerts::EAlertType CNCAlerts::x_IdToType(const string& alert_id)
293 {
294 for (size_t k = 0; k < s_alertToIdMapSize; ++k) {
295 if (NStr::CompareNocase(alert_id, s_alertToIdMap[k].id) == 0)
296 return s_alertToIdMap[k].type;
297 }
298 return CNCAlerts::eUnknown;
299 }
300
x_TypeToId(CNCAlerts::EAlertType type)301 string CNCAlerts::x_TypeToId(CNCAlerts::EAlertType type)
302 {
303 for (size_t k = 0; k < s_alertToIdMapSize; ++k) {
304 if (s_alertToIdMap[k].type == type)
305 return s_alertToIdMap[k].id;
306 }
307 return "Unknown";
308 }
309
310 END_NCBI_SCOPE;
311