Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:20:55

0001 #include "OnlMonHtml.h"
0002 
0003 #include <onlmon/RunDBodbc.h>
0004 
0005 #include <dirent.h>
0006 #include <sys/stat.h>
0007 #include <algorithm>
0008 #include <cstddef>  // for size_t
0009 #include <cstring>
0010 #include <fstream>
0011 #include <iomanip>
0012 #include <iostream>
0013 #include <iterator>
0014 #include <set>
0015 #include <sstream>
0016 #include <vector>
0017 
0018 namespace
0019 {
0020   //___________________________________________________________________________
0021   std::vector<std::string> split(const char sep, const std::string& s)
0022   {
0023     std::string str = s;
0024     std::vector<size_t> slashes_pos;
0025 
0026     if (str[0] != sep)
0027     {
0028       str.insert(str.begin(), sep);
0029     }
0030 
0031     if (str[str.size() - 1] != sep)
0032     {
0033       str.push_back(sep);
0034     }
0035 
0036     for (size_t i = 0; i < str.size(); i++)
0037     {
0038       if (str[i] == sep)
0039       {
0040         slashes_pos.push_back(i);
0041       }
0042     }
0043 
0044     std::vector<std::string> parts;
0045 
0046     if (slashes_pos.size() > 0)
0047     {
0048       for (size_t i = 0; i < slashes_pos.size() - 1; i++)
0049       {
0050         parts.push_back(str.substr(slashes_pos[i] + 1,
0051                                    slashes_pos[i + 1] - slashes_pos[i] - 1));
0052       }
0053     }
0054 
0055     return parts;
0056   }
0057 
0058   //___________________________________________________________________________
0059   std::string join(const char sep, const std::vector<std::string>& parts)
0060   {
0061     std::string rv;
0062     for (size_t i = 0; i < parts.size(); ++i)
0063     {
0064       rv += parts[i];
0065       if (i + 1 < parts.size())
0066       {
0067         rv += sep;
0068       }
0069     }
0070     return rv;
0071   }
0072 }  // namespace
0073 
0074 //_____________________________________________________________________________
0075 OnlMonHtml::OnlMonHtml(const std::string& topdir)
0076   : fHtmlDir(topdir)
0077 {
0078   if (fHtmlDir.empty())
0079   {
0080     fHtmlDir = "./";
0081   }
0082   rundb = new RunDBodbc();
0083 }
0084 
0085 OnlMonHtml::~OnlMonHtml()
0086 {
0087   if (rundb)
0088   {
0089     delete rundb;
0090   }
0091 }
0092 
0093 //_____________________________________________________________________________
0094 void OnlMonHtml::addMenu(const std::string& header, const std::string& path,
0095                          const std::string& relfilename)
0096 {
0097   std::ostringstream menufile;
0098 
0099   menufile << fHtmlRunDir << "/menu";
0100 
0101   std::ifstream in(menufile.str().c_str());
0102 
0103   if (!in.good())
0104   {
0105     if (verbosity())
0106     {
0107       std::cout << __PRETTY_FUNCTION__ << "File " << menufile.str() << " does not exist."
0108                 << "I'm creating it now" << std::endl;
0109     }
0110     std::ofstream out(menufile.str().c_str());
0111     out.close();
0112   }
0113   else
0114   {
0115     if (verbosity())
0116     {
0117       std::cout << __PRETTY_FUNCTION__ << "Reading file " << menufile.str() << std::endl;
0118     }
0119   }
0120 
0121   // we read back the old menu file...
0122   std::vector<std::string> lines;
0123   char str[1024];
0124   while (in.getline(str, 1024, '\n'))
0125   {
0126     lines.emplace_back(str);
0127   }
0128   in.close();
0129 
0130   // ... we then append the requested new entry...
0131   std::ostringstream sline;
0132   sline << header << "/" << path << "/" << relfilename;
0133 
0134   lines.push_back(sline.str());
0135 
0136   // ... and we sort this out...
0137   sort(lines.begin(), lines.end());
0138 
0139   // ... and we remove duplicates lines...
0140   std::set<std::string> olines;
0141   copy(lines.begin(), lines.end(),
0142        std::insert_iterator<std::set<std::string> >(olines, olines.begin()));
0143 
0144   // ... and finally we write the full new menu file out.
0145   std::ofstream out(menufile.str());
0146   copy(olines.begin(), olines.end(), std::ostream_iterator<std::string>(out, "\n"));
0147   out.close();
0148 
0149   // --end of normal menu generation--
0150 
0151   // -- For those who do not have javascript (and thus the menu file
0152   // created by addMenu will be useless) or
0153   // in case cgi script(s) won't be allowed for some reason,
0154   // make a plain html menu file too.
0155   plainHtmlMenu(olines);
0156 }
0157 
0158 //_____________________________________________________________________________
0159 void OnlMonHtml::plainHtmlMenu(const std::set<std::string>& olines)
0160 {
0161   std::ostringstream htmlmenufile;
0162 
0163   htmlmenufile << fHtmlRunDir << "/menu.html";
0164 
0165   // First get the list of directories found in menu file above (contained
0166   // in olines set). The olines are of the form:
0167   // D1/D2/TITLE/link (where link is generally somefile.gif)
0168   // The dir in this case is D1/D2, which is why we look for 2 slashes
0169   // below (the one before TITLE and the one before link).
0170   std::set<std::string> dirlist;
0171   std::set<std::string>::const_iterator it;
0172   for (it = olines.begin(); it != olines.end(); ++it)
0173   {
0174     const std::string& line = *it;
0175     std::string::size_type pos = line.find_last_of('/');
0176     pos = line.substr(0, pos).find_last_of('/');
0177     std::string dir = line.substr(0, pos);
0178     std::vector<std::string> parts = split('/', dir);
0179     for (size_t i = 0; i <= parts.size(); ++i)
0180     {
0181       std::string dir2 = join('/', parts);
0182       dirlist.insert(dir2);
0183       parts.pop_back();
0184     }
0185   }
0186 
0187   // We now generate the menu.html file.
0188   std::ofstream out(htmlmenufile.str().c_str());
0189   if (!out.good())
0190   {
0191     std::cout << __PRETTY_FUNCTION__ << " cannot open output file "
0192               << htmlmenufile.str() << std::endl;
0193     return;
0194   }
0195 
0196   for (it = dirlist.begin(); it != dirlist.end(); ++it)
0197   {
0198     // in the example above, dir is D1/D2
0199     const std::string& dir = *it;
0200     int nslashes = count(dir.begin(), dir.end(), '/') + 1;
0201     std::string name = dir;
0202     std::string::size_type pos = dir.find_last_of('/');
0203     if (pos < dir.size())
0204     {
0205       name = dir.substr(pos + 1);
0206     }
0207     else
0208     {
0209       out << "<HR><BR>\n";
0210     }
0211     out << "<H" << nslashes << ">" << name
0212         << "</H" << nslashes << "><BR>\n";
0213 
0214     // We then loop on all the olines, and for those matching the
0215     // dir pattern, we generate link <A HREF="link">TITLE</A>
0216     std::set<std::string>::const_iterator it2;
0217     for (it2 = olines.begin(); it2 != olines.end(); ++it2)
0218     {
0219       const std::string& line = *it2;
0220       std::string::size_type pos2 = line.find_last_of('/');
0221       pos2 = line.substr(0, pos2).find_last_of('/');
0222       std::string ldir = line.substr(0, pos2);
0223       if (ldir == dir)  // we get a matching line
0224       {
0225         std::string sline = line.substr(dir.size() + 1);
0226         // in the example above, sline is TITLE/link...
0227         pos2 = sline.find('/');
0228         // ...which we split at the slash pos
0229         if (pos2 < sline.size())
0230         {
0231           out << "<A HREF=\""
0232               << sline.substr(pos + 1) << "\">"
0233               << sline.substr(0, pos) << "</A><BR>\n";
0234         }
0235       }
0236     }
0237   }
0238   out.close();
0239 }
0240 
0241 //_____________________________________________________________________________
0242 void OnlMonHtml::namer(const std::string& header,
0243                        const std::string& basefilename,
0244                        const std::string& ext,
0245                        std::string& fullfilename,
0246                        std::string& filename)
0247 {
0248   std::ostringstream sfilename;
0249 
0250   sfilename << header << "_";
0251   if (!basefilename.empty())
0252   {
0253     sfilename << basefilename << "_";
0254   }
0255   sfilename << runNumber() << "." << ext;
0256 
0257   std::ostringstream sfullfilename;
0258 
0259   sfullfilename << fHtmlRunDir << "/" << sfilename.str();
0260 
0261   fullfilename = sfullfilename.str();
0262   filename = sfilename.str();
0263 
0264   if (verbosity())
0265   {
0266     std::cout << __PRETTY_FUNCTION__ << "namer: header=" << header
0267               << " basefilename=" << basefilename << " ext=" << ext
0268               << std::endl
0269               << "fullfilename=" << fullfilename
0270               << " filename=" << filename
0271               << std::endl;
0272   }
0273 }
0274 
0275 //_____________________________________________________________________________
0276 std::string
0277 OnlMonHtml::registerPage(const std::string& header,
0278                          const std::string& path,
0279                          const std::string& basefilename,
0280                          const std::string& ext)
0281 {
0282   std::string fullfilename;
0283   std::string filename;
0284   std::string menupath = path;
0285   namer(header, basefilename, ext, fullfilename, filename);
0286   if (path.find('/') != std::string::npos)
0287   {
0288     std::cout << "OnlMonHtml::registerPage: found fatal \"/\" in path: \"" << path 
0289           << "\" stripping it" << std::endl;
0290   }
0291   menupath.erase(remove(menupath.begin(),menupath.end(),'/'),menupath.end());
0292   addMenu(header, menupath, filename);
0293   return fullfilename;
0294 }
0295 
0296 //_____________________________________________________________________________
0297 void OnlMonHtml::runInit()
0298 {
0299   // Check if html output directory for this run exist.
0300   // If not create it.
0301   // Then check (and create if necessary) the "menu" template file.
0302   std::string runtype = "unknowndata";
0303   std::string runtmp = rundb->RunType(fRunNumber);
0304   if (!runtmp.empty())
0305   {
0306     runtype = runtmp;
0307   }
0308   std::cout << "runtype is " << runtype << std::endl;
0309 
0310   std::ostringstream fulldir;
0311 
0312   fulldir << fHtmlDir << "/" << runtype << "/"
0313           << runRange() << "/" << runNumber();
0314 
0315   fHtmlRunDir = fulldir.str();
0316   DIR* htdir = opendir(fulldir.str().c_str());
0317   if (!htdir)
0318   {
0319     std::vector<std::string> mkdirlist;
0320     mkdirlist.push_back(fulldir.str());
0321     std::string updir = fulldir.str();
0322     std::string::size_type pos1;
0323     while ((pos1 = updir.rfind('/')) != std::string::npos)
0324     {
0325       updir.erase(pos1, updir.size());
0326       htdir = opendir(updir.c_str());
0327       if (!htdir)
0328       {
0329         mkdirlist.push_back(updir);
0330       }
0331       else
0332       {
0333         closedir(htdir);
0334         break;
0335       }
0336     }
0337     while (mkdirlist.rbegin() != mkdirlist.rend())
0338     {
0339       std::string md = *(mkdirlist.rbegin());
0340       if (verbosity())
0341       {
0342         std::cout << __PRETTY_FUNCTION__ << "Trying to create dir " << md << std::endl;
0343       }
0344       std::filesystem::perms permissions = std::filesystem::perms::owner_all | std::filesystem::perms::group_all | std::filesystem::perms::group_exec | std::filesystem::perms::others_read | std::filesystem::perms::others_exec;
0345       if (std::filesystem::create_directory(md))
0346       {
0347     if (verbosity())
0348     {
0349       std::cout << "created " << md << std::endl;
0350     }
0351         char* onlprod_real_html = getenv("ONLMON_REAL_HTML");
0352         if (!onlprod_real_html)
0353         {
0354           std::filesystem::permissions(md, permissions);
0355           set_group_sticky_bit(md);
0356         }
0357       }
0358       else
0359       {
0360         std::cout << "Error creating directory " << md << std::endl;
0361         fHtmlRunDir = fHtmlDir;
0362         break;
0363       }
0364       mkdirlist.pop_back();
0365     }
0366     fHtmlRunDir = fulldir.str();
0367     // use ostringstream fulldir which contains the full directory
0368     // to create .htaccess file for automatic gunzipping
0369     fulldir << "/.htaccess";
0370     std::ofstream htaccess;
0371     htaccess.open(fulldir.str().c_str(), std::ios::trunc);  // overwrite if exists
0372     htaccess << "<Files *.html.gz>" << std::endl;
0373     htaccess << "     AddEncoding x-gzip .gz" << std::endl;
0374     htaccess << "     AddType text/html .gz" << std::endl;
0375     htaccess << "</Files>" << std::endl;
0376     htaccess << "<Files *.txt.gz>" << std::endl;
0377     htaccess << "     AddEncoding x-gzip .gz" << std::endl;
0378     htaccess << "     AddType text/html .gz" << std::endl;
0379     htaccess << "</Files>" << std::endl;
0380     htaccess.close();
0381   }
0382   else
0383   {
0384     closedir(htdir);
0385   }
0386 
0387   if (verbosity())
0388   {
0389     std::cout << __PRETTY_FUNCTION__ << "OK. fHtmlRunDir=" << fHtmlRunDir << std::endl;
0390   }
0391 }
0392 
0393 //_____________________________________________________________________________
0394 void OnlMonHtml::runNumber(int runnumber)
0395 {
0396   fRunNumber = runnumber;
0397   runInit();
0398 }
0399 
0400 //_____________________________________________________________________________
0401 std::string
0402 OnlMonHtml::runRange()
0403 {
0404   const int range = 1000;
0405   int start = runNumber() / range;
0406 
0407   std::ostringstream s;
0408 
0409   s << "run_" << std::setw(10) << std::setfill('0') << start * range
0410     << "_" << std::setw(10) << std::setfill('0') << (start + 1) * range;
0411 
0412   return s.str();
0413 }
0414 
0415 void OnlMonHtml::set_group_sticky_bit(const std::filesystem::path& dir)
0416 {
0417   struct stat st
0418   {
0419   };
0420   if (stat(dir.c_str(), &st) != 0)
0421   {
0422     std::cout << "Failed to stat directory: " << std::strerror(errno) << std::endl;
0423     return;
0424   }
0425 
0426   // Add the setgid bit to the existing permissions
0427   // NOLINTNEXTLINE(hicpp-signed-bitwise)
0428   mode_t new_mode = st.st_mode | S_ISGID;
0429 
0430   if (chmod(dir.c_str(), new_mode) != 0)
0431   {
0432     std::cerr << "Failed to set group sticky bit: " << std::strerror(errno) << std::endl;
0433   }
0434   else
0435   {
0436     if (verbosity() > 0)
0437     {
0438       std::cout << "Group sticky bit set for directory: " << dir << std::endl;
0439     }
0440   }
0441 }