复现已有算法

This commit is contained in:
cloud
2026-07-14 15:43:18 +08:00
parent abebd2a683
commit 50b8111fd9
860 changed files with 182250 additions and 18 deletions
@@ -0,0 +1,167 @@
#include <drogon/drogon.h>
#include <drogon/HttpController.h>
#include <drogon/HttpRequest.h>
#include <fstream>
using namespace drogon;
class StreamEchoReader : public RequestStreamReader
{
public:
StreamEchoReader(ResponseStreamPtr respStream)
: respStream_(std::move(respStream))
{
}
void onStreamData(const char *data, size_t length) override
{
LOG_INFO << "onStreamData[" << length << "]";
respStream_->send({data, length});
}
void onStreamFinish(std::exception_ptr ptr) override
{
if (ptr)
{
try
{
std::rethrow_exception(ptr);
}
catch (const std::exception &e)
{
LOG_ERROR << "onStreamError: " << e.what();
}
}
else
{
LOG_INFO << "onStreamFinish";
}
respStream_->close();
}
private:
ResponseStreamPtr respStream_;
};
class RequestStreamExampleCtrl : public HttpController<RequestStreamExampleCtrl>
{
public:
METHOD_LIST_BEGIN
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_echo, "/stream_echo", Post);
ADD_METHOD_TO(RequestStreamExampleCtrl::stream_upload,
"/stream_upload",
Post);
METHOD_LIST_END
void stream_echo(
const HttpRequestPtr &,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) const
{
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
[stream](ResponseStreamPtr respStream) {
stream->setStreamReader(
std::make_shared<StreamEchoReader>(std::move(respStream)));
});
callback(resp);
}
void stream_upload(
const HttpRequestPtr &req,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) const
{
struct Entry
{
MultipartHeader header;
std::string tmpName;
std::ofstream file;
};
auto files = std::make_shared<std::vector<Entry>>();
auto reader = RequestStreamReader::newMultipartReader(
req,
[files](MultipartHeader &&header) {
LOG_INFO << "Multipart name: " << header.name
<< ", filename:" << header.filename
<< ", contentType:" << header.contentType;
files->push_back({std::move(header)});
auto tmpName = drogon::utils::genRandomString(40);
if (!files->back().header.filename.empty())
{
files->back().tmpName = tmpName;
files->back().file.open("uploads/" + tmpName,
std::ios::trunc);
}
},
[files](const char *data, size_t length) {
if (files->back().tmpName.empty())
{
return;
}
auto &currentFile = files->back().file;
if (length == 0)
{
LOG_INFO << "file finish";
if (currentFile.is_open())
{
currentFile.flush();
currentFile.close();
}
return;
}
LOG_INFO << "data[" << length << "]: ";
if (currentFile.is_open())
{
LOG_INFO << "write file";
currentFile.write(data, length);
}
else
{
LOG_ERROR << "file not open";
}
},
[files, callback = std::move(callback)](std::exception_ptr ex) {
if (ex)
{
try
{
std::rethrow_exception(std::move(ex));
}
catch (const StreamError &e)
{
LOG_ERROR << "stream error: " << e.what();
}
catch (const std::exception &e)
{
LOG_ERROR << "multipart error: " << e.what();
}
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
resp->setBody("error\n");
callback(resp);
}
else
{
LOG_INFO << "stream finish, received " << files->size()
<< " files";
Json::Value respJson;
for (const auto &item : *files)
{
if (item.tmpName.empty())
continue;
Json::Value entry;
entry["name"] = item.header.name;
entry["filename"] = item.header.filename;
entry["tmpName"] = item.tmpName;
respJson.append(entry);
}
auto resp = HttpResponse::newHttpJsonResponse(respJson);
callback(resp);
}
});
stream->setStreamReader(std::move(reader));
}
};
+113
View File
@@ -0,0 +1,113 @@
#include <drogon/drogon.h>
#include <chrono>
#include <functional>
#include <mutex>
#include <unordered_map>
#include <trantor/utils/Logger.h>
#include <trantor/net/callbacks.h>
#include <trantor/net/TcpConnection.h>
using namespace drogon;
using namespace std::chrono_literals;
std::mutex mutex;
std::unordered_map<trantor::TcpConnectionPtr, std::function<void()>>
connMapping;
int main()
{
app().registerHandler(
"/stream",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback) {
const auto &weakConnPtr = req->getConnectionPtr();
if (auto connPtr = weakConnPtr.lock())
{
std::lock_guard lk(mutex);
connMapping.emplace(std::move(connPtr), [] {
LOG_INFO << "call stop or other options!!!!";
});
}
auto resp = drogon::HttpResponse::newAsyncStreamResponse(
[](drogon::ResponseStreamPtr stream) {
std::thread([stream =
std::shared_ptr<drogon::ResponseStream>{
std::move(stream)}]() mutable {
std::cout << std::boolalpha << stream->send("hello ")
<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << std::boolalpha << stream->send("world");
std::this_thread::sleep_for(std::chrono::seconds(2));
stream->close();
}).detach();
});
resp->setContentTypeCodeAndCustomString(
ContentType::CT_APPLICATION_JSON, "application/json");
callback(resp);
});
// Example: register a stream-mode function handler
app().registerHandler(
"/stream_req",
[](const HttpRequestPtr &req,
RequestStreamPtr &&stream,
std::function<void(const HttpResponsePtr &)> &&callback) {
if (!stream)
{
LOG_INFO << "stream mode is not enabled";
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k400BadRequest);
resp->setBody("no stream");
callback(resp);
return;
}
auto reader = RequestStreamReader::newReader(
[](const char *data, size_t length) {
LOG_INFO << "piece[" << length
<< "]: " << std::string_view{data, length};
},
[callback = std::move(callback)](std::exception_ptr ex) {
auto resp = HttpResponse::newHttpResponse();
if (ex)
{
try
{
std::rethrow_exception(std::move(ex));
}
catch (const std::exception &e)
{
LOG_ERROR << "stream error: " << e.what();
}
resp->setStatusCode(k400BadRequest);
resp->setBody("error\n");
callback(resp);
}
else
{
LOG_INFO << "stream finish";
resp->setBody("success\n");
callback(resp);
}
});
stream->setStreamReader(std::move(reader));
},
{Post});
LOG_INFO << "Server running on 127.0.0.1:8848";
app().enableRequestStream(); // This is for request stream.
app().setConnectionCallback([](const trantor::TcpConnectionPtr &conn) {
if (conn->disconnected())
{
std::lock_guard lk(mutex);
if (auto it = connMapping.find(conn); it != connMapping.end())
{
LOG_INFO << "disconnect";
connMapping[conn]();
connMapping.erase(conn);
}
}
});
app().addListener("127.0.0.1", 8848).run();
}