Add MainHUD gameplay UI, net handshake updates, and server maintenance mode.
Introduce UiManager/MainHUD prefab flow, strengthen GameNet/WsClient, and add AIServer maintenance endpoint support. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "auth.hpp"
|
||||
#include "crypto.hpp"
|
||||
#include "json.hpp"
|
||||
#include "maintenance.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
@@ -269,8 +270,8 @@ void ws_loop(socket_t s) {
|
||||
|
||||
} // namespace
|
||||
|
||||
HttpWsServer::HttpWsServer(db::Database& db, std::string host, uint16_t port)
|
||||
: db_(db), host_(std::move(host)), port_(port) {}
|
||||
HttpWsServer::HttpWsServer(db::Database& db, std::string host, uint16_t port, std::string maintenance_path)
|
||||
: db_(db), host_(std::move(host)), port_(port), maintenance_path_(std::move(maintenance_path)) {}
|
||||
|
||||
HttpWsServer::~HttpWsServer() { stop(); }
|
||||
|
||||
@@ -398,6 +399,18 @@ void HttpWsServer::handle_client(uintptr_t client_sock) {
|
||||
<< "\r\n";
|
||||
const auto resp = oss.str();
|
||||
if (!send_all(s, resp.data(), resp.size())) return;
|
||||
|
||||
// 维护模式:升级成功后下发 maintenance 并断开(客户端停重连)
|
||||
{
|
||||
const auto m = maintenance::load(maintenance_path_);
|
||||
if (m.enabled) {
|
||||
nlohmann::json body{{"op", "maintenance"}, {"message", m.message}, {"ok", false}};
|
||||
send_ws_text(s, body.dump());
|
||||
std::printf("[ws] maintenance reject pid=%lld\n", static_cast<long long>(pid));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::printf("[ws] open pid=%lld\n", static_cast<long long>(pid));
|
||||
ws_loop(s);
|
||||
std::printf("[ws] close pid=%lld\n", static_cast<long long>(pid));
|
||||
@@ -430,7 +443,18 @@ void HttpWsServer::handle_client(uintptr_t client_sock) {
|
||||
}
|
||||
|
||||
if (req.method == "GET" && req.path == "/health") {
|
||||
auto resp = http_response(200, "OK", "{\"ok\":true,\"service\":\"aiserver\"}");
|
||||
const auto m = maintenance::load(maintenance_path_);
|
||||
nlohmann::json body{{"ok", true}, {"service", "aiserver"}, {"maintenance", m.enabled}};
|
||||
if (m.enabled) body["message"] = m.message;
|
||||
auto resp = http_response(200, "OK", body.dump());
|
||||
send_all(s, resp.data(), resp.size());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method == "GET" && req.path == "/maintenance") {
|
||||
const auto m = maintenance::load(maintenance_path_);
|
||||
nlohmann::json body{{"enabled", m.enabled}, {"message", m.message}};
|
||||
auto resp = http_response(200, "OK", body.dump());
|
||||
send_all(s, resp.data(), resp.size());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
class HttpWsServer {
|
||||
public:
|
||||
HttpWsServer(db::Database& db, std::string host, uint16_t port);
|
||||
HttpWsServer(db::Database& db, std::string host, uint16_t port, std::string maintenance_path = {});
|
||||
~HttpWsServer();
|
||||
|
||||
bool start();
|
||||
@@ -22,6 +22,7 @@ class HttpWsServer {
|
||||
db::Database& db_;
|
||||
std::string host_;
|
||||
uint16_t port_;
|
||||
std::string maintenance_path_;
|
||||
std::atomic<bool> running_{false};
|
||||
uintptr_t listen_sock_ = static_cast<uintptr_t>(-1);
|
||||
std::thread accept_thread_;
|
||||
|
||||
+21
-8
@@ -10,22 +10,31 @@
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static void usage(const char* argv0) {
|
||||
std::printf("Usage: %s [--host 0.0.0.0] [--port 8080] [--db data/aiserver.db] [--daemon]\n", argv0);
|
||||
std::printf(
|
||||
"Usage: %s [--host 0.0.0.0] [--port 8080] [--db data/aiserver.db] "
|
||||
"[--maintenance data/maintenance.json] [--daemon]\n",
|
||||
argv0);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string host = "0.0.0.0";
|
||||
uint16_t port = 8080;
|
||||
std::string db_path = "data/aiserver.db";
|
||||
|
||||
std::string maintenance_path;
|
||||
bool daemon = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const std::string a = argv[i];
|
||||
if (a == "--host" && i + 1 < argc) host = argv[++i];
|
||||
else if (a == "--port" && i + 1 < argc) port = static_cast<uint16_t>(std::stoi(argv[++i]));
|
||||
else if (a == "--db" && i + 1 < argc) db_path = argv[++i];
|
||||
else if (a == "--daemon") daemon = true;
|
||||
if (a == "--host" && i + 1 < argc)
|
||||
host = argv[++i];
|
||||
else if (a == "--port" && i + 1 < argc)
|
||||
port = static_cast<uint16_t>(std::stoi(argv[++i]));
|
||||
else if (a == "--db" && i + 1 < argc)
|
||||
db_path = argv[++i];
|
||||
else if (a == "--maintenance" && i + 1 < argc)
|
||||
maintenance_path = argv[++i];
|
||||
else if (a == "--daemon")
|
||||
daemon = true;
|
||||
else if (a == "-h" || a == "--help") {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
@@ -36,6 +45,9 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (maintenance_path.empty())
|
||||
maintenance_path = (fs::path(db_path).parent_path() / "maintenance.json").string();
|
||||
|
||||
try {
|
||||
fs::create_directories(fs::path(db_path).parent_path());
|
||||
} catch (...) {
|
||||
@@ -47,15 +59,16 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
HttpWsServer server(database, host, port);
|
||||
HttpWsServer server(database, host, port, maintenance_path);
|
||||
if (!server.start()) {
|
||||
std::printf("Listen failed on %s:%u\n", host.c_str(), static_cast<unsigned>(port));
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::printf("AIServer listening http://%s:%u (POST /register /login, WS /ws?pid=&token=)\n",
|
||||
std::printf("AIServer listening http://%s:%u (POST /register /login, GET /maintenance, WS /ws)\n",
|
||||
host.c_str(), static_cast<unsigned>(port));
|
||||
std::printf("DB=%s\n", db_path.c_str());
|
||||
std::printf("MaintenanceFile=%s\n", maintenance_path.c_str());
|
||||
if (daemon) {
|
||||
std::printf("daemon mode: running until process killed\n");
|
||||
while (server.running()) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "maintenance.hpp"
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace maintenance {
|
||||
|
||||
State load(const std::string& path) {
|
||||
State s;
|
||||
if (path.empty()) return s;
|
||||
std::ifstream in(path);
|
||||
if (!in) return s;
|
||||
try {
|
||||
nlohmann::json j;
|
||||
in >> j;
|
||||
s.enabled = j.value("enabled", false);
|
||||
s.message = j.value("message", s.message);
|
||||
} catch (...) {
|
||||
// ignore malformed
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace maintenance
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace maintenance {
|
||||
|
||||
struct State {
|
||||
bool enabled = false;
|
||||
std::string message = "服务器维护中,请稍后再试。";
|
||||
};
|
||||
|
||||
/// 读取 JSON:{"enabled":true,"message":"..."};文件不存在则 enabled=false。
|
||||
State load(const std::string& path);
|
||||
|
||||
} // namespace maintenance
|
||||
Reference in New Issue
Block a user