完成上传

main
wuyize 2023-07-06 14:14:24 +08:00
parent d18183e835
commit 81624c2b5e
4 changed files with 220 additions and 67 deletions

View File

@ -44,46 +44,10 @@ Item {
"uuid": uuid "uuid": uuid
}]) }])
} }
FluButton { UploadButton {
Layout.alignment: Qt.AlignRight header: header
text: "上传"
onClicked: function () {
console.log("click")
fileDialog.open()
}
FileDialog {
id: fileDialog
onAccepted: function () {
let name = FileTransferManager.getFileName(selectedFile)
const size = FileTransferManager.getFileSize(
selectedFile)
const md5 = FileTransferManager.getFileMd5(selectedFile)
if (size <= 0 || md5 === '')
return
var body = {
"name": name,
"brief": "brief",
"size": size,
"md5": md5,
"tags": [],
"parentId": header.items.length
!== 0 ? header.items[header.items.length - 1].uuid : null
}
console.log("begin")
console.log(JSON.stringify(body))
Request.post("knowledge/file", JSON.stringify(body),
function (res, data) {
console.log(res)
console.log(data)
FileTransferManager.upload(
selectedFile, data.id,
data.ticket, name)
}, function (res, data) {
console.log(res)
})
}
}
} }
RowLayout { RowLayout {
id: fileListItemHeaderItem id: fileListItemHeaderItem
width: ListView.view.width width: ListView.view.width

View File

@ -39,13 +39,13 @@ FluArea {
Image { Image {
id: icon id: icon
source: type ? "qrc:/AicsKnowledgeBase/res/" + type + ".png" : "" source: type ? "qrc:/AicsKnowledgeBase/res/" + type + ".png" : ""
Layout.preferredHeight: 32 Layout.preferredHeight: 24
Layout.preferredWidth: 32 Layout.preferredWidth: 24
} }
FluText { FluText {
id: title id: title
font.bold: true font.bold: true
font.pointSize: 15 font.pointSize: 12
text: fileItem.title text: fileItem.title
} }
} }

View File

@ -0,0 +1,146 @@
import QtQuick 2.15
import QtQuick.Layouts
import FluentUI
import QtQuick.Dialogs
import "qrc:///AicsKnowledgeBase/qml/global"
import SignalFileOperation 1.0
import AicsKB.FileTransferManager
FluButton {
property var header
property var currentSelectedFile: null
Layout.alignment: Qt.AlignRight
text: "上传"
onClicked: function () {
console.log("click")
fileDialog.open()
}
FileDialog {
id: fileDialog
onAccepted: function () {
currentSelectedFile = selectedFile
popup.open()
}
onRejected: currentSelectedFile = null
}
FluPopup {
id: popup
focus: true
Rectangle {
id: layout_content
anchors.fill: parent
implicitWidth: Window.window == null ? 400 : Math.min(
Window.window.width, 400)
implicitHeight: text_title.height + text_message.height + layout_actions.height
color: 'transparent'
radius: 5
FluText {
id: text_title
font: FluTextStyle.TitleLarge
text: "上传知识文件"
topPadding: 20
leftPadding: 20
rightPadding: 20
wrapMode: Text.WrapAnywhere
anchors {
top: parent.top
left: parent.left
right: parent.right
}
}
FluText {
id: text_message
font: FluTextStyle.Body
wrapMode: Text.WrapAnywhere
text: "content"
topPadding: 14
leftPadding: 20
rightPadding: 20
bottomPadding: 14
anchors {
top: text_title.bottom
left: parent.left
right: parent.right
}
}
Rectangle {
id: layout_actions
height: 68
radius: 5
color: FluTheme.dark ? Qt.rgba(
32 / 255, 32 / 255, 32 / 255,
blurBackground ? blurOpacity - 0.4 : 1) : Qt.rgba(
243 / 255, 243 / 255, 243 / 255,
blurBackground ? blurOpacity - 0.4 : 1)
anchors {
top: text_message.bottom
left: parent.left
right: parent.right
}
RowLayout {
anchors {
centerIn: parent
margins: spacing
fill: parent
}
spacing: 15
FluButton {
id: negative_btn
Layout.fillWidth: true
Layout.fillHeight: true
text: "取消"
onClicked: {
popup.close()
}
}
FluFilledButton {
id: positive_btn
Layout.fillWidth: true
Layout.fillHeight: true
text: "上传"
onClicked: {
popup.close()
let name = FileTransferManager.getFileName(
currentSelectedFile)
const size = FileTransferManager.getFileSize(
currentSelectedFile)
const md5 = FileTransferManager.getFileMd5(
currentSelectedFile)
if (size <= 0 || md5 === '')
return
var body = {
"name": name,
"brief": "brief",
"size": size,
"md5": md5,
"tags": [],
"parentId": currentParentId()
}
console.log("begin")
console.log(JSON.stringify(body))
Request.post("knowledge/file",
JSON.stringify(body),
function (res, data) {
console.log(res)
console.log(data)
FileTransferManager.upload(
currentSelectedFile,
data.id, data.ticket,
name)
}, function (res, data) {
console.log(res)
})
}
}
}
}
}
}
function currentParentId() {
return header.items.length !== 0 ? header.items[header.items.length - 1].uuid : null
}
}

View File

@ -30,6 +30,24 @@ struct FileUploading : FileItem
std::unordered_map<QString, FileUploading> uploadingMap; std::unordered_map<QString, FileUploading> uploadingMap;
std::mutex uploadingMapMutex; std::mutex uploadingMapMutex;
CURL *initCurlWithCommonOptions()
{
CURL *curl = curl_easy_init();
if (!curl) {
qCritical() << "CURL INIT FAILED!";
return nullptr;
}
curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3000);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
//curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYPEER, 0L);
//curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYHOST, 0L);//不验证证书和HOST
return curl;
}
size_t writeDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj) size_t writeDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj)
{ {
auto buf = (FileDownloading *) obj; auto buf = (FileDownloading *) obj;
@ -41,9 +59,8 @@ size_t writeDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj)
size_t readDataFunc(void *ptr, size_t size, size_t nmemb, void *obj) size_t readDataFunc(void *ptr, size_t size, size_t nmemb, void *obj)
{ {
auto buf = (FileUploading *) obj; auto buf = (FileUploading *) obj;
auto readSize = size * nmemb; buf->file.read(reinterpret_cast<char *>(ptr), size * nmemb);
buf->file.read(reinterpret_cast<char *>(ptr), readSize); return buf->file.gcount();
return readSize;
} }
static int xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) static int xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
@ -113,25 +130,18 @@ static size_t writeDataCallback(void *contents, size_t size, size_t nmemb, void
} }
CURLcode CURLcode
httpGet(const std::string &url, std::string &response, long httpVersion = CURL_HTTP_VERSION_3ONLY, int timeout = 3000) httpGet(const std::string &url, std::string &response)
{ {
CURLcode res; CURLcode res;
// 获取easy handle // 获取easy handle
CURL *easy_handle = curl_easy_init(); CURL *easy_handle = initCurlWithCommonOptions();
if (!easy_handle) return CURLE_FAILED_INIT; if (!easy_handle) return CURLE_FAILED_INIT;
// 设置easy handle属性
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(easy_handle, CURLOPT_HTTP_VERSION, httpVersion);
curl_easy_setopt(easy_handle, CURLOPT_URL, (baseUrl + url).c_str()); curl_easy_setopt(easy_handle, CURLOPT_URL, (baseUrl + url).c_str());
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writeDataCallback); curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, writeDataCallback);
curl_easy_setopt(easy_handle, CURLOPT_TIMEOUT, timeout);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *) &response); curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, (void *) &response);
curl_easy_setopt(easy_handle, CURLOPT_FOLLOWLOCATION, 1L);
//curl_easy_setopt(easy_handle, CURLOPT_DEFAULT_PROTOCOL, "https");
//curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYPEER, 0L);
//curl_easy_setopt(easy_handle, CURLOPT_SSL_VERIFYHOST, 0L);//不验证证书和HOST
// 执行数据请求 // 执行数据请求
res = curl_easy_perform(easy_handle); res = curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle); curl_easy_cleanup(easy_handle);
@ -148,12 +158,40 @@ FileTransferManager::FileTransferManager(QObject *parent)
qDebug() << "HTTP3 FAILED"; qDebug() << "HTTP3 FAILED";
} }
bool uploadComplete(const QString &fileId, const QString &ticket)
{
CURLcode res;
auto curlHandle = initCurlWithCommonOptions();
if (!curlHandle) return false;
curl_httppost *formpost = nullptr;
curl_httppost *lastptr = nullptr;
curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "ticket",
CURLFORM_COPYCONTENTS, ticket.toStdString().c_str(),
CURLFORM_END);
curl_easy_setopt(curlHandle, CURLOPT_URL, (baseUrl + "File/" + fileId.toStdString() + "/complete").c_str());
curl_easy_setopt(curlHandle, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curlHandle);
curl_easy_cleanup(curlHandle);
curl_formfree(formpost);
return res == CURLE_OK;
}
void void
FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QString &ticket, const QString &fileName) FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QString &ticket, const QString &fileName)
{ {
qDebug() << fileUrl.fileName(); qDebug() << fileUrl.fileName();
QtConcurrent::run([fileUrl, fileId, ticket, fileName] { QtConcurrent::run([fileUrl, fileId, ticket, fileName] {
std::string resData;
if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData))
return false;
qDebug() << resData.c_str();
auto resJson = QJsonDocument::fromJson(resData.c_str());
//if(!resJson["isCompleted"].toBool())
auto fileSize = QFileInfo(fileUrl.toLocalFile()).size(); auto fileSize = QFileInfo(fileUrl.toLocalFile()).size();
@ -176,7 +214,7 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS
} }
CURLcode res; CURLcode res;
fileUploading.curlHandle = curl_easy_init(); fileUploading.curlHandle = initCurlWithCommonOptions();
if (!fileUploading.curlHandle) if (!fileUploading.curlHandle)
return false; return false;
@ -194,27 +232,33 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS
CURLFORM_END); CURLFORM_END);
curl_formadd(&formpost, &lastptr, curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "data", CURLFORM_COPYNAME, "file",
CURLFORM_FILENAME, fileName.toLocal8Bit().toStdString().c_str(),
CURLFORM_STREAM, &fileUploading, CURLFORM_STREAM, &fileUploading,
CURLFORM_CONTENTLEN, fileSize, CURLFORM_CONTENTLEN, fileSize,
CURLFORM_END); CURLFORM_END);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_URL, (baseUrl + fileId.toStdString()).c_str()); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_URL, (baseUrl + "File/" + fileId.toStdString()).c_str());
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_HTTPPOST, formpost); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_READFUNCTION, readDataFunc); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_READFUNCTION, readDataFunc);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_NOPROGRESS, false); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFOFUNCTION, uploadInfo); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFOFUNCTION, uploadInfo);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFODATA, &fileUploading); curl_easy_setopt(fileUploading.curlHandle, CURLOPT_XFERINFODATA, &fileUploading);
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_WRITEFUNCTION, writeDataCallback);
std::string response;
curl_easy_setopt(fileUploading.curlHandle, CURLOPT_WRITEDATA, (void *) &response);
qDebug() << "Begin Upload"; qDebug() << "Begin Upload";
qDebug() << ticket.toStdString().c_str();
qDebug() << std::to_string(fileSize).c_str();
res = curl_easy_perform(fileUploading.curlHandle); res = curl_easy_perform(fileUploading.curlHandle);
if (res == CURLE_OK) if (res == CURLE_OK)
qDebug() << "Upload Success"; qDebug() << "Upload Success";
else else
qDebug() << "Upload Failed"; qDebug() << "Upload Failed";
qDebug() << response.c_str();
curl_easy_cleanup(fileUploading.curlHandle); curl_easy_cleanup(fileUploading.curlHandle);
curl_formfree(formpost); curl_formfree(formpost);
fileUploading.file.close(); fileUploading.file.close();
@ -223,6 +267,8 @@ FileTransferManager::upload(const QUrl &fileUrl, const QString &fileId, const QS
uploadingMap.erase(fileId); uploadingMap.erase(fileId);
uploadingMapMutex.unlock(); uploadingMapMutex.unlock();
if (res == CURLE_OK)
uploadComplete(fileId, ticket);
}); });
} }
@ -231,11 +277,10 @@ curl_off_t getHttpFileSize(const std::string &url)
{ {
curl_off_t fileLength = 0; curl_off_t fileLength = 0;
CURL *handle = curl_easy_init(); CURL *handle = initCurlWithCommonOptions();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头 curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头
curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
if (curl_easy_perform(handle) == CURLE_OK) if (curl_easy_perform(handle) == CURLE_OK)
curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &fileLength); curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &fileLength);
@ -261,7 +306,7 @@ bool httpDownload(const std::string &url, const FileItem &item)
FileDownloading &obj = iter->second; FileDownloading &obj = iter->second;
obj.curlHandle = curl_easy_init(); obj.curlHandle = initCurlWithCommonOptions();
if (!obj.curlHandle) if (!obj.curlHandle)
return false; return false;
obj.totalSize = fileSize;//原始文件大小 obj.totalSize = fileSize;//原始文件大小
@ -273,10 +318,8 @@ bool httpDownload(const std::string &url, const FileItem &item)
return false; return false;
} }
curl_easy_setopt(obj.curlHandle, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0); curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0);
curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(obj.curlHandle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(obj.curlHandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(obj.curlHandle, CURLOPT_URL, url.c_str());
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj);
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, writeDataFunc); curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, writeDataFunc);
@ -377,7 +420,7 @@ void FileTransferManager::resume(const QString &fileId)
qDebug() << "Start Get"; qDebug() << "Start Get";
std::string resData; std::string resData;
if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData, CURL_HTTP_VERSION_1_1)) if (CURLE_OK != httpGet("File/" + fileId.toStdString() + "/status", resData))
return; return;
qDebug() << resData.c_str(); qDebug() << resData.c_str();