map/das-dn/minio/ftp2minio.cpp

433 lines
13 KiB
C++
Raw Normal View History

2024-11-15 16:12:14 +08:00
#include "ftp2minio.h"
#include <iostream>
#include <fstream>
2024-12-10 10:14:40 +08:00
#include <regex>
2024-11-15 16:12:14 +08:00
FtpManage::FtpManage(const std::string user, const std::string password, const std::string id)
:Ftp_ip(id), User(user), Password(password)
{
CURLcode res = curl_global_init(CURL_GLOBAL_ALL); // 初始化全局环境只需要初始化一次
if (res != CURLE_OK)
{
vLog(LOG_ERROR, "curl_global_init() falied %s\n", curl_easy_strerror(res));
return;
}
}
FtpManage::~FtpManage()
{
if (curl)
{
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
//接收消息回调函数
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output)
{
size_t totalSize = size * nmemb;
output->append(static_cast<char*>(contents), totalSize);
return totalSize;
}
// 初始化curl
void FtpManage::SetURL()
{
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); // 设置长连接
curl_easy_setopt(curl, CURLOPT_USERPWD, (User + ':' + Password).c_str()); //设置用户名和密码
}
// 把带有路径的文件转换为文件名 D:/ggbond/123.jpg->123.jpg
std::string FtpManage::GetFileNameFromPath(const std::string& filePath)
{
if (filePath == "") return filePath;
//去除路径最后的空格
std::string retPath;
size_t lastBlank = filePath.find_last_not_of(' ');
if (lastBlank != std::string::npos)
{
retPath = filePath.substr(0, lastBlank+1);
}
else
{
return "";
}
size_t lastSlashPos = retPath.find_last_of("/\\");
if (lastSlashPos != std::string::npos)
{
return retPath.substr(lastSlashPos + 1);
}
else
{ // 如果没有找到斜杠或反斜杠,整个路径就是文件名
return retPath;
}
}
// 下载单一文件,把remoteFilePath的文件下载到localDirectory里面
bool FtpManage::DownloadFile(const char* remoteFilePath, const char* localDirectory)
{
SetURL();
_URL = Ftp_ip + remoteFilePath;
curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str()); // 设置请求的URL
if (curl)
{
FILE* fp = fopen((localDirectory + GetFileNameFromPath(remoteFilePath)).c_str(), "wb");
if (fp)
{ // 设置文件写入地址
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
// 执行任务
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
vLog(LOG_ERROR, "DownLoad file: %s failed<%s>.", remoteFilePath, curl_easy_strerror(res));
fclose(fp);
curl_easy_cleanup(curl);
return false;
}
else
{
vLog(LOG_DEBUG, "DownLoad file: %s successfully!\n", remoteFilePath);
fclose(fp);
}
}
else
{
vLog(LOG_ERROR, "file open failed!\n");
curl_easy_cleanup(curl); // 清除curl
return false;
}
}
curl_easy_cleanup(curl);
return true;
}
// 下载全部文件
bool FtpManage::DownloadAllFiles(const char* remoteFilePath, const char* localDirectory)
{
if (GetfilenameFromftp(remoteFilePath))
{
for (const auto& fns : fNs)
{
std::string filename = remoteFilePath + fns;
bool res = DownloadFile(filename.c_str(), localDirectory);
if (res) continue;
else
{
return false;
}
}
}
return true;
}
// 获取ftp某个文件夹内文件名
bool FtpManage::GetfilenameFromftp(const std::string filePath)
{
SetURL();
std::string path = Ftp_ip + filePath;
std::string fileName; // 文件名列表保存位置
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, path.c_str()); // 设置访问URL
curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); // 设置只返回文件
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fileName); // 设置只获取文件名列表
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // 设置get的回调函数
if (curl_easy_perform(curl) == CURLE_OK) //执行任务
{
fNs.clear();
size_t startPos = 0, endPos = 0;
while ((endPos = fileName.find('\n', startPos)) != std::string::npos )
{
std::string name = fileName.substr(startPos, endPos - startPos);
fNs.emplace_back(name);
startPos = endPos + 1;
}
}
}
else
{
return false;
}
curl_easy_cleanup(curl);
return true;
}
// 获取FTP文件夹内所有文件名的接口函数
const std::vector<std::string>& FtpManage::GetFilesName(const std::string filepath)
{
if (GetfilenameFromftp(filepath))
{
return fNs;
}
return std::vector<std::string>();
}
CFtp2MinioProcess::CFtp2MinioProcess()
{
m_pAftp = NULL;
}
CFtp2MinioProcess::~CFtp2MinioProcess()
{
if (m_pAftp) delete m_pAftp;
m_pAftp = NULL;
saveMapToFile();
}
void CFtp2MinioProcess::saveMapToFile(void)
{
char fileName[260];
snprintf(fileName, sizeof(fileName), "minioftp_%d.mem", GetCurID());
std::ofstream outFile(fileName);
if (!outFile)
{
vLog(LOG_ERROR, "Unable to open file for writing!\n");
return;
}
for (const auto& pair : fileName2Id_map)
{
outFile << pair.first << " " << pair.second << std::endl;
}
outFile.close();
}
void CFtp2MinioProcess::loadMapFromFile(void)
{
char fileName[260];
snprintf(fileName, sizeof(fileName), "minioftp_%d.mem", GetCurID());
std::ifstream inFile(fileName);
if (!inFile)
{
vLog(LOG_ERROR, "Unable to open file for reading!\n");
return;
}
std::string key;
int value;
fileName2Id_map.clear();
while (inFile >> key >> value) {
fileName2Id_map[key] = value; //如果键已经存在,则会更新其值
}
inFile.close();
}
BOOLEAN CFtp2MinioProcess::OnPreCreate(int id)
{
if (!CProcess::OnPreCreate(id)) return FALSE;
DWORD target_addr;
if (!GetOption(&m_nOptions, sizeof(m_nOptions)))
{ //获取新配置
vLog(LOG_DEBUG, "润阳ftp转modbus读取配置错误。");
return FALSE;
}
if (m_pAftp) m_pAftp = NULL;
target_addr = m_nOptions.net.target_addr;
char user[128] = "administrator";
char password[128] = "123456";
char ipaddress[128] = "127.0.0.1";
char remotePath[128] = "\0";
char localPath[128];
char url[256];
2024-12-10 10:14:40 +08:00
//char listpath[256];
2024-11-15 16:12:14 +08:00
snprintf(user, sizeof(user), "%s", m_nOptions.ftp.user);
snprintf(password, sizeof(password), "%s", m_nOptions.ftp.password);
snprintf(localPath, sizeof(localPath), "%s", m_nOptions.ftp.localPath);
m_localPath = std::string(localPath);
2024-12-10 10:14:40 +08:00
if (m_localPath.back() != '/') m_localPath += std::string("/");
2024-11-15 16:12:14 +08:00
char *escaped_string = escape_char_in_string(m_nOptions.ftp.remotePath, ' ');
if (!escaped_string) return FALSE;
snprintf(remotePath, sizeof(remotePath), "%s", escaped_string);
free(escaped_string);
memset(ipaddress, '\0', sizeof(ipaddress));
inet_ntop(AF_INET, &target_addr, ipaddress, 16);
snprintf(url, sizeof(url), "ftp://%s", ipaddress);
2024-12-10 10:14:40 +08:00
std::string listpaths(remotePath);
std::vector<std::string> splits = split(listpaths, ';');
for (std::vector<std::string>::iterator it = splits.begin(); it != splits.end(); it++)
{
if ((*it).back() != '/')
{
2024-12-16 12:29:35 +08:00
m_listPaths.push_back((*it) + "/");
2024-12-10 10:14:40 +08:00
}
else
{
2024-12-16 12:29:35 +08:00
m_listPaths.push_back((*it));
2024-12-10 10:14:40 +08:00
}
}
2024-11-15 16:12:14 +08:00
m_pAftp = new FtpManage(user, password, url);
fileName2Id_map.clear();
//读取列表
loadMapFromFile();
last_count = fileName2Id_map.size();
return TRUE;
}
BOOLEAN CFtp2MinioProcess::Run(void)
{
if (!CProcess::Run()) return FALSE;
return TRUE;
}
2024-12-10 10:14:40 +08:00
std::optional<std::string> CFtp2MinioProcess::extractDate(const std::string& filename, const std::string& regex)
{
std::regex datePattern(regex);//(R"(\d{4}-\d{2}-\d{2})");
std::smatch match;
if (std::regex_search(filename, match, datePattern))
{
return match.str(); // 返回匹配到的日期字符串
}
return std::nullopt; // 没有找到日期则返回 nullopt
}
2024-11-15 16:12:14 +08:00
BOOLEAN CFtp2MinioProcess::OnTimer(void)
{
if (!CProcess::OnTimer()) return FALSE;
BOOLEAN min_changed = FALSE;
if (last_min != system32.now.minute)
{
last_min = system32.now.minute;
min_changed = TRUE;
}
if (min_changed)
2024-12-10 10:14:40 +08:00
{
for (std::vector<std::string>::iterator it = m_listPaths.begin(); it != m_listPaths.end(); it++)
2024-11-15 16:12:14 +08:00
{
2024-12-10 10:14:40 +08:00
m_listPath = (*it);
if (m_listPath.empty()) continue;
// 检查字符串的最后一个字符是否为 '/'
vLog(LOG_DEBUG, "准备读取文件夹%s的内容\n", m_listPath.c_str());
for (const auto& n : m_pAftp->GetFilesName(m_listPath))
2024-11-15 16:12:14 +08:00
{
2024-12-10 10:14:40 +08:00
std::string remotefile = m_listPath + n;
std::string localpath = m_localPath;
if (fileName2Id_map.find(n) == fileName2Id_map.end())
{
fileName2Id_map.insert(fileName2Idmap::value_type(n, 0));
if (m_pAftp->DownloadFile(remotefile.c_str(), localpath.c_str()))
{
vLog(LOG_DEBUG, "下载成功!\n");
std::vector<std::string> tokens = split(m_listPath, '/');
push2minio(tokens[tokens.size() - 1], n);
}
}
else
2024-11-15 16:12:14 +08:00
{
2024-12-10 10:14:40 +08:00
vLog(LOG_WARN, "该文件:%s已经被下载。\n", n.c_str());
2024-11-15 16:12:14 +08:00
}
}
2024-12-10 10:14:40 +08:00
if (last_count != fileName2Id_map.size())
2024-11-15 16:12:14 +08:00
{
2024-12-10 10:14:40 +08:00
last_count = fileName2Id_map.size();
saveMapToFile();
2024-11-15 16:12:14 +08:00
}
}
}
return TRUE;
}
2024-12-10 10:14:40 +08:00
BOOLEAN CFtp2MinioProcess::push2minio(std::string parentDir, std::string pathName)
2024-11-15 16:12:14 +08:00
{
//创建URL
//minio::s3::BaseUrl base_url("http://192.168.109.187:9000");
minio::s3::BaseUrl base_url(m_nOptions.minio.url);
base_url.https = false;
//创建鉴权对象
//minio::creds::StaticProvider provider("das", "zaq12WSX");
minio::creds::StaticProvider provider(m_nOptions.minio.user, m_nOptions.minio.password);
// 创建客户端
minio::s3::Client client(base_url, &provider);
//std::string bucket_name = "test";
std::string bucket_name = std::string(m_nOptions.minio.bucket);
2024-12-10 10:14:40 +08:00
2024-11-15 16:12:14 +08:00
// 检查test桶是否存在
bool exist;
{
minio::s3::BucketExistsArgs args;
args.bucket = bucket_name;
minio::s3::BucketExistsResponse resp = client.BucketExists(args);
if (!resp) {
vLog(LOG_ERROR, "unable to do bucket existence check; %s\n", resp.Error());
return FALSE;
}
exist = resp.exist;
}
// 如果test桶不存在则创建test桶
if (!exist) {
minio::s3::MakeBucketArgs args;
args.bucket = bucket_name;
minio::s3::MakeBucketResponse resp = client.MakeBucket(args);
if (!resp) {
vLog(LOG_ERROR, "unable to create bucket; %s\n", resp.Error());
return FALSE;
}
}
// 上传文件
minio::s3::UploadObjectArgs args;
args.bucket = bucket_name;
//上传到桶中的绝对路径
//char *pYMDhms = strchr((char *)pathName.c_str(), '.');
//args.object = "/A-001/Alarm/" + pathName;
2024-12-10 10:14:40 +08:00
//args.object = std::string(m_nOptions.minio.object) + pathName;
auto date = extractDate(pathName, R"(\d{4}-\d{2}-\d{2})");
std::string date_string;
if (date.has_value())
{
//vLog(LOG_DEBUG, "fileName is: %s, Date is: %s\n", pathName.c_str(), date.value().c_str());
date_string = replaceChar(date.value(), '-', '/');
//vLog(LOG_DEBUG, "date_string is: %s\n", date_string.c_str());
}
else
{
date = extractDate(pathName, R"(\d{4}\d{2}\d{2})");
if (date.has_value())
{
//vLog(LOG_DEBUG, "fileName is: %s, Date is: %s\n", pathName.c_str(), date.value().c_str());
date_string = date.value().substr(0, 4) + std::string("/") + date.value().substr(4, 2) + std::string("/") + date.value().substr(6, 2) + std::string("/");
//vLog(LOG_DEBUG, "date_string is: %s\n", date_string.c_str());
}
else
{
vLog(LOG_DEBUG, "文件不存在时间格式\n");
return TRUE;
}
}
//return TRUE;
2024-12-16 12:11:04 +08:00
args.object = std::string(m_nOptions.minio.object) + std::string("/") + parentDir + std::string("/") + date_string + std::string("/") + pathName;
2024-11-15 16:12:14 +08:00
//本地文件系统中的绝对路径
2024-12-10 10:14:40 +08:00
args.filename = m_localPath + pathName;
2024-11-15 16:12:14 +08:00
minio::s3::UploadObjectResponse resp = client.UploadObject(args);
if (!resp) {
vLog(LOG_ERROR, "unable to upload object; %s\n", resp.Error());
return FALSE;
}
vLog(LOG_DEBUG, "'%s' is successfully uploaded as object '%s' to bucket 'test'.", args.filename.c_str(), args.object.c_str());
return TRUE;
}