Chuyển lưu trữ dữ liệu sang data base
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-06-17 11:16:30 +07:00
parent 4054d81aaf
commit 098e1b2b69
45 changed files with 1971 additions and 1657 deletions

View File

@@ -0,0 +1,34 @@
#include "server/api_server.hpp"
#include "util/http_util.hpp"
namespace lm {
void ApiServer::registerDashboardRoutes(httplib::Server& svr)
{
svr.Get("/api/dashboards", [this](const httplib::Request&, httplib::Response& res) {
HttpUtil::addCors(res);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = dashboard_store_.snapshot().dump();
});
svr.Put("/api/dashboards", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
nlohmann::json body;
try
{
body = nlohmann::json::parse(req.body);
}
catch (...)
{
return HttpUtil::jsonError(res, 400, "invalid JSON");
}
std::string err;
if (!dashboard_store_.replace(body, err))
return HttpUtil::jsonError(res, 400, err);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = dashboard_store_.snapshot().dump();
});
}
} // namespace lm

View File

@@ -0,0 +1,197 @@
#include "server/api_server.hpp"
#include "util/file_util.hpp"
#include "util/http_util.hpp"
namespace lm {
void ApiServer::registerMediaRoutes(httplib::Server& svr)
{
svr.Get("/api/maps", [this](const httplib::Request&, httplib::Response& res) {
HttpUtil::addCors(res);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = nlohmann::json({{"maps", map_store_.list()}}).dump();
});
svr.Get(R"(/api/maps/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
const auto map = map_store_.find(id);
if (!map)
return HttpUtil::jsonError(res, 404, "map not found");
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = map->dump();
});
svr.Post("/api/maps", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
nlohmann::json body;
try
{
body = nlohmann::json::parse(req.body);
}
catch (...)
{
return HttpUtil::jsonError(res, 400, "invalid JSON");
}
std::string err;
const auto created = map_store_.create(body, err);
if (!created)
return HttpUtil::jsonError(res, 400, err);
res.status = 201;
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = created->dump();
});
svr.Put(R"(/api/maps/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
nlohmann::json body;
try
{
body = nlohmann::json::parse(req.body);
}
catch (...)
{
return HttpUtil::jsonError(res, 400, "invalid JSON");
}
std::string err;
if (!map_store_.update(id, body, err))
return HttpUtil::jsonError(res, 404, err);
const auto updated = map_store_.find(id);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = updated ? updated->dump() : nlohmann::json::object().dump();
});
svr.Delete(R"(/api/maps/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
std::string err;
if (!map_store_.remove(id, err))
return HttpUtil::jsonError(res, 404, err);
res.status = 204;
});
svr.Get(R"(/api/maps/([^/]+)/image$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
const auto path = map_store_.imagePath(id);
if (!path)
return HttpUtil::jsonError(res, 404, "map image not found");
res.set_header("Content-Type", HttpUtil::contentTypeForPath(*path));
res.body = FileUtil::readBinary(*path);
});
svr.Post(R"(/api/maps/([^/]+)/image$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
if (!req.form.has_file("file"))
return HttpUtil::jsonError(res, 400, "file is required");
const auto& file = req.form.get_file("file");
const std::string filename = file.filename.empty() ? "map.png" : file.filename;
std::string err;
if (!map_store_.saveImageFile(id, filename, file.content, err))
return HttpUtil::jsonError(res, 400, err);
const auto updated = map_store_.find(id);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = updated ? updated->dump() : nlohmann::json::object().dump();
});
svr.Get("/api/sounds", [this](const httplib::Request&, httplib::Response& res) {
HttpUtil::addCors(res);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = nlohmann::json({{"sounds", sound_store_.list()}}).dump();
});
svr.Get(R"(/api/sounds/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
const auto sound = sound_store_.find(id);
if (!sound)
return HttpUtil::jsonError(res, 404, "sound not found");
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = sound->dump();
});
svr.Post("/api/sounds", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
nlohmann::json body;
try
{
body = nlohmann::json::parse(req.body);
}
catch (...)
{
return HttpUtil::jsonError(res, 400, "invalid JSON");
}
std::string err;
const auto created = sound_store_.create(body, err);
if (!created)
return HttpUtil::jsonError(res, 400, err);
res.status = 201;
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = created->dump();
});
svr.Put(R"(/api/sounds/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
nlohmann::json body;
try
{
body = nlohmann::json::parse(req.body);
}
catch (...)
{
return HttpUtil::jsonError(res, 400, "invalid JSON");
}
std::string err;
if (!sound_store_.update(id, body, err))
return HttpUtil::jsonError(res, 404, err);
const auto updated = sound_store_.find(id);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = updated ? updated->dump() : nlohmann::json::object().dump();
});
svr.Delete(R"(/api/sounds/([^/]+)$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
std::string err;
if (!sound_store_.remove(id, err))
return HttpUtil::jsonError(res, 404, err);
res.status = 204;
});
svr.Get(R"(/api/sounds/([^/]+)/file$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
const auto path = sound_store_.filePath(id);
if (!path)
return HttpUtil::jsonError(res, 404, "sound file not found");
res.set_header("Content-Type", HttpUtil::contentTypeForPath(*path));
res.body = FileUtil::readBinary(*path);
});
svr.Post(R"(/api/sounds/([^/]+)/file$)", [this](const httplib::Request& req, httplib::Response& res) {
HttpUtil::addCors(res);
const std::string id = req.matches[1];
if (!req.form.has_file("file"))
return HttpUtil::jsonError(res, 400, "file is required");
const auto& file = req.form.get_file("file");
const std::string filename = file.filename.empty() ? (id + ".wav") : file.filename;
std::string err;
if (!sound_store_.saveFile(id, filename, file.content, err))
return HttpUtil::jsonError(res, 400, err);
const auto updated = sound_store_.find(id);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = updated ? updated->dump() : nlohmann::json::object().dump();
});
svr.Get("/api/recordings", [](const httplib::Request&, httplib::Response& res) {
HttpUtil::addCors(res);
res.set_header("Content-Type", "application/json; charset=utf-8");
res.body = nlohmann::json({{"recordings", nlohmann::json::array()}}).dump();
});
}
} // namespace lm

