220 lines
7.5 KiB
C++
220 lines
7.5 KiB
C++
#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();
|
|
}
|