1 /*  $Id: pubseq_gateway_utils.cpp 629837 2021-04-22 12:47:49Z ivanov $
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  * Authors: Sergey Satskiy
27  *
28  * File Description:
29  *
30  */
31 #include <ncbi_pch.hpp>
32 
33 #include <corelib/ncbistr.hpp>
34 #include <objects/seqloc/Seq_id.hpp>
35 
36 #include "pubseq_gateway_utils.hpp"
37 #include "psgs_request.hpp"
38 #include "psgs_reply.hpp"
39 
40 USING_NCBI_SCOPE;
41 USING_SCOPE(objects);
42 
43 
44 // see CXX-10728
45 // Need to replace the found accession with the seq_ids found accession
46 EPSGS_AccessionAdjustmentResult
AdjustAccession(shared_ptr<CPSGS_Request> request,shared_ptr<CPSGS_Reply> reply)47 SBioseqResolution::AdjustAccession(shared_ptr<CPSGS_Request>  request,
48                                    shared_ptr<CPSGS_Reply>  reply)
49 {
50     if (m_AdjustmentTried)
51         return m_AccessionAdjustmentResult;
52     m_AdjustmentTried = true;
53 
54     if (m_ResolutionResult != ePSGS_BioseqDB && m_ResolutionResult != ePSGS_BioseqCache) {
55         m_AdjustmentError = "BIOSEQ_INFO accession adjustment logic error. The "
56                             "data are not ready for adjustments.";
57         m_AccessionAdjustmentResult = ePSGS_LogicError;
58         return m_AccessionAdjustmentResult;
59     }
60 
61     auto    seq_id_type = m_BioseqInfo.GetSeqIdType();
62     if (m_BioseqInfo.GetVersion() > 0 && seq_id_type != CSeq_id::e_Gi) {
63         if (request->NeedTrace())
64             reply->SendTrace("No need to adjust accession",
65                              request->GetStartTimestamp());
66 
67         m_AccessionAdjustmentResult = ePSGS_NotRequired;
68         return m_AccessionAdjustmentResult;
69     }
70 
71     auto &    seq_ids = m_BioseqInfo.GetSeqIds();
72     for (const auto &  seq_id : seq_ids) {
73         if (get<0>(seq_id) == CSeq_id::e_Gi) {
74             string  orig_accession = m_BioseqInfo.GetAccession();
75             auto    orig_seq_id_type = m_BioseqInfo.GetSeqIdType();
76 
77             m_BioseqInfo.SetAccession(get<1>(seq_id));
78             m_BioseqInfo.SetSeqIdType(CSeq_id::e_Gi);
79 
80             seq_ids.erase(seq_id);
81             if (orig_seq_id_type != CSeq_id::e_Gi)
82                 seq_ids.insert(make_tuple(orig_seq_id_type, orig_accession));
83 
84             if (request->NeedTrace())
85                 reply->SendTrace("Accession adjusted with Gi",
86                                  request->GetStartTimestamp());
87 
88             m_AccessionAdjustmentResult = ePSGS_AdjustedWithGi;
89             return m_AccessionAdjustmentResult;
90         }
91     }
92 
93     if (seq_ids.empty()) {
94         m_AdjustmentError = "BIOSEQ_INFO data inconsistency. Accession " +
95                             m_BioseqInfo.GetAccession() + " needs to be "
96                             "adjusted but the seq_ids list is empty.";
97         m_AccessionAdjustmentResult = ePSGS_SeqIdsEmpty;
98         return m_AccessionAdjustmentResult;
99     }
100 
101     // Adjusted with any
102     string  orig_accession = m_BioseqInfo.GetAccession();
103     auto    orig_seq_id_type = m_BioseqInfo.GetSeqIdType();
104 
105     auto    first_seq_id = seq_ids.begin();
106     m_BioseqInfo.SetAccession(get<1>(*first_seq_id));
107     m_BioseqInfo.SetSeqIdType(get<0>(*first_seq_id));
108 
109     seq_ids.erase(*first_seq_id);
110     if (orig_seq_id_type != CSeq_id::e_Gi)
111         seq_ids.insert(make_tuple(orig_seq_id_type, orig_accession));
112 
113     if (request->NeedTrace())
114         reply->SendTrace("Accession adjusted with type " +
115                          to_string(m_BioseqInfo.GetSeqIdType()) +
116                          " (first from the seq_ids list)",
117                          request->GetStartTimestamp());
118 
119     m_AccessionAdjustmentResult = ePSGS_AdjustedWithAny;
120     return m_AccessionAdjustmentResult;
121 }
122 
123 
124 
125 static string   s_ProtocolPrefix = "\n\nPSG-Reply-Chunk: ";
126 
127 // Names
128 static string   s_ItemId = "item_id=";
129 static string   s_ItemType = "item_type=";
130 static string   s_ChunkType = "chunk_type=";
131 static string   s_Size = "size=";
132 static string   s_BlobChunk = "blob_chunk=";
133 static string   s_NChunks = "n_chunks=";
134 static string   s_Status = "status=";
135 static string   s_Code = "code=";
136 static string   s_Severity = "severity=";
137 static string   s_BlobId = "blob_id=";
138 static string   s_Fmt = "fmt=";
139 static string   s_NA = "na=";
140 static string   s_Reason = "reason=";
141 static string   s_NChunksOne = "n_chunks=1";
142 static string   s_ProcessorId = "processor_id=";
143 static string   s_Id2Chunk = "id2_chunk=";
144 static string   s_Id2Info = "id2_info=";
145 static string   s_LastModified = "last_modified=";
146 
147 // Fixed values
148 static string   s_BioseqInfo = "bioseq_info";
149 static string   s_BlobProp = "blob_prop";
150 static string   s_Data = "data";
151 static string   s_Reply = "reply";
152 static string   s_Blob = "blob";
153 static string   s_Meta = "meta";
154 static string   s_Message = "message";
155 static string   s_Protobuf = "protobuf";
156 static string   s_Json = "json";
157 static string   s_BioseqNA = "bioseq_na";
158 static string   s_Excluded = "excluded";
159 static string   s_InProgress = "inprogress";
160 static string   s_Sent = "sent";
161 static string   s_Processor = "processor";
162 static string   s_PublicComment = "public_comment";
163 
164 // Combinations
165 static string   s_AndSize = "&" + s_Size;
166 static string   s_AndStatus = "&" + s_Status;
167 static string   s_AndCode = "&" + s_Code;
168 static string   s_AndSeverity = "&" + s_Severity;
169 static string   s_AndNChunks = "&" + s_NChunks;
170 static string   s_AndBlobId = "&" + s_BlobId;
171 static string   s_AndBlobChunk = "&" + s_BlobChunk;
172 static string   s_AndNChunksOne = "&" + s_NChunksOne;
173 static string   s_AndReason = "&" + s_Reason;
174 static string   s_AndNA = "&" + s_NA;
175 static string   s_BioseqInfoItem = s_ItemType + s_BioseqInfo;
176 static string   s_AndBioseqInfoItem = "&" + s_BioseqInfoItem;
177 static string   s_BlobPropItem = s_ItemType + s_BlobProp;
178 static string   s_AndBlobPropItem = "&" + s_BlobPropItem;
179 static string   s_BioseqNAItem = s_ItemType + s_BioseqNA;
180 static string   s_AndBioseqNAItem = "&" + s_BioseqNAItem;
181 static string   s_BlobItem = s_ItemType + s_Blob;
182 static string   s_AndBlobItem = "&" + s_BlobItem;
183 static string   s_ReplyItem = s_ItemType + s_Reply;
184 static string   s_AndReplyItem = "&" + s_ReplyItem;
185 static string   s_ProcessorItem = s_ItemType + s_Processor;
186 static string   s_PublicCommentItem = s_ItemType + s_PublicComment;
187 static string   s_AndProcessorItem = "&" + s_ProcessorItem;
188 static string   s_AndPublicCommentItem = "&" + s_PublicCommentItem;
189 static string   s_AndProcessorId = "&" + s_ProcessorId;
190 static string   s_AndId2Chunk = "&" + s_Id2Chunk;
191 static string   s_AndId2Info = "&" + s_Id2Info;
192 static string   s_AndLastModified = "&" + s_LastModified;
193 
194 static string   s_DataChunk = s_ChunkType + s_Data;
195 static string   s_AndDataChunk = "&" + s_DataChunk;
196 static string   s_MetaChunk = s_ChunkType + s_Meta;
197 static string   s_AndMetaChunk = "&" + s_MetaChunk;
198 static string   s_MessageChunk = s_ChunkType + s_Message;
199 static string   s_AndMessageChunk = "&" + s_MessageChunk;
200 static string   s_FmtJson = s_Fmt + s_Json;
201 static string   s_AndFmtJson = "&" + s_FmtJson;
202 static string   s_FmtProtobuf = s_Fmt + s_Protobuf;
203 static string   s_AndFmtProtobuf = "&" + s_FmtProtobuf;
204 
205 static string   s_ReplyBegin = s_ProtocolPrefix + s_ItemId;
206 static string   s_ReplyCompletionFixedPart = s_ReplyBegin + "0&" +
207                                              s_ReplyItem + "&" +
208                                              s_MetaChunk + "&" + s_NChunks;
209 
210 
SeverityToLowerString(EDiagSev severity)211 static string SeverityToLowerString(EDiagSev  severity)
212 {
213     string  severity_as_string = CNcbiDiag::SeverityName(severity);
214     NStr::ToLower(severity_as_string);
215     return severity_as_string;
216 }
217 
218 
SkipReasonToString(EPSGS_BlobSkipReason skip_reason)219 static string SkipReasonToString(EPSGS_BlobSkipReason  skip_reason)
220 {
221     switch (skip_reason) {
222         case ePSGS_BlobExcluded:
223             return s_Excluded;
224         case ePSGS_BlobInProgress:
225             return s_InProgress;
226         case ePSGS_BlobSent:
227             return s_Sent;
228     }
229     return "UnknownSkipReason";
230 }
231 
232 
GetBioseqInfoHeader(size_t item_id,const string & processor_id,size_t bioseq_info_size,SPSGS_ResolveRequest::EPSGS_OutputFormat output_format)233 string  GetBioseqInfoHeader(size_t  item_id,
234                             const string &  processor_id,
235                             size_t  bioseq_info_size,
236                             SPSGS_ResolveRequest::EPSGS_OutputFormat  output_format)
237 {
238     // E.g. PSG-Reply-Chunk: item_id=1&processor_id=get+blob+proc&item_type=bioseq_info&chunk_type=data&size=450&fmt=protobuf
239     string      reply(s_ReplyBegin);
240 
241     reply.append(to_string(item_id))
242          .append(s_AndProcessorId)
243          .append(NStr::URLEncode(processor_id))
244          .append(s_AndBioseqInfoItem)
245          .append(s_AndDataChunk)
246          .append(s_AndSize)
247          .append(to_string(bioseq_info_size));
248     if (output_format == SPSGS_ResolveRequest::ePSGS_JsonFormat)
249         reply.append(s_AndFmtJson);
250     else
251         reply.append(s_AndFmtProtobuf);
252     return reply.append(1, '\n');
253 }
254 
255 
GetBioseqMessageHeader(size_t item_id,const string & processor_id,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)256 string  GetBioseqMessageHeader(size_t  item_id,
257                                const string &  processor_id,
258                                size_t  msg_size,
259                                CRequestStatus::ECode  status,
260                                int  code,
261                                EDiagSev  severity)
262 {
263     string      reply(s_ReplyBegin);
264 
265     return reply.append(to_string(item_id))
266                 .append(s_AndProcessorId)
267                 .append(NStr::URLEncode(processor_id))
268                 .append(s_AndBioseqInfoItem)
269                 .append(s_AndMessageChunk)
270                 .append(s_AndSize)
271                 .append(to_string(msg_size))
272                 .append(s_AndStatus)
273                 .append(to_string(static_cast<int>(status)))
274                 .append(s_AndCode)
275                 .append(to_string(code))
276                 .append(s_AndSeverity)
277                 .append(SeverityToLowerString(severity))
278                 .append(1, '\n');
279 }
280 
281 
GetBioseqCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)282 string  GetBioseqCompletionHeader(size_t  item_id,
283                                   const string &  processor_id,
284                                   size_t  chunk_count)
285 {
286     // E.g. PSG-Reply-Chunk: item_id=1&processor_id=get+blob+proc&item_type=bioseq_info&chunk_type=meta&n_chunks=1
287     string      reply(s_ReplyBegin);
288 
289     return reply.append(to_string(item_id))
290                 .append(s_AndProcessorId)
291                 .append(NStr::URLEncode(processor_id))
292                 .append(s_AndBioseqInfoItem)
293                 .append(s_AndMetaChunk)
294                 .append(s_AndNChunks)
295                 .append(to_string(chunk_count))
296                 .append(1, '\n');
297 }
298 
299 
GetBlobPropHeader(size_t item_id,const string & processor_id,const string & blob_id,size_t blob_prop_size,CBlobRecord::TTimestamp last_modified)300 string  GetBlobPropHeader(size_t  item_id,
301                           const string &  processor_id,
302                           const string &  blob_id,
303                           size_t  blob_prop_size,
304                           CBlobRecord::TTimestamp  last_modified)
305 {
306     string      reply(s_ReplyBegin);
307 
308     string      last_modified_part;
309     if (last_modified != -1)
310         last_modified_part.append(s_AndLastModified)
311                           .append(to_string(last_modified));
312 
313     return reply.append(to_string(item_id))
314                 .append(s_AndProcessorId)
315                 .append(NStr::URLEncode(processor_id))
316                 .append(s_AndBlobPropItem)
317                 .append(s_AndDataChunk)
318                 .append(s_AndSize)
319                 .append(to_string(blob_prop_size))
320                 .append(s_AndBlobId)
321                 .append(blob_id)
322                 .append(last_modified_part)
323                 .append(1, '\n');
324 }
325 
GetTSEBlobPropHeader(size_t item_id,const string & processor_id,int64_t id2_chunk,const string & id2_info,size_t blob_prop_size)326 string  GetTSEBlobPropHeader(size_t  item_id,
327                              const string &  processor_id,
328                              int64_t  id2_chunk,
329                              const string &  id2_info,
330                              size_t  blob_prop_size)
331 {
332     // E.g. PSG-Reply-Chunk: item_id=2&processor_id=get+blob+proc&item_type=blob_prop&chunk_type=data&size=550
333     string      reply(s_ReplyBegin);
334 
335     return reply.append(to_string(item_id))
336                 .append(s_AndProcessorId)
337                 .append(NStr::URLEncode(processor_id))
338                 .append(s_AndBlobPropItem)
339                 .append(s_AndDataChunk)
340                 .append(s_AndSize)
341                 .append(to_string(blob_prop_size))
342                 .append(s_AndId2Chunk)
343                 .append(to_string(id2_chunk))
344                 .append(s_AndId2Info)
345                 .append(id2_info)
346                 .append(1, '\n');
347 }
348 
349 
GetBlobPropMessageHeader(size_t item_id,const string & processor_id,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)350 string  GetBlobPropMessageHeader(size_t  item_id,
351                                  const string &  processor_id,
352                                  size_t  msg_size,
353                                  CRequestStatus::ECode  status,
354                                  int  code,
355                                  EDiagSev  severity)
356 {
357     string      reply(s_ReplyBegin);
358 
359     return reply.append(to_string(item_id))
360                 .append(s_AndProcessorId)
361                 .append(NStr::URLEncode(processor_id))
362                 .append(s_AndBlobPropItem)
363                 .append(s_AndMessageChunk)
364                 .append(s_AndSize)
365                 .append(to_string(msg_size))
366                 .append(s_AndStatus)
367                 .append(to_string(static_cast<int>(status)))
368                 .append(s_AndCode)
369                 .append(to_string(code))
370                 .append(s_AndSeverity)
371                 .append(SeverityToLowerString(severity))
372                 .append(1, '\n');
373 }
374 
375 
GetTSEBlobPropMessageHeader(size_t item_id,const string & processor_id,int64_t id2_chunk,const string & id2_info,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)376 string  GetTSEBlobPropMessageHeader(size_t  item_id,
377                                     const string &  processor_id,
378                                     int64_t  id2_chunk,
379                                     const string &  id2_info,
380                                     size_t  msg_size,
381                                     CRequestStatus::ECode  status,
382                                     int  code,
383                                     EDiagSev  severity)
384 {
385     string      reply(s_ReplyBegin);
386 
387     return reply.append(to_string(item_id))
388                 .append(s_AndProcessorId)
389                 .append(NStr::URLEncode(processor_id))
390                 .append(s_AndId2Chunk)
391                 .append(to_string(id2_chunk))
392                 .append(s_AndId2Info)
393                 .append(id2_info)
394                 .append(s_AndBlobPropItem)
395                 .append(s_AndMessageChunk)
396                 .append(s_AndSize)
397                 .append(to_string(msg_size))
398                 .append(s_AndStatus)
399                 .append(to_string(static_cast<int>(status)))
400                 .append(s_AndCode)
401                 .append(to_string(code))
402                 .append(s_AndSeverity)
403                 .append(SeverityToLowerString(severity))
404                 .append(1, '\n');
405 }
406 
GetBlobPropCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)407 string  GetBlobPropCompletionHeader(size_t  item_id,
408                                     const string &  processor_id,
409                                     size_t  chunk_count)
410 {
411     string      reply(s_ReplyBegin);
412 
413     return reply.append(to_string(item_id))
414                 .append(s_AndProcessorId)
415                 .append(NStr::URLEncode(processor_id))
416                 .append(s_AndBlobPropItem)
417                 .append(s_AndMetaChunk)
418                 .append(s_AndNChunks)
419                 .append(to_string(chunk_count))
420                 .append(1, '\n');
421 }
422 
423 
GetTSEBlobPropCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)424 string  GetTSEBlobPropCompletionHeader(size_t  item_id,
425                                        const string &  processor_id,
426                                        size_t  chunk_count)
427 {
428     string      reply(s_ReplyBegin);
429 
430     return reply.append(to_string(item_id))
431                 .append(s_AndProcessorId)
432                 .append(NStr::URLEncode(processor_id))
433                 .append(s_AndBlobPropItem)
434                 .append(s_AndMetaChunk)
435                 .append(s_AndNChunks)
436                 .append(to_string(chunk_count))
437                 .append(1, '\n');
438 }
439 
440 
GetBlobChunkHeader(size_t item_id,const string & processor_id,const string & blob_id,size_t chunk_size,size_t chunk_number,CBlobRecord::TTimestamp last_modified)441 string  GetBlobChunkHeader(size_t  item_id,
442                            const string &  processor_id,
443                            const string &  blob_id,
444                            size_t  chunk_size,
445                            size_t  chunk_number,
446                            CBlobRecord::TTimestamp  last_modified)
447 {
448     // E.g. PSG-Reply-Chunk: item_id=3&processor_id=get+blob+proc&item_type=blob&chunk_type=data&size=2345&blob_id=333.444&blob_chunk=37
449     string      reply(s_ReplyBegin);
450 
451     string      last_modified_part;
452     if (last_modified != -1)
453         last_modified_part.append(s_AndLastModified)
454                           .append(to_string(last_modified));
455 
456     return reply.append(to_string(item_id))
457                 .append(s_AndProcessorId)
458                 .append(NStr::URLEncode(processor_id))
459                 .append(s_AndBlobItem)
460                 .append(s_AndDataChunk)
461                 .append(s_AndSize)
462                 .append(to_string(chunk_size))
463                 .append(s_AndBlobId)
464                 .append(blob_id)
465                 .append(last_modified_part)
466                 .append(s_AndBlobChunk)
467                 .append(to_string(chunk_number))
468                 .append(1, '\n');
469 }
470 
471 
GetTSEBlobChunkHeader(size_t item_id,const string & processor_id,size_t chunk_size,size_t chunk_number,int64_t id2_chunk,const string & id2_info)472 string  GetTSEBlobChunkHeader(size_t  item_id,
473                               const string &  processor_id,
474                               size_t  chunk_size,
475                               size_t  chunk_number,
476                               int64_t  id2_chunk,
477                               const string &  id2_info)
478 {
479     // E.g. PSG-Reply-Chunk:
480     // item_id=3&processor_id=get+blob+proc&item_type=blob&chunk_type=data&size=2345&id2_chunk=11&id2_info=33.44.55&blob_chunk=37
481     string      reply(s_ReplyBegin);
482 
483     return reply.append(to_string(item_id))
484                 .append(s_AndProcessorId)
485                 .append(NStr::URLEncode(processor_id))
486                 .append(s_AndBlobItem)
487                 .append(s_AndDataChunk)
488                 .append(s_AndSize)
489                 .append(to_string(chunk_size))
490                 .append(s_AndBlobChunk)
491                 .append(to_string(chunk_number))
492                 .append(s_AndId2Chunk)
493                 .append(to_string(id2_chunk))
494                 .append(s_AndId2Info)
495                 .append(id2_info)
496                 .append(1, '\n');
497 }
498 
499 
GetBlobExcludeHeader(size_t item_id,const string & processor_id,const string & blob_id,EPSGS_BlobSkipReason skip_reason,CBlobRecord::TTimestamp last_modified)500 string  GetBlobExcludeHeader(size_t  item_id,
501                              const string &  processor_id,
502                              const string &  blob_id,
503                              EPSGS_BlobSkipReason  skip_reason,
504                              CBlobRecord::TTimestamp  last_modified)
505 {
506     // E.g. PSG-Reply-Chunk: item_id=5&processor_id=get+blob+proc&item_type=blob&chunk_type=meta&blob_id=555.666&n_chunks=1&reason={excluded,inprogress,sent}
507     string      reply(s_ReplyBegin);
508 
509     string      last_modified_part;
510     if (last_modified != -1)
511         last_modified_part.append(s_AndLastModified)
512                           .append(to_string(last_modified));
513 
514     return reply.append(to_string(item_id))
515                 .append(s_AndProcessorId)
516                 .append(NStr::URLEncode(processor_id))
517                 .append(s_AndBlobItem)
518                 .append(s_AndMetaChunk)
519                 .append(s_AndBlobId)
520                 .append(blob_id)
521                 .append(last_modified_part)
522                 .append(s_AndNChunksOne)
523                 .append(s_AndReason)
524                 .append(SkipReasonToString(skip_reason))
525                 .append(1, '\n');
526 }
527 
528 
GetTSEBlobExcludeHeader(size_t item_id,const string & processor_id,int64_t id2_chunk,const string & id2_info,EPSGS_BlobSkipReason skip_reason)529 string  GetTSEBlobExcludeHeader(size_t  item_id,
530                                 const string &  processor_id,
531                                 int64_t  id2_chunk,
532                                 const string &  id2_info,
533                                 EPSGS_BlobSkipReason  skip_reason)
534 {
535     string      reply(s_ReplyBegin);
536 
537     return reply.append(to_string(item_id))
538                 .append(s_AndProcessorId)
539                 .append(NStr::URLEncode(processor_id))
540                 .append(s_AndId2Chunk)
541                 .append(to_string(id2_chunk))
542                 .append(s_AndId2Info)
543                 .append(id2_info)
544                 .append(s_AndBlobItem)
545                 .append(s_AndMetaChunk)
546                 .append(s_AndNChunksOne)
547                 .append(s_AndReason)
548                 .append(SkipReasonToString(skip_reason))
549                 .append(1, '\n');
550 }
551 
552 
GetBlobCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)553 string  GetBlobCompletionHeader(size_t  item_id,
554                                 const string &  processor_id,
555                                 size_t  chunk_count)
556 {
557     // E.g. PSG-Reply-Chunk: item_id=4&processor_id=get+blob+proc&item_type=blob&chunk_type=meta&n_chunks=100
558     string      reply(s_ReplyBegin);
559 
560     return reply.append(to_string(item_id))
561                 .append(s_AndProcessorId)
562                 .append(NStr::URLEncode(processor_id))
563                 .append(s_AndBlobItem)
564                 .append(s_AndMetaChunk)
565                 .append(s_AndNChunks)
566                 .append(to_string(chunk_count))
567                 .append(1, '\n');
568 }
569 
570 
GetTSEBlobCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)571 string GetTSEBlobCompletionHeader(size_t  item_id,
572                                   const string &  processor_id,
573                                   size_t  chunk_count)
574 {
575     // E.g. PSG-Reply-Chunk:
576     // item_id=4&processor_id=get+blob+proc&item_type=blob&chunk_type=meta&n_chunks=100
577     string      reply(s_ReplyBegin);
578 
579     return reply.append(to_string(item_id))
580                 .append(s_AndProcessorId)
581                 .append(NStr::URLEncode(processor_id))
582                 .append(s_AndBlobItem)
583                 .append(s_AndMetaChunk)
584                 .append(s_AndNChunks)
585                 .append(to_string(chunk_count))
586                 .append(1, '\n');
587 
588 }
589 
590 
GetBlobMessageHeader(size_t item_id,const string & processor_id,const string & blob_id,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity,CBlobRecord::TTimestamp last_modified)591 string  GetBlobMessageHeader(size_t  item_id,
592                              const string &  processor_id,
593                              const string &  blob_id,
594                              size_t  msg_size,
595                              CRequestStatus::ECode  status,
596                              int  code,
597                              EDiagSev  severity,
598                              CBlobRecord::TTimestamp  last_modified)
599 {
600     // E.g. PSG-Reply-Chunk: item_id=3&processor_id=get+blob+proc&item_type=blob&chunk_type=message&size=22&blob_id=333.444&status=404&code=5&severity=critical
601     string      reply(s_ReplyBegin);
602 
603     string      last_modified_part;
604     if (last_modified != -1)
605         last_modified_part.append(s_AndLastModified)
606                           .append(to_string(last_modified));
607 
608     return reply.append(to_string(item_id))
609                 .append(s_AndProcessorId)
610                 .append(NStr::URLEncode(processor_id))
611                 .append(s_AndBlobItem)
612                 .append(s_AndMessageChunk)
613                 .append(s_AndSize)
614                 .append(to_string(msg_size))
615                 .append(s_AndBlobId)
616                 .append(blob_id)
617                 .append(last_modified_part)
618                 .append(s_AndStatus)
619                 .append(to_string(static_cast<int>(status)))
620                 .append(s_AndCode)
621                 .append(to_string(code))
622                 .append(s_AndSeverity)
623                 .append(SeverityToLowerString(severity))
624                 .append(1, '\n');
625 }
626 
627 
GetTSEBlobMessageHeader(size_t item_id,const string & processor_id,int64_t id2_chunk,const string & id2_info,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)628 string  GetTSEBlobMessageHeader(size_t  item_id,
629                                 const string &  processor_id,
630                                 int64_t  id2_chunk,
631                                 const string &  id2_info,
632                                 size_t  msg_size,
633                                 CRequestStatus::ECode  status,
634                                 int  code,
635                                 EDiagSev  severity)
636 {
637     string      reply(s_ReplyBegin);
638 
639     return reply.append(to_string(item_id))
640                 .append(s_AndProcessorId)
641                 .append(NStr::URLEncode(processor_id))
642                 .append(s_AndBlobItem)
643                 .append(s_AndMessageChunk)
644                 .append(s_AndSize)
645                 .append(to_string(msg_size))
646                 .append(s_AndId2Chunk)
647                 .append(to_string(id2_chunk))
648                 .append(s_AndId2Info)
649                 .append(id2_info)
650                 .append(s_AndStatus)
651                 .append(to_string(static_cast<int>(status)))
652                 .append(s_AndCode)
653                 .append(to_string(code))
654                 .append(s_AndSeverity)
655                 .append(SeverityToLowerString(severity))
656                 .append(1, '\n');
657 }
658 
659 
GetReplyCompletionHeader(size_t chunk_count)660 string  GetReplyCompletionHeader(size_t  chunk_count)
661 {
662     // E.g. PSG-Reply-Chunk: item_id=0&item_type=reply&chunk_type=meta&n_chunks=153
663     string      reply(s_ReplyCompletionFixedPart);
664 
665     return reply.append(to_string(chunk_count))
666                 .append(1, '\n');
667 }
668 
669 
GetReplyMessageHeader(size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)670 string  GetReplyMessageHeader(size_t  msg_size,
671                               CRequestStatus::ECode  status,
672                               int  code,
673                               EDiagSev  severity)
674 {
675     // E.g. PSG-Reply-Chunk: item_id=0&item_type=reply&chunk_type=message&size=22&status=404&code=5&severity=critical
676     string      reply(s_ReplyBegin);
677 
678     return reply.append(1, '0')
679                 .append(s_AndReplyItem)
680                 .append(s_AndMessageChunk)
681                 .append(s_AndSize)
682                 .append(to_string(msg_size))
683                 .append(s_AndStatus)
684                 .append(to_string(static_cast<int>(status)))
685                 .append(s_AndCode)
686                 .append(to_string(code))
687                 .append(s_AndSeverity)
688                 .append(SeverityToLowerString(severity))
689                 .append(1, '\n');
690 }
691 
692 
GetNamedAnnotationHeader(size_t item_id,const string & processor_id,const string & annot_name,size_t annotation_size)693 string GetNamedAnnotationHeader(size_t  item_id,
694                                 const string &  processor_id,
695                                 const string &  annot_name,
696                                 size_t  annotation_size)
697 {
698     // E.g. PSG-Reply-Chunk: item_id=1&processor_id=get+blob+proc&item_type=bioseq_na&chunk_type=data&size=150&na=NA000111.1
699     string      reply(s_ReplyBegin);
700 
701     return reply.append(to_string(item_id))
702                 .append(s_AndProcessorId)
703                 .append(NStr::URLEncode(processor_id))
704                 .append(s_AndBioseqNAItem)
705                 .append(s_AndDataChunk)
706                 .append(s_AndSize)
707                 .append(to_string(annotation_size))
708                 .append(s_AndNA)
709                 .append(annot_name)
710                 .append(1, '\n');
711 }
712 
713 
GetNamedAnnotationMessageHeader(size_t item_id,const string & processor_id,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)714 string GetNamedAnnotationMessageHeader(size_t  item_id,
715                                        const string &  processor_id,
716                                        size_t  msg_size,
717                                        CRequestStatus::ECode  status,
718                                        int  code,
719                                        EDiagSev  severity)
720 {
721     // E.g. PSG-Reply-Chunk: item_id=5&processor_id=get+blob+proc&item_type=reply&chunk_type=message&size=22&status=404&code=5&severity=critical
722 
723     string      reply(s_ReplyBegin);
724 
725     return reply.append(to_string(item_id))
726                 .append(s_AndProcessorId)
727                 .append(NStr::URLEncode(processor_id))
728                 .append(s_AndBioseqNAItem)
729                 .append(s_AndMessageChunk)
730                 .append(s_AndSize)
731                 .append(to_string(msg_size))
732                 .append(s_AndStatus)
733                 .append(to_string(static_cast<int>(status)))
734                 .append(s_AndCode)
735                 .append(to_string(code))
736                 .append(s_AndSeverity)
737                 .append(SeverityToLowerString(severity))
738                 .append(1, '\n');
739 }
740 
741 
GetNamedAnnotationMessageCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)742 string GetNamedAnnotationMessageCompletionHeader(size_t  item_id,
743                                                  const string &  processor_id,
744                                                  size_t  chunk_count)
745 {
746     string      reply(s_ReplyBegin);
747 
748     return reply.append(to_string(item_id))
749                 .append(s_AndProcessorId)
750                 .append(NStr::URLEncode(processor_id))
751                 .append(s_AndBioseqNAItem)
752                 .append(s_AndMetaChunk)
753                 .append(s_AndNChunks)
754                 .append(to_string(chunk_count))
755                 .append(1, '\n');
756 }
757 
758 
GetNamedAnnotationCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)759 string GetNamedAnnotationCompletionHeader(size_t  item_id,
760                                           const string &  processor_id,
761                                           size_t  chunk_count)
762 {
763     string      reply(s_ReplyBegin);
764 
765     return reply.append(to_string(item_id))
766                 .append(s_AndProcessorId)
767                 .append(NStr::URLEncode(processor_id))
768                 .append(s_AndBioseqNAItem)
769                 .append(s_AndMetaChunk)
770                 .append(s_AndNChunks)
771                 .append(to_string(chunk_count))
772                 .append(1, '\n');
773 }
774 
775 
GetProcessorMessageHeader(size_t item_id,const string & processor_id,size_t msg_size,CRequestStatus::ECode status,int code,EDiagSev severity)776 string GetProcessorMessageHeader(size_t  item_id,
777                                  const string &  processor_id,
778                                  size_t  msg_size,
779                                  CRequestStatus::ECode  status,
780                                  int  code,
781                                  EDiagSev  severity)
782 {
783     string      reply(s_ReplyBegin);
784 
785     return reply.append(to_string(item_id))
786                 .append(s_AndProcessorId)
787                 .append(NStr::URLEncode(processor_id))
788                 .append(s_AndProcessorItem)
789                 .append(s_AndMessageChunk)
790                 .append(s_AndSize)
791                 .append(to_string(msg_size))
792                 .append(s_AndStatus)
793                 .append(to_string(static_cast<int>(status)))
794                 .append(s_AndCode)
795                 .append(to_string(code))
796                 .append(s_AndSeverity)
797                 .append(SeverityToLowerString(severity))
798                 .append(1, '\n');
799 }
800 
801 
GetProcessorMessageCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)802 string GetProcessorMessageCompletionHeader(size_t  item_id,
803                                            const string &  processor_id,
804                                            size_t  chunk_count)
805 {
806     string      reply(s_ReplyBegin);
807 
808     return reply.append(to_string(item_id))
809                 .append(s_AndProcessorId)
810                 .append(NStr::URLEncode(processor_id))
811                 .append(s_AndProcessorItem)
812                 .append(s_AndMetaChunk)
813                 .append(s_AndNChunks)
814                 .append(to_string(chunk_count))
815                 .append(1, '\n');
816 }
817 
818 
GetPublicCommentHeader(size_t item_id,const string & processor_id,const string & blob_id,CBlobRecord::TTimestamp last_modified,size_t msg_size)819 string GetPublicCommentHeader(size_t  item_id,
820                               const string &  processor_id,
821                               const string &  blob_id,
822                               CBlobRecord::TTimestamp  last_modified,
823                               size_t  msg_size)
824 {
825     string      reply(s_ReplyBegin);
826 
827     return reply.append(to_string(item_id))
828                 .append(s_AndProcessorId)
829                 .append(NStr::URLEncode(processor_id))
830                 .append(s_AndPublicCommentItem)
831                 .append(s_AndDataChunk)
832                 .append(s_AndBlobId)
833                 .append(blob_id)
834                 .append(s_AndLastModified)
835                 .append(to_string(last_modified))
836                 .append(s_AndSize)
837                 .append(to_string(msg_size))
838                 .append(1, '\n');
839 }
840 
841 
GetPublicCommentHeader(size_t item_id,const string & processor_id,int64_t id2_chunk,const string & id2_info,size_t msg_size)842 string GetPublicCommentHeader(size_t  item_id,
843                               const string &  processor_id,
844                               int64_t  id2_chunk,
845                               const string &  id2_info,
846                               size_t  msg_size)
847 {
848     string      reply(s_ReplyBegin);
849 
850     return reply.append(to_string(item_id))
851                 .append(s_AndProcessorId)
852                 .append(NStr::URLEncode(processor_id))
853                 .append(s_AndPublicCommentItem)
854                 .append(s_AndDataChunk)
855                 .append(s_AndId2Chunk)
856                 .append(to_string(id2_chunk))
857                 .append(s_AndId2Info)
858                 .append(id2_info)
859                 .append(s_AndSize)
860                 .append(to_string(msg_size))
861                 .append(1, '\n');
862 
863 }
864 
865 
GetPublicCommentCompletionHeader(size_t item_id,const string & processor_id,size_t chunk_count)866 string GetPublicCommentCompletionHeader(size_t  item_id,
867                                         const string &  processor_id,
868                                         size_t  chunk_count)
869 {
870     string      reply(s_ReplyBegin);
871 
872     return reply.append(to_string(item_id))
873                 .append(s_AndProcessorId)
874                 .append(NStr::URLEncode(processor_id))
875                 .append(s_AndPublicCommentItem)
876                 .append(s_AndMetaChunk)
877                 .append(s_AndNChunks)
878                 .append(to_string(chunk_count))
879                 .append(1, '\n');
880 }
881 
882 
883 
884 extern bool  g_Log;
885 
886 
887 // If the thread had no context set => the context need to be reset.
888 // The client IP address is set only for non default context.
CRequestContextResetter()889 CRequestContextResetter::CRequestContextResetter() :
890     m_NeedReset(!CDiagContext::GetRequestContext().IsSetClientIP())
891 {}
892 
~CRequestContextResetter()893 CRequestContextResetter::~CRequestContextResetter()
894 {
895     if (g_Log && m_NeedReset) {
896         CDiagContext::SetRequestContext(NULL);
897     }
898 }
899 
900 
FormatPreciseTime(const chrono::system_clock::time_point & t_point)901 string FormatPreciseTime(const chrono::system_clock::time_point &  t_point)
902 {
903     std::time_t             t = chrono::system_clock::to_time_t(t_point);
904     chrono::milliseconds    t_ms = chrono::duration_cast<chrono::milliseconds>
905                                                     (t_point.time_since_epoch());
906 
907     struct tm               local_time;
908     localtime_r(&t, &local_time);
909 
910     char                    buffer[64];
911     size_t                  char_count = strftime(buffer, 64,
912                                                   "%Y-%m-%d %H:%M:%S",
913                                                   &local_time);
914     sprintf(&buffer[char_count], ".%03ld", t_ms.count() % 1000);
915     return buffer;
916 }
917 
918 
919 
920 static map<EPSGS_StartupDataState, string> s_CassStartupDataStateMsg =
921     { {ePSGS_NoCassConnection, "Cassandra DB connection is not established"},
922       {ePSGS_NoValidCassMapping, "Cassandra DB mapping configuration is invalid"},
923       {ePSGS_NoCassCache, "LMDB cache is not initialized"},
924       {ePSGS_StartupDataOK, "Cassandra DB mapping data are OK"} };
GetCassStartupDataStateMessage(EPSGS_StartupDataState state)925 string GetCassStartupDataStateMessage(EPSGS_StartupDataState  state)
926 {
927     return s_CassStartupDataStateMsg[state];
928 }
929 
930