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