diff --git a/ClassInfluxDB.cpp b/ClassInfluxDB.cpp new file mode 100644 index 0000000..4624c6b --- /dev/null +++ b/ClassInfluxDB.cpp @@ -0,0 +1,266 @@ +#include "ClassInfluxDB.h" + +#include + +InfluxDB::InfluxDB(){ + curl = curl_easy_init(); + databaseIP = ""; + respondCode = 0; + dataPoints = ""; + headers = nullptr; + influxVersionStr = ""; + influxVersion = -1; + token = ""; + connectionOK = false; +} + +InfluxDB::InfluxDB(std::string url, bool verbose){ + curl = curl_easy_init(); + if( verbose) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + SetURL(url); + respondCode = 0; + dataPoints = ""; + headers = nullptr; + influxVersionStr = ""; + influxVersion = -1; + token = ""; + connectionOK = false; +} + +InfluxDB::~InfluxDB(){ + curl_slist_free_all(headers); + curl_easy_cleanup(curl); +} + +void InfluxDB::SetURL(std::string url){ + // check the last char of url is "/" + if( url.back() != '/') { + this->databaseIP = url + "/"; + }else{ + this->databaseIP = url; + } +} + +void InfluxDB::SetToken(std::string token){ + this->token = token; + headers = curl_slist_append(headers, "Accept: application/csv"); + if( !token.empty() ) headers = curl_slist_append(headers, ("Authorization: Token " + token).c_str()); +} + +bool InfluxDB::TestingConnection(bool debug){ + CheckInfluxVersion(debug); + if( respond != CURLE_OK ) return false; + connectionOK = true; + return true; +} + +std::string InfluxDB::CheckInfluxVersion(bool debug){ + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "ping").c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); + curl_easy_setopt(curl, CURLOPT_HEADER, 1); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack); + std::string respondStr; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &respondStr); + + Execute(); + + if( respond != CURLE_OK) return "CURL Error."; + + if( debug) printf("%s\n", respondStr.c_str()); + + //Find Version from readBuffer + std::regex pattern(R"(X-Influxdb-Version: (.*))"); + std::smatch match; + + if (regex_search(respondStr, match, pattern)) { + influxVersionStr = match[1]; + + size_t dotPosition = influxVersionStr.find('.'); + if( dotPosition != std::string::npos){ + influxVersion = atoi(influxVersionStr.substr(dotPosition-1, 1).c_str()); + } + } + + // printf("Influx Version : %s | %u\n", influxVersionStr.c_str(), influxVersion); + + return respondStr; + +} + +std::string InfluxDB::CheckDatabases(){ + if( ! connectionOK ) return "no connection. try TestConnection() again."; + if( influxVersion == 2 && token.empty() ) return "token no provided, abort."; + + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str()); + + std::string postFields="q=Show databases"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack); + std::string respondStr; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &respondStr); + + Execute(); + + printf("|%s|\n", respondStr.c_str()); + + if( respond != CURLE_OK) return "CURL Error."; + + databaseList.clear(); + + // Split the input string into lines + std::istringstream iss(respondStr); + std::vector lines; + std::string line; + while (std::getline(iss, line)) { + printf("%s\n", line.c_str()); + lines.push_back(line); + } + + // Extract the third column from each line and store it in a vector + std::vector thirdColumn; + for (const auto& l : lines) { + std::istringstream lineIss(l); + std::string token; + for (int i = 0; std::getline(lineIss, token, ','); ++i) { + if (i == 2) { // Third column + databaseList.push_back(token); + break; + } + } + } + + // {//============ when output is JSON + // size_t pos = readBuffer.find("values"); + // if( pos > 0 ){ + // std::string kaka = readBuffer.substr(pos+8); + // pos = kaka.find("}"); + // kaka = kaka.substr(0, pos); + // int len = kaka.length(); + // bool startFlag = false; + // std::string lala; + // char yaya = '"'; + // for( int i = 0; i < len; i++){ + // if( startFlag == false && kaka[i] == yaya ) { + // startFlag = true; + // lala = ""; + // continue; + // } + // if( startFlag && kaka[i] == yaya ){ + // startFlag = false; + // databaseList.push_back(lala); + // continue; + // } + // if( startFlag ) lala += kaka[i]; + // } + // } + // } + + return respondStr; + +} + +void InfluxDB::PrintDataBaseList(){ + for( size_t i = 0; i < databaseList.size(); i++){ + printf("%2ld| %s\n", i, databaseList[i].c_str()); + } + +} + +std::string InfluxDB::Query(std::string databaseName, std::string influxQL_query){ + if( ! connectionOK ) return "no connection. try TestConnection() again."; + if( influxVersion == 2 && token.empty() ) return "token no provided, abort."; + + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query?db=" + databaseName).c_str()); + + std::string postFields = "q=" + influxQL_query; + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack); + std::string respondStr; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &respondStr); + + Execute(); + + //printf("|%s|\n", readBuffer.c_str()); + + return respondStr; +} + +void InfluxDB::CreateDatabase(std::string databaseName){ + if( ! connectionOK ) return ; + if( influxVersion == 2 && token.empty() ) return; + + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str()); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + std::string postFields = "q=CREATE DATABASE " + databaseName; + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); + + Execute(); +} + +void InfluxDB::AddDataPoint(std::string fullString){ + // printf(" InfluxDB::%s |%s| \n", __func__, fullString.c_str()); + dataPoints += fullString + "\n"; +} + +void InfluxDB::ClearDataPointsBuffer(){ + // printf(" InfluxDB::%s \n", __func__); + dataPoints = ""; +} + +void InfluxDB::PrintDataPoints(){ + // printf(" InfluxDB::%s \n", __func__); + printf("%s\n", dataPoints.c_str()); +} + +void InfluxDB::WriteData(std::string databaseName){ + if( ! connectionOK ) return ; + if( influxVersion == 2 && token.empty() ) return; + + // printf(" InfluxDB::%s \n", __func__); + if( dataPoints.length() == 0 ) return; + //printf("|%s|\n", (databaseIP + "write?db=" + databaseName).c_str()); + curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "write?db=" + databaseName).c_str()); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_HEADER, 0); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(dataPoints.length())); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataPoints.c_str()); + Execute(); +} + +void InfluxDB::Execute(){ + // printf(" InfluxDB::%s \n", __func__); + try{ + respond = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode); + //printf("==== respond %d (OK = %d)\n", respond, CURLE_OK); + if( respond != CURLE_OK ) printf("############# InfluxDB::Execute fail | %ld\n", respondCode); + } catch (std::exception& e){ // in case of unexpected error + printf("%s\n", e.what()); + respond = CURLE_SEND_ERROR; + } +} + +size_t InfluxDB::WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp){ + // printf(" InfluxDB::%s \n", __func__); + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} diff --git a/influxdb.h b/ClassInfluxDB.h similarity index 70% rename from influxdb.h rename to ClassInfluxDB.h index a731a78..f337a10 100644 --- a/influxdb.h +++ b/ClassInfluxDB.h @@ -9,8 +9,6 @@ class InfluxDB{ private: - - bool isURLValid; CURL * curl; CURLcode respond; @@ -18,24 +16,39 @@ class InfluxDB{ std::string databaseIP; std::string dataPoints; - + std::string token; + + struct curl_slist * headers; + std::vector databaseList; + + unsigned short influxVersion; + std::string influxVersionStr; + + bool connectionOK; static size_t WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp); void Execute(); public: - /// url = https://fsunuc.physics.fsu.edu/InfluxDB/ + InfluxDB(std::string url, bool verbose = false); + InfluxDB(); ~InfluxDB(); void SetURL(std::string url); - bool TestingConnection(); - bool IsURLValid() const {return isURLValid;} + void SetToken(std::string token); + bool TestingConnection(bool debug = false); + bool IsConnectionOK() const {return connectionOK;} - /// Query + unsigned short GetVersionNo() const {return influxVersion;} + std::string GetVersionString() const {return influxVersionStr;} + + /// Query, query will be in CSV format + std::string CheckInfluxVersion(bool debug = false); std::string CheckDatabases(); /// this save the list of database into databaseList + void PrintDataBaseList(); std::string Query(std::string databaseName, std::string query); /// the CheckDatabases() function must be called before diff --git a/Hit.h b/Hit.h index 854979f..0905e8f 100644 --- a/Hit.h +++ b/Hit.h @@ -153,7 +153,7 @@ class Hit { } void PrintEnergyTimeStamp(){ - printf("ch: %2d, energy: %u, timestamp: %llu ch, traceLenght: %lu\n", channel, energy, timestamp, traceLenght); + printf("ch: %2d, energy: %u, timestamp: %lu ch, traceLenght: %lu\n", channel, energy, timestamp, traceLenght); } std::string AnaProbeType(uint8_t probeType){ @@ -248,8 +248,8 @@ class Hit { } printf("ch : %2d (0x%02X), fail: %d, flush: %d\n", channel, channel, board_fail, flush); - if( DPPType == DPPType::PHA ) printf("energy: %u, timestamp: %llu, fine_timestamp: %u \n", energy, timestamp, fine_timestamp); - if( DPPType == DPPType::PSD ) printf("energy: %u, energy_S : %u, timestamp: %llu, fine_timestamp: %u \n", energy, energy_short, timestamp, fine_timestamp); + if( DPPType == DPPType::PHA ) printf("energy: %u, timestamp: %lu, fine_timestamp: %u \n", energy, timestamp, fine_timestamp); + if( DPPType == DPPType::PSD ) printf("energy: %u, energy_S : %u, timestamp: %lu, fine_timestamp: %u \n", energy, energy_short, timestamp, fine_timestamp); printf("flag (high): 0x%02X, (low): 0x%03X, traceLength: %lu\n", flags_high_priority, flags_low_priority, traceLenght); printf("Agg counter : %u, trigger Thr.: %u, downSampling: %u \n", aggCounter, trigger_threashold, downSampling); printf("AnaProbe Type: %s(%u), %s(%u)\n", AnaProbeType(analog_probes_type[0]).c_str(), analog_probes_type[0], diff --git a/SOLARIS_Qt6_DAQ.pro b/SOLARIS_Qt6_DAQ.pro index e4ff2e6..d4a5455 100644 --- a/SOLARIS_Qt6_DAQ.pro +++ b/SOLARIS_Qt6_DAQ.pro @@ -25,7 +25,7 @@ QMAKE_CFLAGS_RELEASE = -O0 # Input HEADERS += ClassDigitizer2Gen.h \ Hit.h \ - influxdb.h \ + ClassInfluxDB.h \ mainwindow.h \ digiSettingsPanel.h \ Digiparameters.h \ @@ -36,7 +36,7 @@ HEADERS += ClassDigitizer2Gen.h \ SOLARISpanel.h SOURCES += ClassDigitizer2Gen.cpp \ - influxdb.cpp \ + ClassInfluxDB.cpp \ main.cpp \ mainwindow.cpp \ digiSettingsPanel.cpp \ diff --git a/influxdb.cpp b/influxdb.cpp deleted file mode 100644 index afb8747..0000000 --- a/influxdb.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "influxdb.h" - - -InfluxDB::InfluxDB(std::string url, bool verbose){ - - curl = curl_easy_init(); - if( verbose) curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - SetURL(url); - respondCode = 0; - dataPoints = ""; -} - -InfluxDB::~InfluxDB(){ - curl_easy_cleanup(curl); -} - -void InfluxDB::SetURL(std::string url){ - // check the last char of url is "/" - if( url.back() != '/') { - this->databaseIP = url + "/"; - }else{ - this->databaseIP = url; - } -} - -bool InfluxDB::TestingConnection(){ - CheckDatabases(); - if( respond != CURLE_OK ) return false; - return true; -} - -std::string InfluxDB::CheckDatabases(){ - curl_easy_setopt(curl, CURLOPT_POST, 1); - - curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str()); - - std::string postFields="q=Show databases"; - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack); - std::string readBuffer; - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - - Execute(); - - //printf("|%s|\n", readBuffer.c_str()); - - if( respond != CURLE_OK) return ""; - - databaseList.clear(); - - size_t pos = readBuffer.find("values"); - - if( pos > 0 ){ - std::string kaka = readBuffer.substr(pos+8); - - pos = kaka.find("}"); - kaka = kaka.substr(0, pos); - - int len = kaka.length(); - bool startFlag = false; - std::string lala; - - char yaya = '"'; - - for( int i = 0; i < len; i++){ - - if( startFlag == false && kaka[i] == yaya ) { - startFlag = true; - lala = ""; - continue; - } - - if( startFlag && kaka[i] == yaya ){ - startFlag = false; - databaseList.push_back(lala); - continue; - } - if( startFlag ) lala += kaka[i]; - } - } - - return readBuffer; -} - -std::string InfluxDB::Query(std::string databaseName, std::string query){ - - curl_easy_setopt(curl, CURLOPT_POST, 1); - - curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query?db=" + databaseName).c_str()); - - std::string postFields = "q=" + query; - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallBack); - std::string readBuffer; - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - - Execute(); - - //printf("|%s|\n", readBuffer.c_str()); - - return readBuffer; -} - -void InfluxDB::CreateDatabase(std::string databaseName){ - curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "query").c_str()); - curl_easy_setopt(curl, CURLOPT_POST, 1); - - std::string postFields = "q=CREATE DATABASE " + databaseName; - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(postFields.length())); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.c_str()); - - Execute(); -} - -void InfluxDB::AddDataPoint(std::string fullString){ - dataPoints += fullString + "\n"; -} - -void InfluxDB::ClearDataPointsBuffer(){ - dataPoints = ""; -} - -void InfluxDB::PrintDataPoints(){ - printf("%s\n", dataPoints.c_str()); -} - -void InfluxDB::WriteData(std::string databaseName){ - if( dataPoints.length() == 0 ) return; - //printf("|%s|\n", (databaseIP + "write?db=" + databaseName).c_str()); - curl_easy_setopt(curl, CURLOPT_URL, (databaseIP + "write?db=" + databaseName).c_str()); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast(dataPoints.length())); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, dataPoints.c_str()); - Execute(); -} - - -void InfluxDB::Execute(){ - try{ - respond = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &respondCode); - //printf("==== respond %d (OK = %d)\n", respond, CURLE_OK); - if( respond != CURLE_OK) printf("############# InfluxDB::Execute fail\n"); - } catch (std::exception& e){ // in case of unexpected error - printf("%s\n", e.what()); - respond = CURLE_SEND_ERROR; - } -} - -size_t InfluxDB::WriteCallBack(char *contents, size_t size, size_t nmemb, void *userp){ - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; -} diff --git a/macro.h b/macro.h index afbdfd3..ebe3867 100644 --- a/macro.h +++ b/macro.h @@ -5,6 +5,8 @@ #define DAQLockFile "DAQLock.dat" #define PIDFile "pid.dat" +#include + //^================================= namespace Utility{ /// either haha is "0xFFF" or "12435", convert to 10-base diff --git a/mainwindow.cpp b/mainwindow.cpp index ed5edb6..bdb15be 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1448,6 +1448,13 @@ void MainWindow::ProgramSettingsPanel(){ lbDatbaseName->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbDatbaseName, rowID, 0); lDatbaseName = new QLineEdit(DatabaseName, &dialog); layout->addWidget(lDatbaseName, rowID, 1, 1, 2); + //-------- DataBase Token + rowID ++; + QLabel *lbDatbaseToken = new QLabel("Database Token *", &dialog); + lbDatbaseToken->setAlignment(Qt::AlignRight | Qt::AlignCenter); + layout->addWidget(lbDatbaseToken, rowID, 0); + lDatbaseToken = new QLineEdit(DatabaseToken, &dialog); layout->addWidget(lDatbaseToken, rowID, 1, 1, 2); + //-------- Elog IP rowID ++; QLabel *lbElogIP = new QLabel("Elog IP *", &dialog); @@ -1463,6 +1470,7 @@ void MainWindow::ProgramSettingsPanel(){ IPListStr = lIPDomain->text(); DatabaseIP = lDatbaseIP->text(); DatabaseName = lDatbaseName->text(); + DatabaseToken = lDatbaseToken->text(); ElogIP = lElogIP->text(); analysisPath = lAnalysisPath->text(); masterExpDataPath = lExpDataPath->text(); @@ -1544,7 +1552,8 @@ bool MainWindow::LoadProgramSettings(){ case 3 : analysisPath = line; break; case 4 : DatabaseIP = line; break; case 5 : DatabaseName = line; break; - case 6 : ElogIP = line; break; + case 6 : DatabaseToken = line; break; + case 7 : ElogIP = line; break; } count ++; @@ -1557,6 +1566,7 @@ bool MainWindow::LoadProgramSettings(){ LogMsg(" Analysis Path : " + analysisPath); LogMsg(" Database IP : " + DatabaseIP); LogMsg(" Database Name : " + DatabaseName); + LogMsg(" Database Token : " + DatabaseToken); LogMsg(" ElogIP : " + ElogIP); LogMsg(" Exp Data Path : " + masterExpDataPath); LogMsg(" Temp Exp. Name : " + expName); @@ -1649,6 +1659,7 @@ void MainWindow::SaveProgramSettings(){ file.write((analysisPath+"\n").toStdString().c_str()); file.write((DatabaseIP+"\n").toStdString().c_str()); file.write((DatabaseName+"\n").toStdString().c_str()); + file.write((DatabaseToken+"\n").toStdString().c_str()); file.write((ElogIP+"\n").toStdString().c_str()); file.write("//------------end of file."); @@ -2286,10 +2297,21 @@ void MainWindow::SetupInflux(){ influx = new InfluxDB(DatabaseIP.toStdString(), false); if( influx->TestingConnection() ){ - LogMsg(" InfluxDB URL ("+ DatabaseIP + ") is Valid "); + + LogMsg(" InfluxDB URL ("+ DatabaseIP + ") is Valid. Version : " + QString::fromStdString(influx->GetVersionString())+ " "); + + if( influx->GetVersionNo() > 1 && DatabaseToken.isEmpty() ) { + LogMsg("A Token is required for accessing the database."); + delete influx; + influx = nullptr; + return; + } + + influx->SetToken(DatabaseToken.toStdString()); //==== chck database exist LogMsg("List of database:"); + influx->CheckDatabases(); std::vector databaseList = influx->GetDatabaseList(); bool foundDatabase = false; for( int i = 0; i < (int) databaseList.size(); i++){ diff --git a/mainwindow.h b/mainwindow.h index 8edf721..c107d5b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -22,7 +22,8 @@ #include "macro.h" #include "ClassDigitizer2Gen.h" -#include "influxdb.h" +// #include "influxdb.h" +#include "ClassInfluxDB.h" #include "CustomThreads.h" @@ -174,6 +175,7 @@ private: QLineEdit * lIPDomain; QLineEdit * lDatbaseIP; QLineEdit * lDatbaseName; + QLineEdit * lDatbaseToken; QLineEdit * lElogIP; QStringList existGitBranches; @@ -188,6 +190,7 @@ private: QStringList IPList; QString DatabaseIP; QString DatabaseName; + QString DatabaseToken; QString ElogIP; //@------ experiment settings