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 }
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
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
0131 std::ostringstream sline;
0132 sline << header << "/" << path << "/" << relfilename;
0133
0134 lines.push_back(sline.str());
0135
0136
0137 sort(lines.begin(), lines.end());
0138
0139
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
0145 std::ofstream out(menufile.str());
0146 copy(olines.begin(), olines.end(), std::ostream_iterator<std::string>(out, "\n"));
0147 out.close();
0148
0149
0150
0151
0152
0153
0154
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
0166
0167
0168
0169
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
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
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
0215
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)
0224 {
0225 std::string sline = line.substr(dir.size() + 1);
0226
0227 pos2 = sline.find('/');
0228
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
0300
0301
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
0368
0369 fulldir << "/.htaccess";
0370 std::ofstream htaccess;
0371 htaccess.open(fulldir.str().c_str(), std::ios::trunc);
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
0427
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 }