View File

@@ -15,13 +15,19 @@ ApiServer::ApiServer(StateRepository& repo,
MissionStore& mission_store,
ModbusTriggerService& modbus,
MissionScheduler& scheduler,
RobotRuntime& robot_runtime)
RobotRuntime& robot_runtime,
MapStore& map_store,
SoundStore& sound_store,
DashboardStore& dashboard_store)
: repo_(repo),
mission_queue_(mission_queue),
mission_store_(mission_store),
modbus_(modbus),
scheduler_(scheduler),
robot_runtime_(robot_runtime)
robot_runtime_(robot_runtime),
map_store_(map_store),
sound_store_(sound_store),
dashboard_store_(dashboard_store)
{
}
@@ -541,6 +547,8 @@ void ApiServer::registerRoutes(httplib::Server& svr)
registerIntegrationRoutes(svr);
registerMirV2Routes(svr);
registerRobotRoutes(svr);
registerMediaRoutes(svr);
registerDashboardRoutes(svr);
}
} // namespace lm

View File

@@ -7,6 +7,9 @@
#include "mission/mission_store.hpp"
#include "mission/modbus_trigger_service.hpp"
#include "robot/robot_runtime.hpp"
#include "storage/dashboard_store.hpp"
#include "storage/map_store.hpp"
#include "storage/sound_store.hpp"
#include "storage/state_repository.hpp"
namespace lm {
@@ -19,7 +22,10 @@ public:
MissionStore& mission_store,
ModbusTriggerService& modbus,
MissionScheduler& scheduler,
RobotRuntime& robot_runtime);
RobotRuntime& robot_runtime,
MapStore& map_store,
SoundStore& sound_store,
DashboardStore& dashboard_store);
void registerRoutes(httplib::Server& svr);
@@ -30,6 +36,9 @@ private:
ModbusTriggerService& modbus_;
MissionScheduler& scheduler_;
RobotRuntime& robot_runtime_;
MapStore& map_store_;
SoundStore& sound_store_;
DashboardStore& dashboard_store_;
bool enqueueRequest(const nlohmann::json& request, httplib::Response& res, int status_code = 201);
std::optional<nlohmann::json> enqueueMission(const nlohmann::json& request, std::string& err);
@@ -38,6 +47,8 @@ private:
void registerMirV2Routes(httplib::Server& svr);
void registerIntegrationRoutes(httplib::Server& svr);
void registerRobotRoutes(httplib::Server& svr);
void registerMediaRoutes(httplib::Server& svr);
void registerDashboardRoutes(httplib::Server& svr);
};
} // namespace lm