BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
FileCatalogue.cxx
Go to the documentation of this file.
1#include "FileCatalogue.h"
2
3#include "file_db_settings.h"
4#include "nlohmann/json.hpp"
5
6#include <fstream>
7#include <iostream>
8#include <map>
9#include <sstream>
10
11using json = nlohmann::ordered_json;
12
13map<int, string> const Errors{{401, "Unauthorized Access (check user login and password)"},
14 {403, "Token invalid or expired"},
15 {404, "Requested Data not found"},
16 {409, "Incorrect Database Request (e.g. violating constraints)"},
17 {422, "Incorrect Input Request"},
18 {500, "Internal Server Error"},
19 {503, "Service Unavaialble"},
20 {504, "Server Timeout"}};
21
22string const GetErrorString(int error_id)
23{
24 auto it = Errors.find(error_id);
25 return it != Errors.end() ? it->second : "";
26}
27
29{
30 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
31 std::mt19937 engine(seed);
32 std::uniform_int_distribution<int> dist(1, 1000000000);
33 int randomNum = dist(engine);
34 return randomNum;
35}
36
38 : iValueType(0)
39 , FileAttribute(attribute)
40 , FileMatchCriteria(condition)
41{}
42
44 : iValueType(1)
45 , iValue(value)
46 , FileAttribute(attribute)
47 , FileMatchCriteria(condition)
48{}
49
50FileCondition::FileCondition(searchAttributes attribute, matchCriteria condition, unsigned int value)
51 : iValueType(2)
52 , uiValue(value)
53 , FileAttribute(attribute)
54 , FileMatchCriteria(condition)
55{}
56
58 : iValueType(3)
59 , fValue(value)
60 , FileAttribute(attribute)
61 , FileMatchCriteria(condition)
62{}
63
65 : iValueType(4)
66 , strValue(value)
67 , FileAttribute(attribute)
68 , FileMatchCriteria(condition)
69{}
70
71// private default constructor
77
82
87
89{
90 switch (iValueType) {
91 case 1:
92 return std::to_string(iValue);
93 case 2:
94 return std::to_string(uiValue);
95 case 3:
96 return std::to_string(fValue);
97 case 4:
98 return strValue;
99 }
100 return "0";
101}
102
103// File Catalog Constructor
105{
106 curl_global_init(CURL_GLOBAL_DEFAULT);
107 curlInstance = curl_easy_init();
108 if (!curlInstance) {
109 throw runtime_error("CURL initialisation failed");
110 return;
111 }
112
113 ServiceUrl =
114 FILE_API_HOST + string("/") + FILE_API_NAME + string("/v") + to_string(FileInfo::Version) + string("/");
116}
117
118// File Catalog Destructor
120{
121 curl_easy_cleanup(curlInstance);
122 curl_global_cleanup();
123}
124
125std::string ReplaceAll(std::string str, const std::string& from, const std::string& to)
126{
127 size_t start_pos = 0;
128 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
129 str.replace(start_pos, from.length(), to);
130 start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
131 }
132 return str;
133}
134
135int FileCatalogue::GetFileList(vector<unique_ptr<FileCondition>> file_conditions, vector<string>& filepaths)
136{
137 string conditions = "filepath?";
138 for (const auto& cond : file_conditions) {
139 switch (cond->getFileAttribute()) {
141 conditions += "period_number";
142 break;
144 conditions += "run_number";
145 break;
147 conditions += "run_type";
148 break;
150 conditions += "start_datetime";
151 break;
153 conditions += "end_datetime";
154 break;
156 conditions += "beam_particle";
157 break;
159 conditions += "target_particle";
160 break;
162 conditions += "energy";
163 break;
165 conditions += "field_voltage";
166 break;
168 conditions += "start_event";
169 break;
171 conditions += "end_event";
172 break;
174 conditions += "event_count";
175 break;
177 conditions += "file_size";
178 break;
180 return -404;
181 };
182 switch (cond->getMatchCriteria()) {
184 conditions = conditions + "=|" + cond->getValueAsString();
185 break;
187 conditions = conditions + "=" + cond->getValueAsString();
188 break;
190 conditions = conditions + "!=" + cond->getValueAsString();
191 break;
193 conditions = conditions + "=" + cond->getValueAsString() + "|";
194 break;
196 conditions = conditions + "=*" + cond->getValueAsString() + "*";
197 };
198 conditions += "&";
199 }
200 conditions.erase(conditions.size() - 1, 1); // get rid of last &.
201 conditions = ReplaceAll(conditions, string(" "), string("%20"));
202 string result;
203 result = performRequest(conditions, "", "GET");
204 if (result == "ERROR: Failed to authenticate\n") {
205 return -401;
206 }
207 if (result == "ERROR: Can't get files list (DIRAC API ERROR)\n") {
208 return -500;
209 }
210 if (result == "ERROR: Can't get files list\n") {
211 return -500;
212 }
213 if (result.find("ERROR") != std::string::npos)
214 return -503; // presumably server is not available
215 result = result.erase(0, 2);
216 size_t delim = result.find("\",\"");
217 while (delim != string::npos) {
218 filepaths.push_back(result.substr(0, delim));
219 result.erase(0, delim + 3);
220 delim = result.find("\",\"");
221 }
222 delim = result.find("\"]");
223 filepaths.push_back(result.substr(0, delim));
224 return 0;
225}
226
227int FileCatalogue::GetFileInfo(string LFN, FileInfo& file_info)
228{
229 string conditions = "meta?filepath=" + LFN;
230 string res = performRequest(conditions, "", "GET");
231 if (res == "ERROR: Failed to authenticate\n") {
232 return -401;
233 }
234 if (res == "ERROR: File not found\n") {
235 return -404;
236 }
237 if (res == "ERROR: Can't get meta (DIRAC API ERROR)\n") {
238 return -500;
239 }
240 if (res == "ERROR: Can't get meta\n") {
241 return -500;
242 }
243 if (res.find("ERROR") != std::string::npos)
244 return -503; // presumably server is not available
245 json result = json::parse(res);
246 char DTbuf[100];
247 std::tm DTtm = {};
248 for (auto& [key, value] : result.items()) {
249 if (key == "period_number")
250 file_info.PeriodNumber = value.get<int>();
251 if (key == "run_number")
252 file_info.RunNumber = value.get<int>();
253 if (key == "run_type")
254 file_info.RunType = value.get<int>();
255 if (key == "start_datetime") {
256 strptime(value.get<string>().c_str(), "%a, %d %b %Y %H:%M:%S GMT", &DTtm);
257 strftime(DTbuf, sizeof DTbuf, "%Y-%m-%d %H:%M:%S", &DTtm); // format from default GMT to YY-MM-DD hh-mm-ss
258 file_info.StartDateTime = DTbuf;
259 }
260 if (key == "end_datetime") {
261 strptime(value.get<string>().c_str(), "%a, %d %b %Y %H:%M:%S GMT", &DTtm);
262 strftime(DTbuf, sizeof DTbuf, "%Y-%m-%d %H:%M:%S", &DTtm); // format from default GMT to YY-MM-DD hh-mm-ss
263 file_info.EndDateTime = DTbuf;
264 }
265 if (key == "beam_particle")
266 file_info.BeamParticle = value.get<string>();
267 if (key == "target_particle")
268 file_info.TargetParticle = value.get<string>();
269 if (key == "energy")
270 file_info.Energy = value.get<float>();
271 if (key == "field_voltage")
272 file_info.FieldVoltage = value.get<float>();
273 if (key == "start_event")
274 file_info.StartEvent = value.get<int>();
275 if (key == "end_event")
276 file_info.EndEvent = value.get<int>();
277 if (key == "event_count")
278 file_info.EventCount = value.get<int>();
279 if (key == "file_size")
280 file_info.FileSize = value.get<float>();
281 }
282 return 0;
283}
284
285int FileCatalogue::GetDirectoryInfo(string path, string& directory_info)
286{
287 string conditions = "directorymeta?dirpath=" + path;
288 string res = performRequest(conditions, "", "GET");
289 if (res == "ERROR: Failed to authenticate\n") {
290 return -401;
291 }
292 if (res == "ERROR: File not found\n") {
293 return -404;
294 }
295 if (res == "ERROR: Can't get meta (DIRAC API ERROR)\n") {
296 return -500;
297 }
298 if (res == "ERROR: Can't get meta\n") {
299 return -500;
300 }
301 if (res.find("ERROR") != std::string::npos)
302 return -503; // presumably server is not available
303 directory_info = res;
304 return 0;
305}
306
308{
309 string conditions = "checkstatus?";
310 string result = performRequest(conditions, "", "GET");
311 if (result == "ERROR: Can't read check status file\n")
312 return -500;
313 if (result == "ERROR: Failed to authenticate\n")
314 return -401;
315 result = result.erase(0, result.find("ID=") + 3);
316 return stoi(result);
317}
318
320 int& fc_missing_count,
321 vector<string>& eos_missing,
322 vector<string>& fc_missing)
323{
324 string conditions = "checkresults?";
325 string result = performRequest(conditions, "", "GET");
326 if (result == "ERROR: Can't read check results file\n")
327 return -500;
328 if (result == "ERROR: Failed to authenticate\n")
329 return -401;
330 if (result.find("ERROR") != std::string::npos)
331 return -503; // presumably server is not available
332 string line;
333 stringstream stream(result);
334 getline(stream, line); // skipping the first line
335 while (getline(stream, line)) {
336 if (line.find("Addto count:") != string::npos) {
337 fc_missing_count = stoi(line.erase(0, 12));
338 break;
339 }
340 fc_missing.push_back(line);
341 }
342 getline(stream, line); // skipping the line
343 while (getline(stream, line)) {
344 if (line.find("Missing count:") != string::npos) {
345 eos_missing_count = stoi(line.erase(0, 14));
346 break;
347 }
348 eos_missing.push_back(line);
349 }
350 return 0;
351}
352
353int FileCatalogue::GetFile(string LFN, string save_path)
354{
355 if (save_path.find("root") == 0) {
356 // xrd way
357 string conditions = "file_to_xrd?LFN=" + LFN + "&XRDURL=" + save_path;
358 string res = performRequest(conditions, "", "GET");
359 if (res == "ERROR: Failed to authenticate\n")
360 return -401;
361 if (res == "ERROR: Can't download file from CICC(DIRAC)\n")
362 return -500;
363 if (res == "ERROR: Can't upload to xrootd path\n")
364 return -500;
365 return 0;
366 } else {
367 string conditions = "file?LFN=" + LFN;
368 return DownloadFile(conditions, save_path);
369 }
370}
371
372int FileCatalogue::GetPFNs(string LFN, vector<string>& PFNs)
373{
374 string conditions = "pfn?LFN=" + LFN;
375 string res = performRequest(conditions, "", "GET");
376 if (res == "ERROR: Failed to authenticate\n") {
377 return -401;
378 }
379 if (res == "ERROR: None found\n") {
380 return -404;
381 }
382 if (res == "ERROR: Can't get PFN\n") {
383 return -500;
384 }
385 if (res.find("ERROR") != std::string::npos)
386 return -503; // presumably server is not available
387 try {
388 json j = json::parse(res);
389 if (!j.is_array()) {
390 return -500;
391 }
392 PFNs = j.get<std::vector<std::string>>();
393 return 0;
394 } catch (const json::parse_error& e) {
395 // std::cerr << "Ошибка парсинга JSON: " << e.what() << std::endl;
396 return -500;
397 }
398 return 0;
399}
400
401int FileCatalogue::AddFileInfo(string LFN, FileInfo file_metadata)
402{
403 json fi;
404 fi["run_number"] = file_metadata.RunNumber;
405 fi["run_type"] = file_metadata.RunType;
406 fi["start_datetime"] = file_metadata.StartDateTime;
407 fi["end_datetime"] = file_metadata.EndDateTime;
408 fi["beam_particle"] = file_metadata.BeamParticle;
409 fi["target_particle"] = file_metadata.TargetParticle;
410 fi["energy"] = file_metadata.Energy;
411 fi["field_voltage"] = file_metadata.FieldVoltage;
412 fi["start_event"] = file_metadata.StartEvent;
413 fi["end_event"] = file_metadata.EndEvent;
414 fi["event_count"] = file_metadata.EventCount;
415 fi["file_size"] = file_metadata.FileSize;
416 string conditions = "meta?filepath=" + LFN;
417 string result = performRequest(conditions, fi.dump(), "PUT");
418 if (result == "ERROR: Can't set meta (DIRAC API ERROR)\n" || result == "ERROR: Can't set meta\n")
419 return -500;
420 if (result == "ERROR: File not found\n")
421 return -404;
422 if (result == "ERROR: Failed to authenticate\n")
423 return -401;
424 return 0;
425}
426
427int FileCatalogue::AddMetadataField(string field_name, string field_type, bool isDirectoryType)
428{
429 set<string> valid_meta_types = {"INT", "DATETIME", "FLOAT", "VARCHAR(128)"};
430 if (valid_meta_types.find(field_type) == valid_meta_types.end()) {
431 cout << " Please, use the valid metadata field type. Like one of this: (INT, DATETIME, FLOAT, VARCHAR(128). "
432 "Thanks"
433 << endl;
434 return -422;
435 }
436 string conditions = "";
437 if (isDirectoryType)
438 conditions = "metadatafield_directory?fieldname=" + field_name + "&fieldtype=" + field_type;
439 else
440 conditions = "metadatafield?fieldname=" + field_name + "&fieldtype=" + field_type;
441 string result = performRequest(conditions, "", "POST");
442 if (result == "ERROR: Failed to authenticate\n")
443 return -401;
444 if (result == "ERROR: Can't set metadata field (DIRAC API ERROR)\n"
445 || result == "ERROR: Can't set metadata field\n")
446 return -500;
447 return 0;
448}
449
450size_t appendData(void* contents, size_t size, size_t nmemb, string* data)
451{
452 size_t realsize = size * nmemb;
453 try {
454 data->append((char*)contents, realsize);
455 } catch (std::bad_alloc& e) {
456 // handle memory problem
457 return 0;
458 }
459
460 return realsize;
461}
462
463int FileCatalogue::AddFileInfo(string json_file_path)
464{
465 ifstream json_file(json_file_path);
466 json full_json = json::parse(json_file);
467 auto it = full_json.find("file_path");
468 if (it == full_json.end()) {
469 cout << " Please include \"file_path\" field with correct filepath to file in your json, thanks " << endl;
470 return -422;
471 }
472 string filepath = it.value();
473 full_json.erase("file_path");
474 string conditions = "meta?filepath=" + filepath;
475 string result = performRequest(conditions, full_json.dump(), "PUT");
476
477 if (result == "ERROR: Failed to authenticate\n")
478 return -401;
479 if (result == "ERROR: Can't set meta (DIRAC API ERROR)\n" || result == "ERROR: Can't set meta\n") // some
480 return -500;
481 if (result == "ERROR: File not found\n") // file not found
482 return -404;
483 return 0;
484}
485
486int FileCatalogue::AddDirectoryInfo(string json_file_path)
487{
488 ifstream json_file(json_file_path);
489 json full_json = json::parse(json_file);
490 auto it = full_json.find("dir_path");
491 if (it == full_json.end()) {
492 cout << " Please include \"dir_path\" field with correct filepath to file in your json, thanks " << endl;
493 return -422;
494 }
495 string dirpath = it.value();
496 full_json.erase("dir_path");
497 string conditions = "meta?filepath=" + dirpath;
498 string result = performRequest(conditions, full_json.dump(), "PUT");
499 if (result == "ERROR: Failed to authenticate\n")
500 return -401;
501 if (result == "ERROR: Can't set meta (DIRAC API ERROR)\n" || result == "ERROR: Can't set meta\n") // some
502 return -500;
503 if (result == "ERROR: File not found\n") // file not found
504 return -404;
505 return 0;
506}
507
508int FileCatalogue::AddFile(string input_path, string LFN)
509{
510 string result;
511 string conditions = "file?LFN=" + LFN;
512 return UploadFile(conditions, input_path);
513}
514
515int FileCatalogue::UpdateFileInfo(string LFN, FileInfo file_metadata)
516{
517 return AddFileInfo(LFN, file_metadata);
518}
519
521{
522 string conditions = "meta?filepath=" + LFN;
523 string result = performRequest(conditions, "", "DELETE");
524 if (result == "ERROR: Can't delete metadata (DIRAC API ERROR)\n" || result == "ERROR: Can't delete metadata\n")
525 return -500;
526 if (result == "ERROR: File not found\n")
527 return -404;
528 if (result == "ERROR: Failed to authenticate\n")
529 return -401;
530 return 0;
531}
532
534{
535 string conditions = "directorymeta?dirpath=" + path;
536 string result = performRequest(conditions, "", "DELETE");
537 if (result == "ERROR: Can't delete metadata (DIRAC API ERROR)\n" || result == "ERROR: Can't delete metadata\n")
538 return -500;
539 if (result == "ERROR: Directory not found\n")
540 return -404;
541 if (result == "ERROR: Failed to authenticate\n")
542 return -401;
543 return 0;
544}
545
546int FileCatalogue::DeleteMetadataField(string metadatafield_name)
547{
548 string conditions = "metadatafield?fieldname=" + metadatafield_name;
549 string result = performRequest(conditions, "", "DELETE");
550 if (result == "ERROR: Can't delete metadata field (DIRAC API ERROR)\n"
551 || result == "ERROR: Can't delete metadata field\n")
552 return -500;
553 if (result == "ERROR: Failed to authenticate\n")
554 return -401;
555 return 0;
556}
557
559{
560 string conditions = "file?LFN=" + LFN;
561 string result = performRequest(conditions, "", "DELETE");
562 if (result == "ERROR: Can't delete file from CICC (DIRAC API ERROR)\n"
563 || result == "ERROR: Can't delete file from CICC\n")
564 return -500;
565 if (result == "ERROR: Failed to authenticate\n")
566 return -401;
567 return 0;
568}
569
571{
572 string conditions = "meta?filepath=" + LFN;
573 string res = performRequest(conditions, "", "GET");
574 if (res == "ERROR: Failed to authenticate\n")
575 return -401;
576 if (res == "ERROR: File not found\n")
577 return -404;
578 if (res == "ERROR: Can't get meta (DIRAC API ERROR)\n" || res == "ERROR: Can't get meta\n")
579 return -500;
580 if (res == "{}\n")
581 return -1;
582 return 0;
583}
584
586{
587 string conditions = "isfileexist?filepath=" + LFN;
588 string res = performRequest(conditions, "", "GET");
589 if (res == "ERROR: Failed to authenticate\n")
590 return -401;
591 if (res == "ERROR: Can't check file exist (DIRAC API ERROR)\n" || res == "ERROR: Can't check file exist\n")
592 return -500;
593 if (res == "FALSE\n")
594 return 0;
595 if (res == "TRUE\n")
596 return 1;
597 return -500;
598}
599
601{
602 string conditions = "meta?filepath=" + LFN;
603 string res = performRequest(conditions, "", "GET");
604 if (res == "ERROR: Failed to authenticate\n") {
605 cout << " Sorry, failed to authenticate" << endl;
606 return -401;
607 }
608 if (res == "ERROR: File not found\n") {
609 cout << " The file " << LFN << " was not found! " << endl;
610 return -2;
611 }
612 if (res == "ERROR: Can't get meta (DIRAC API ERROR)\n" || res == "ERROR: Can't get meta\n") {
613 cout << " Sorry, we got some errors while getting metadata of your file " << endl;
614 return -500;
615 }
616 if (res == "{}\n") {
617 cout << " There is no metadata for your file - " << LFN << endl;
618 return 0;
619 }
620 cout << " Here is metadata for your file - " << LFN << ": " << endl << res << endl;
621 return 0;
622}
623
625{
626 string res = performRequest("metadatafields?", "", "GET");
627 if (res == "ERROR: Can't get metadata fields (DIRAC API ERROR)\n" || res == "ERROR: Can't get metadata fields\n")
628 return -500;
629 if (res == "ERROR: Failed to authenticate\n")
630 return -401;
631 cout << " Metadatafields list: " << endl << res << endl;
632 return 0;
633}
634
635std::string exec(const char* cmd)
636{
637 char buffer[128];
638 std::string result = "";
639 FILE* pipe = popen(cmd, "r");
640 if (!pipe)
641 return "-1";
642 // throw std::runtime_error("popen() failed!");
643 try {
644 while (fgets(buffer, sizeof buffer, pipe) != NULL) {
645 result += buffer;
646 }
647 } catch (...) {
648 pclose(pipe);
649 throw;
650 }
651 pclose(pipe);
652 return result;
653}
654
655int FileCatalogue::FileCatalogRequest(string rest_api_request, vector<string>& filepaths)
656{
657 vector<string> file_array;
658 if (rest_api_request.find("GET") == string::npos) {
659 return -422;
660 }
661 string result;
662 try {
663 result = exec(rest_api_request.c_str());
664 } catch (...) {
665 return -500;
666 }
667 if (result == "ERROR: Failed to authenticate\n")
668 return -401;
669 // if (result.find("ERROR") != std::string::npos)
670 // return -503; // presumably server is not available
671 result = result.erase(0, 2);
672 size_t delim = result.find("\",\"");
673 while (delim != string::npos) {
674 filepaths.push_back(result.substr(0, delim));
675 result.erase(0, delim + 3);
676 delim = result.find("\",\"");
677 }
678 delim = result.find("\"]");
679 filepaths.push_back(result.substr(0, delim));
680 return 0;
681}
682
684{
685 int check_id = 0;
686 string res = performRequest("consistencycheck?", "", "POST");
687 if (res == "ERROR: Can't run consistency check (error from running shell script)\n")
688 return -500;
689 if (res == "ERROR: Failed to authenticate\n")
690 return -401;
691 try {
692 check_id = stoi(res.erase(0, 21));
693 } catch (const std::invalid_argument& e) {
694 return -500;
695 }
696 return check_id;
697}
698
700 int& files_without_replicas,
701 int& replicas_count,
702 int& replicas_without_files)
703{
704 string res = performRequest("catalogcounters?", "", "GET");
705 if (res == "ERROR: Can't get catalog counters (DIRAC API ERROR)\n" || res == "ERROR: Can't get catalog counters\n")
706 return -500;
707 if (res == "ERROR: Failed to authenticate\n")
708 return -401;
709 json metrics = json::parse(res);
710 for (auto& [key, value] : metrics.items()) {
711 if (key == "Files")
712 files_count = value.get<int>();
713 if (key == "Files w/o Replicas")
714 files_without_replicas = value.get<int>();
715 if (key == "Replicas")
716 replicas_count = value.get<int>();
717 if (key == "Replicas w/o Files")
718 replicas_without_files = value.get<int>();
719 }
720 return 0;
721}
722
723string FileCatalogue::performRequest(string conditions, string json_content, string qType)
724{
725 CURLcode res;
726 string response_string;
727
728 conditions = ServiceUrl + conditions;
729 const char* curl_url = conditions.c_str();
730 curl_easy_setopt(curlInstance, CURLOPT_URL, curl_url);
731
732 /* cache the CA cert bundle in memory for a week */
733#ifdef CURLOPT_CA_CACHE_TIMEOUT
734 curl_easy_setopt(curlInstance, CURLOPT_CA_CACHE_TIMEOUT, 604800L); // 7 days
735#endif
736 curl_easy_setopt(curlInstance, CURLOPT_WRITEFUNCTION, appendData);
737 curl_easy_setopt(curlInstance, CURLOPT_WRITEDATA, &response_string);
738 curl_easy_setopt(curlInstance, CURLOPT_USERNAME, FILE_API_USERNAME);
739 curl_easy_setopt(curlInstance, CURLOPT_PASSWORD, FILE_API_PASSWORD);
740
741 struct curl_slist* headers = NULL;
742 // headers = curl_slist_append(headers, "Accept: application/json");
743 headers = curl_slist_append(headers, "Content-Type: application/json");
744 // headers = curl_slist_append(headers, "charset: utf-8");
745
746 const char* c_json = json_content.c_str(); // what's the point of using nlohmann then?
747 const char* curl_customRequest = qType.c_str();
748 curl_easy_setopt(curlInstance, CURLOPT_CUSTOMREQUEST, curl_customRequest);
749 curl_easy_setopt(curlInstance, CURLOPT_HTTPHEADER, headers);
750 curl_easy_setopt(curlInstance, CURLOPT_POSTFIELDS, c_json); // jsonObj
751 /* Perform the request, res gets the return code */
752 res = curl_easy_perform(curlInstance);
753 /* Check for errors */
754 if (res != CURLE_OK) {
755 fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
756 }
757
758 long response_code;
759 curl_easy_getinfo(curlInstance, CURLINFO_RESPONSE_CODE, &response_code);
760 if (VerboseLevel > 2) {
761 double elapsed;
762 curl_easy_getinfo(curlInstance, CURLINFO_TOTAL_TIME, &elapsed);
763 char* url;
764 curl_easy_getinfo(curlInstance, CURLINFO_EFFECTIVE_URL, &url);
765 cout << "DEBUG: CURLINFO_TOTAL_TIME = " << elapsed << ", CURLINFO_EFFECTIVE_URL = " << string(url) << endl;
766 }
767
768 if (VerboseLevel > 1) {
769 double elapsed;
770 curl_easy_getinfo(curlInstance, CURLINFO_TOTAL_TIME, &elapsed);
771 char* url;
772 curl_easy_getinfo(curlInstance, CURLINFO_EFFECTIVE_URL, &url);
773 cout << "CURLINFO_TOTAL_TIME = " << elapsed << endl;
774 }
775 // check the result of the request
776 if ((response_code >= 200) && (response_code < 205)) {
777 if (VerboseLevel > 0)
778 cout << qType << " request has been succesfully processed " << endl;
779 if (VerboseLevel > 1)
780 cout << "Request was finished with the following response: " << response_string << endl;
781 } else {
782 cout << "ERROR: Sending request to '" << ServiceUrl << "' has been failed with code = " << response_code
783 << " and message: " << endl
784 << response_string << endl;
785 curl_slist_free_all(headers);
786 return "ERROR: error code: " + to_string(response_code);
787 }
788 curl_slist_free_all(headers);
789 return response_string;
790}
791
797
799{
801 std::string buffer; // накопленные данные для проверки
802 std::ofstream* file = nullptr;
803 bool error_detected = false;
804 std::string error_msg;
805};
806
807size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
808{
809 WriteData* data = static_cast<WriteData*>(userp);
810 size_t total = size * nmemb;
811 char* chunk = static_cast<char*>(contents);
812
813 if (data->error_detected) {
814 return total; // игнорируем остальные данные
815 }
816
817 if (data->state == CHECK_PREFIX) {
818 // Добавляем в буфер
819 data->buffer.append(chunk, total);
820 // Проверяем, достаточно ли данных для проверки (минимум 5 байт)
821 if (data->buffer.size() >= 5) {
822 if (data->buffer.compare(0, 5, "ERROR") == 0) {
823 data->error_detected = true;
824 data->error_msg = data->buffer;
825 return total; // можно вернуть 0, чтобы прервать запись, но проще игнорировать
826 } else {
827 // Это не ошибка – переключаемся на запись в файл
828 data->state = WRITE_FILE;
829 if (data->file && data->file->is_open()) {
830 data->file->write(data->buffer.data(), data->buffer.size());
831 }
832 data->buffer.clear();
833 }
834 }
835 return total;
836 }
837
838 // WRITE_FILE – просто пишем в файл
839 if (data->file && data->file->is_open()) {
840 data->file->write(chunk, total);
841 }
842 return total;
843}
844
845int FileCatalogue::DownloadFile(string conditions, string savePath)
846{
847
848 std::ofstream file(savePath, std::ios::binary);
849 if (!file.is_open()) {
850 curl_easy_cleanup(curlInstance);
851 return -500;
852 }
853 WriteData data;
854 data.file = &file;
855
856 conditions = ServiceUrl + conditions;
857 const char* curl_url = conditions.c_str();
858 curl_easy_setopt(curlInstance, CURLOPT_URL, curl_url);
859 curl_easy_setopt(curlInstance, CURLOPT_WRITEFUNCTION, WriteCallback);
860 curl_easy_setopt(curlInstance, CURLOPT_WRITEDATA, &data);
861 curl_easy_setopt(curlInstance, CURLOPT_FAILONERROR, 1L);
862 curl_easy_setopt(curlInstance, CURLOPT_USERNAME, FILE_API_USERNAME);
863 curl_easy_setopt(curlInstance, CURLOPT_PASSWORD, FILE_API_PASSWORD);
864
865 CURLcode res = curl_easy_perform(curlInstance);
866 long http_code = 0;
867 curl_easy_getinfo(curlInstance, CURLINFO_RESPONSE_CODE, &http_code);
868 curl_easy_cleanup(curlInstance);
869 file.close();
870
871 if (data.error_detected) {
872 // Удаляем частично записанный файл (если он был создан)
873 std::remove(savePath.c_str());
874 if (data.error_msg == "ERROR: Failed to authenticate\n")
875 return -401;
876 else
877 return -500;
878 }
879
880 if (res != CURLE_OK) {
881 cout << "CURL error: " << curl_easy_strerror(res) << endl;
882 std::remove(savePath.c_str());
883 return -500;
884 }
885
886 return 0;
887}
888
889// MIME API появился в libcurl 7.56.0, CURLOPT_XFERINFOFUNCTION – в 7.32.0.
890// На старых системах (например, CentOS 7 с libcurl 7.29.0) используются устаревшие аналоги.
891#define FC_HAS_CURL_MIME (LIBCURL_VERSION_NUM >= 0x073800)
892#define FC_HAS_CURL_XFERINFO (LIBCURL_VERSION_NUM >= 0x072000)
893
894#if FC_HAS_CURL_XFERINFO
895int progressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
896{
897#else
898int progressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow)
899{
900#endif
901 if (ultotal > 0) {
902 double percent = (double)ulnow / ultotal * 100;
903 std::cout << "\rUploading: " << int(percent) << "%" << std::flush;
904 }
905 return 0; // 0 – продолжать, 1 – прервать
906}
907
908int FileCatalogue::UploadFile(string conditions, string filepath)
909{
910#if FC_HAS_CURL_MIME
911 struct curl_mime* mime = curl_mime_init(curlInstance);
912 struct curl_mimepart* part = curl_mime_addpart(mime);
913 curl_mime_name(part, "file"); // имя поля (как в -F "file=...")
914 curl_mime_filedata(part, filepath.c_str()); // прикрепляем файл
915#else
916 struct curl_httppost* formpost = nullptr;
917 struct curl_httppost* lastptr = nullptr;
918 curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", // имя поля (как в -F "file=...")
919 CURLFORM_FILE, filepath.c_str(), // прикрепляем файл
920 CURLFORM_END);
921#endif
922
923 std::string response;
924 conditions = ServiceUrl + conditions;
925 const char* curl_url = conditions.c_str();
926 curl_easy_setopt(curlInstance, CURLOPT_URL, curl_url);
927 curl_easy_setopt(curlInstance, CURLOPT_USERNAME, FILE_API_USERNAME);
928 curl_easy_setopt(curlInstance, CURLOPT_PASSWORD, FILE_API_PASSWORD);
929#if FC_HAS_CURL_MIME
930 curl_easy_setopt(curlInstance, CURLOPT_MIMEPOST, mime); // POST с multipart
931#else
932 curl_easy_setopt(curlInstance, CURLOPT_HTTPPOST, formpost); // POST с multipart
933#endif
934 curl_easy_setopt(curlInstance, CURLOPT_WRITEFUNCTION, appendData);
935 curl_easy_setopt(curlInstance, CURLOPT_WRITEDATA, &response);
936 curl_easy_setopt(curlInstance, CURLOPT_FAILONERROR, 1L); // чтобы HTTP>=400 возвращал ошибку
937
938 curl_easy_setopt(curlInstance, CURLOPT_TIMEOUT, 3600L); // 1 час
939 curl_easy_setopt(curlInstance, CURLOPT_LOW_SPEED_LIMIT, 1024L); // 1 КБ/с минимум
940 curl_easy_setopt(curlInstance, CURLOPT_LOW_SPEED_TIME, 60L); // если медленнее 60 сек – таймаут
941
942#if FC_HAS_CURL_XFERINFO
943 curl_easy_setopt(curlInstance, CURLOPT_XFERINFOFUNCTION, progressCallback);
944#else
945 curl_easy_setopt(curlInstance, CURLOPT_PROGRESSFUNCTION, progressCallback);
946#endif
947 curl_easy_setopt(curlInstance, CURLOPT_NOPROGRESS, 0L);
948
949 CURLcode res = curl_easy_perform(curlInstance);
950
951 long http_code = 0;
952 curl_easy_getinfo(curlInstance, CURLINFO_RESPONSE_CODE, &http_code);
953
954#if FC_HAS_CURL_MIME
955 curl_mime_free(mime);
956#else
957 curl_formfree(formpost);
958#endif
959 curl_easy_cleanup(curlInstance);
960
961 if (res != CURLE_OK) {
962 return http_code ? -http_code : -500;
963 }
964
965 // Проверяем, не вернул ли сервер ошибку (сообщение начинается с "ERROR")
966 if (response.compare(0, 5, "ERROR") == 0) {
967 if (response == "ERROR: Failed to authenticate\n")
968 return -401;
969 if (response == "ERROR: No file uploaded\n" or response == "ERROR: Empty filename\n")
970 return -422;
971 return -500;
972 }
973
974 // Успех
975 // std::cout << "Upload successful. Server response: " << response << std::endl;
976 return 0;
977}
vector< Double_t > dist(vector< Double_t > qp, Double_t mu)
Definition BmnMath.cxx:869
map< int, string > const Errors
std::string exec(const char *cmd)
size_t appendData(void *contents, size_t size, size_t nmemb, string *data)
@ WRITE_FILE
@ CHECK_PREFIX
int GiveMeNumber()
int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
string const GetErrorString(int error_id)
std::string ReplaceAll(std::string str, const std::string &from, const std::string &to)
int CheckFileExist(string LFN)
Function to check whether file exist or not.
int DeleteDirectoryInfo(string path)
Function to delete metadata for the directory at specific path.
int AddDirectoryInfo(string json_file_path)
Function to add directory metadata to the File Catalog using input JSON directory path.
int DeleteFile(string LFN)
Function to delete file from the File Catalog and CICC.
int AddMetadataField(string field_name, string field_type, bool isDirectoryType=true)
Function to add new metadata field to the File Catalog.
int FileCatalogRequest(string rest_api_request, vector< string > &filepaths)
Function for searching for files matching specific metadata in the File Catalog using REST API reques...
int FileCatalogStats(int &files_count, int &files_without_replicas, int &replicas_count, int &replicas_without_files)
Function to collect summary statistics on the File Catalog.
int UploadFile(string conditions, string filepath)
int PrintFileInfo(string LFN)
Function to print metadata for the file stored at the given location.
int GetDirectoryInfo(string path, string &directory_info)
Function to get metadata of the directory at the given path.
virtual ~FileCatalogue()
int DeleteMetadataField(string metadatafield_name)
Function to delete metadata field from the File Catalog.
string ServiceAccount
int FileCatalogConsistencyCheck()
Function to perform a consistency check in the File Catalog.
int CheckFileInfo(string LFN)
Function to check metadata for the file with specific LFN.
int GetFile(string LFN, string save_path)
Function to download file from the CICC (Dirac FC).
int GetFileList(vector< unique_ptr< FileCondition > > file_conditions, vector< string > &filepaths)
Function for searching for file metadata in the File Catalog using specified conditions.
int UpdateFileInfo(string LFN, FileInfo file_metadata)
Function to update metadata for the file with specific LFN.
int DeleteFileInfo(string LFN)
Function to delete metadata for the file with specific LFN.
int GetConsistencyCheckResults(int &eos_missing_count, int &fc_missing_count, vector< string > &eos_missing, vector< string > &fc_missing)
Function to get result of the last successful consistency check.
int DownloadFile(string conditions, string savePath)
int AddFileInfo(string LFN, FileInfo file_metadata)
Function to add metadata for the file with specific LFN.
string performRequest(string conditions, string json_content, string qType)
Perfrom common curl read/write shenanigans.
int AddFile(string input_path, string LFN)
Function to add file to the File Catalog and upload to CICC.
int GetFileInfo(string LFN, FileInfo &file_info)
Function to get metadata of the file stored at the given location.
int GetPFNs(string LFN, vector< string > &PFNs)
Function to get file PFN (Physical File Name).
int PrintMetadataFields()
Function to print current metadata fields.
int GetConsistencyCheckStatus()
Function to get status of the last successful consistency check.
searchAttributes
enumeration for attributes, which can be used in searching file metadata
string getValueAsString()
matchCriteria
enumeration for conditions, which can be used for matching with a specified value
matchCriteria getMatchCriteria()
matchCriteria FileMatchCriteria
searchAttributes getFileAttribute()
unsigned int uiValue
searchAttributes FileAttribute
Class presenting File Info (Metadata) Structure.
int StartEvent
event number from which stored event set begins
float FileSize
file size in bytes
int RunType
run type (1 - physics run, 2 - calibration run, 3 - test run)
static const int Version
structure (API) version
string BeamParticle
beam particle name
int EndEvent
event number with which event set ends
int EventCount
event count stored in the file
float Energy
beam energy
string EndDateTime
end datetime of the stored event set (YYYY-MM-DD HH-MM-SS format)
int PeriodNumber
number of experiment session, when the events was collected
string StartDateTime
start datetime of the stored event set (YYYY-MM-DD HH-MM-SS format)
int RunNumber
number of experiment run, when the events was collected
string TargetParticle
target particle name
float FieldVoltage
field voltage
const char *const FILE_API_USERNAME
const char *const FILE_API_HOST
const char *const FILE_API_NAME
const char *const FILE_API_PASSWORD
basic_json< nlohmann::ordered_map > ordered_json
specialization that maintains the insertion order of object keys
Definition json.hpp:3374
std::ofstream * file
std::string buffer
std::string error_msg