175 lines
4.9 KiB
C++
175 lines
4.9 KiB
C++
#include "ParkingStatusHttpServer.h"
|
|
|
|
#include <algorithm>
|
|
#include <exception>
|
|
#include <ios>
|
|
#include <ostream>
|
|
#include <utility>
|
|
|
|
#include "Poco/Exception.h"
|
|
#include "Poco/Net/HTTPServer.h"
|
|
#include "Poco/Net/HTTPRequest.h"
|
|
#include "Poco/Net/HTTPRequestHandler.h"
|
|
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
|
#include "Poco/Net/HTTPServerParams.h"
|
|
#include "Poco/Net/HTTPServerRequest.h"
|
|
#include "Poco/Net/HTTPServerResponse.h"
|
|
#include "Poco/Net/ServerSocket.h"
|
|
#include "Poco/Net/SocketAddress.h"
|
|
#include "Poco/URI.h"
|
|
|
|
namespace {
|
|
|
|
const char* kStatusPath = "/api/parking/status";
|
|
|
|
bool IsStatusPath(const std::string& path)
|
|
{
|
|
return path == "/" ||
|
|
path == "/status" ||
|
|
path == "/api/status" ||
|
|
path == kStatusPath;
|
|
}
|
|
|
|
void WriteJson(Poco::Net::HTTPServerResponse& response,
|
|
Poco::Net::HTTPResponse::HTTPStatus status,
|
|
const std::string& body)
|
|
{
|
|
response.setStatus(status);
|
|
response.setContentType("application/json; charset=utf-8");
|
|
response.set("Cache-Control", "no-store");
|
|
response.setContentLength(static_cast<std::streamsize>(body.size()));
|
|
std::ostream& output = response.send();
|
|
output.write(body.data(), static_cast<std::streamsize>(body.size()));
|
|
}
|
|
|
|
class StatusRequestHandler : public Poco::Net::HTTPRequestHandler
|
|
{
|
|
public:
|
|
explicit StatusRequestHandler(ParkingStatusHttpServer::StatusProvider statusProvider)
|
|
: m_statusProvider(std::move(statusProvider))
|
|
{
|
|
}
|
|
|
|
void handleRequest(Poco::Net::HTTPServerRequest& request,
|
|
Poco::Net::HTTPServerResponse& response) override
|
|
{
|
|
if (request.getMethod() != Poco::Net::HTTPRequest::HTTP_GET) {
|
|
WriteJson(response,
|
|
Poco::Net::HTTPResponse::HTTP_METHOD_NOT_ALLOWED,
|
|
"{\"success\":false,\"message\":\"请求方法不支持\"}");
|
|
return;
|
|
}
|
|
|
|
const std::string path = Poco::URI(request.getURI()).getPath();
|
|
if (!IsStatusPath(path)) {
|
|
WriteJson(response,
|
|
Poco::Net::HTTPResponse::HTTP_NOT_FOUND,
|
|
"{\"success\":false,\"message\":\"接口不存在\"}");
|
|
return;
|
|
}
|
|
|
|
const std::string body = m_statusProvider
|
|
? m_statusProvider()
|
|
: std::string("{\"success\":false,\"message\":\"状态服务不可用\"}");
|
|
WriteJson(response, Poco::Net::HTTPResponse::HTTP_OK, body);
|
|
}
|
|
|
|
private:
|
|
ParkingStatusHttpServer::StatusProvider m_statusProvider;
|
|
};
|
|
|
|
class StatusRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory
|
|
{
|
|
public:
|
|
explicit StatusRequestHandlerFactory(ParkingStatusHttpServer::StatusProvider statusProvider)
|
|
: m_statusProvider(std::move(statusProvider))
|
|
{
|
|
}
|
|
|
|
Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest&) override
|
|
{
|
|
return new StatusRequestHandler(m_statusProvider);
|
|
}
|
|
|
|
private:
|
|
ParkingStatusHttpServer::StatusProvider m_statusProvider;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
ParkingStatusHttpServer::ParkingStatusHttpServer() = default;
|
|
|
|
ParkingStatusHttpServer::~ParkingStatusHttpServer()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
int ParkingStatusHttpServer::Start(const HttpServerConfig& config, StatusProvider statusProvider)
|
|
{
|
|
Stop();
|
|
m_lastError.clear();
|
|
|
|
if (!config.enabled) {
|
|
return 0;
|
|
}
|
|
|
|
if (!statusProvider) {
|
|
m_lastError = "HTTP状态服务缺少状态提供函数";
|
|
return -1;
|
|
}
|
|
|
|
try {
|
|
if (config.port <= 0 || config.port > 65535) {
|
|
m_lastError = "HTTP状态服务端口无效";
|
|
return -1;
|
|
}
|
|
|
|
const int maxQueued = std::max(1, config.maxQueued);
|
|
const std::string listenAddress = config.address.empty() ? "0.0.0.0" : config.address;
|
|
Poco::Net::ServerSocket socket;
|
|
socket.bind(Poco::Net::SocketAddress(listenAddress, config.port), true);
|
|
socket.listen(maxQueued);
|
|
|
|
Poco::Net::HTTPServerParams* params = new Poco::Net::HTTPServerParams();
|
|
params->setMaxQueued(maxQueued);
|
|
params->setMaxThreads(std::max(1, config.maxThreads));
|
|
|
|
m_server.reset(new Poco::Net::HTTPServer(
|
|
new StatusRequestHandlerFactory(std::move(statusProvider)),
|
|
socket,
|
|
params));
|
|
m_server->start();
|
|
m_running = true;
|
|
return 0;
|
|
} catch (const Poco::Exception& e) {
|
|
m_lastError = e.displayText();
|
|
} catch (const std::exception& e) {
|
|
m_lastError = e.what();
|
|
} catch (...) {
|
|
m_lastError = "HTTP状态服务启动异常";
|
|
}
|
|
|
|
m_server.reset();
|
|
m_running = false;
|
|
return -1;
|
|
}
|
|
|
|
void ParkingStatusHttpServer::Stop()
|
|
{
|
|
if (m_server) {
|
|
m_server->stopAll(true);
|
|
m_server.reset();
|
|
}
|
|
m_running = false;
|
|
}
|
|
|
|
bool ParkingStatusHttpServer::IsRunning() const
|
|
{
|
|
return m_running;
|
|
}
|
|
|
|
std::string ParkingStatusHttpServer::LastError() const
|
|
{
|
|
return m_lastError;
|
|
}
|