年前提交
This commit is contained in:
219
http_server.cpp
Normal file
219
http_server.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "http_server.h"
|
||||
#include "camera.h"
|
||||
|
||||
QHash<unsigned long, Camera*> HttpServer::sockets;
|
||||
|
||||
HttpServer& HttpServer::instance() {
|
||||
static HttpServer server;
|
||||
return server;
|
||||
}
|
||||
|
||||
void HttpServer::start(const QString &host, int port) {
|
||||
hk_net_sdk_init(NULL); // 全局初始化一次
|
||||
|
||||
mg_mgr_init(&mgr);
|
||||
mg_log_set(MG_LL_INFO);
|
||||
|
||||
std::string url = "http://" + host.toStdString() + ":" + std::to_string(port);
|
||||
|
||||
struct mg_connection *conn = mg_http_listen(&mgr, url.c_str(), ev_handler, this);
|
||||
|
||||
if (conn == NULL) {
|
||||
qCritical().noquote() << "无法启动服务:" << QString::fromStdString(url);
|
||||
return;
|
||||
}
|
||||
|
||||
qInfo().noquote() << "服务运行中:" << QString::fromStdString(url);
|
||||
qInfo() << "按 Ctrl+C 停止服务!";
|
||||
|
||||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, [this]() {
|
||||
mg_mgr_poll(&mgr, 0);
|
||||
});
|
||||
timer->start(100);
|
||||
}
|
||||
|
||||
void HttpServer::stop() {
|
||||
hk_net_sdk_uninit(); // 全局反初始化一次
|
||||
|
||||
if (!timer) return;
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
delete timer;
|
||||
timer = nullptr;
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
qInfo() << "服务器已停止!";
|
||||
}
|
||||
|
||||
void HttpServer::ev_handler(struct mg_connection *conn, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
|
||||
std::string method(hm->method.buf, hm->method.len);
|
||||
|
||||
if (mg_match(hm->uri, mg_str("/dvr/t"), NULL)) {
|
||||
mg_ws_upgrade(conn, hm, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
QString data = QString::fromUtf8(hm->body.buf, hm->body.len);
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
mg_http_reply(conn, 400, "Content-Type: application/json\r\n", "{}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doc.isObject()) return;
|
||||
|
||||
// 已设置和特殊预置位
|
||||
if (mg_match(hm->uri, mg_str("/dvr/camera/preset/list"), NULL)) {
|
||||
QJsonObject packet = doc.object();
|
||||
CameraInfo cameraInfo = CameraInfo::parseFrom(packet);
|
||||
|
||||
Camera* camera = Camera::of(cameraInfo);
|
||||
bool ok = camera->login();
|
||||
if (ok) {
|
||||
std::vector<STRU_PRESET_CONFIG> presets = camera->presets();
|
||||
|
||||
QJsonArray list;
|
||||
for (const auto& preset : presets) {
|
||||
list.append(QJsonObject({{"id", static_cast<int>(preset.ui_no)}, {"special", preset.ui_especial == 1}, {"setted", preset.ui_enable == 1}}));
|
||||
}
|
||||
|
||||
QByteArray buffer = QJsonDocument(list).toJson(QJsonDocument::Compact);
|
||||
mg_http_reply(conn, 200, "Content-Type: application/json\r\n", buffer);
|
||||
} else {
|
||||
mg_http_reply(conn, 401, "Content-Type: application/json\r\n", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
// 设置预置位
|
||||
if (mg_match(hm->uri, mg_str("/dvr/camera/preset"), NULL)) {
|
||||
QJsonObject packet = doc.object();
|
||||
CameraInfo cameraInfo = CameraInfo::parseFrom(packet);
|
||||
|
||||
Camera* camera = Camera::of(cameraInfo);
|
||||
bool ok = camera->login();
|
||||
if (ok) {
|
||||
ok = camera->addPreset(packet);
|
||||
mg_http_reply(conn, ok ? 200 : 403, "Content-Type: application/json\r\n", "{}");
|
||||
} else {
|
||||
mg_http_reply(conn, 401, "Content-Type: application/json\r\n", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
// 关联可见光IP
|
||||
if (mg_match(hm->uri, mg_str("/dvr/camera/getViCameraIP"), NULL)) {
|
||||
QJsonObject packet = doc.object();
|
||||
CameraInfo cameraInfo = CameraInfo::parseFrom(packet);
|
||||
|
||||
Camera* camera = Camera::of(cameraInfo);
|
||||
bool ok = camera->login();
|
||||
|
||||
if (ok) {
|
||||
QString ip = camera->getViCameraIP();
|
||||
if (ip.isEmpty()) {
|
||||
mg_http_reply(conn, 404, "Content-Type: application/json\r\n", "{}");
|
||||
} else {
|
||||
mg_http_reply(conn, 200, "Content-Type: application/json\r\n", ip.toUtf8().constData());
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(conn, 401, "Content-Type: application/json\r\n", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
// 抓图
|
||||
if (mg_match(hm->uri, mg_str("/dvr/camera/capture"), NULL)) {
|
||||
QJsonObject packet = doc.object();
|
||||
CameraInfo cameraInfo = CameraInfo::parseFrom(packet);
|
||||
|
||||
Camera* camera = Camera::of(cameraInfo);
|
||||
bool ok = camera->login();
|
||||
|
||||
if (ok) {
|
||||
CaptureData result = camera->capture();
|
||||
|
||||
if (result.ok) {
|
||||
QByteArray data = result.image;
|
||||
|
||||
qint64 dataSize = data.size();
|
||||
mg_printf(conn, "HTTP/1.1 200 OK\r\n");
|
||||
mg_printf(conn, "Content-Type: application/octet-stream\r\n");
|
||||
mg_printf(conn, "Content-Length: %lld\r\n", dataSize);
|
||||
mg_printf(conn, "Connection: close\r\n");
|
||||
mg_printf(conn, "Cache-Control: no-cache\r\n");
|
||||
mg_printf(conn, "Accept-Ranges: bytes\r\n");
|
||||
mg_printf(conn, "\r\n");
|
||||
mg_send(conn, "", 0);
|
||||
|
||||
const int BUFFER_SIZE = 256 * 1024;
|
||||
qint64 totalSent = 0;
|
||||
const char* rawData = data.constData();
|
||||
while (totalSent < dataSize) {
|
||||
qint64 remaining = dataSize - totalSent;
|
||||
qint64 chunkSize = qMin(static_cast<qint64>(BUFFER_SIZE), remaining);
|
||||
mg_send(conn, rawData + totalSent, chunkSize);
|
||||
totalSent += chunkSize;
|
||||
if (totalSent % (4 * BUFFER_SIZE) == 0) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(conn, 500, "Content-Type: application/json\r\n", "{}");
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(conn, 401, "Content-Type: application/json\r\n", "{}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev == MG_EV_WS_MSG) {
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
|
||||
|
||||
QString data = QString::fromUtf8(wm->data.buf, wm->data.len);
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc.isObject()) {
|
||||
QJsonObject packet = doc.object();
|
||||
|
||||
QString event = packet["event"].toString();
|
||||
if (event == "camera:connect") {
|
||||
QJsonObject payload = packet["payload"].toObject();
|
||||
|
||||
CameraInfo cameraInfo = CameraInfo::parseFrom(payload);
|
||||
|
||||
Camera* camera = Camera::of(cameraInfo);
|
||||
bool ok = camera->login();
|
||||
if (ok) {
|
||||
camera->attach(conn);
|
||||
camera->startRealtimeTemperatureCallback();
|
||||
sockets.insert(conn->id, camera);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ev == MG_EV_CLOSE) {
|
||||
if (conn->is_websocket) {
|
||||
Camera* camera = sockets.take(conn->id);
|
||||
if (camera) {
|
||||
camera->unattach();
|
||||
camera->stopRealtimeTemperatureCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpServer::~HttpServer() {
|
||||
stop();
|
||||
}
|
||||
Reference in New Issue
Block a user