feat: add websocket server
This commit is contained in:
@@ -23,11 +23,16 @@ Spoofer::Spoofer()
|
||||
_log->info("Spoofer init");
|
||||
|
||||
loadConfig();
|
||||
|
||||
_log->info("Starting WebSocket server");
|
||||
initServer();
|
||||
}
|
||||
|
||||
Spoofer::~Spoofer()
|
||||
{
|
||||
_log->info("Stopping WebSocket server");
|
||||
stopServer();
|
||||
|
||||
delete _log;
|
||||
}
|
||||
|
||||
@@ -113,6 +118,127 @@ void Spoofer::saveConfig()
|
||||
auto errCtx = glz::write_file_json(conf, configPath, buffer);
|
||||
if (errCtx.ec != glz::error_code::none) _log->error("Failed to save config to {}", configPath);
|
||||
}
|
||||
|
||||
/*
|
||||
websocket
|
||||
*/
|
||||
void Spoofer::initServer()
|
||||
{
|
||||
if (_wsServer) PANIC("Attempted to init websocket server from invalid state");
|
||||
_wsServer = new ix::WebSocketServer(WS_PORT, WS_ADDR);
|
||||
|
||||
_wsServer->setOnClientMessageCallback([this](std::shared_ptr<ix::ConnectionState> connectionState,
|
||||
ix::WebSocket& webSocket,
|
||||
const std::unique_ptr<ix::WebSocketMessage>& msg) {
|
||||
this->wsMessageCallback(connectionState, webSocket, msg);
|
||||
});
|
||||
|
||||
std::pair<bool, std::string> res = _wsServer->listen();
|
||||
if (!res.first) PANIC("Websocket server failed to start");
|
||||
|
||||
_log->verbose("WebSocket server running @ {}:{}", WS_ADDR, WS_PORT);
|
||||
|
||||
_wsServer->start();
|
||||
}
|
||||
|
||||
void Spoofer::stopServer()
|
||||
{
|
||||
if (_wsServer)
|
||||
{
|
||||
_wsServer->stop();
|
||||
delete _wsServer;
|
||||
_wsServer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Spoofer::wsMessageCallback(std::shared_ptr<ix::ConnectionState> /*connectionState*/, ix::WebSocket& webSocket,
|
||||
const std::unique_ptr<ix::WebSocketMessage>& msg)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
switch (msg->type)
|
||||
{
|
||||
case ix::WebSocketMessageType::Open:
|
||||
{
|
||||
_log->verbose("Websocket connection open, URI: {}", msg->openInfo.uri);
|
||||
WSMessages::Init initMsg;
|
||||
initMsg.profile.camperItems = _camperItems;
|
||||
initMsg.profile.camperAddons = _camperAddons;
|
||||
initMsg.profile.slasherAddons = _slasherAddons;
|
||||
initMsg.profile.camperOfferings = _camperOfferings;
|
||||
initMsg.profile.slasherOfferings = _slasherOfferings;
|
||||
initMsg.profile.globalOfferings = _globalOfferings;
|
||||
initMsg.profile.camperPerks = _camperPerks;
|
||||
initMsg.profile.slasherPerks = _slasherPerks;
|
||||
initMsg.profile.catalogItemIds = _catalogItemIds;
|
||||
initMsg.profile.dlcListGRDK = _dlcListGRDK;
|
||||
initMsg.profile.dlcListEGS = _dlcListEGS;
|
||||
initMsg.profile.dlcListSteam = _dlcListSteam;
|
||||
initMsg.profile.unlockedCharacters = _unlockedCharacters;
|
||||
initMsg.toggles.spoofItems = _spoofItems;
|
||||
initMsg.toggles.spoofPerks = _spoofPerks;
|
||||
initMsg.toggles.spoofCatalog = _spoofCatalog;
|
||||
initMsg.toggles.spoofDLCs = _spoofDLCs;
|
||||
std::string out;
|
||||
auto errCtx = glz::write_json(initMsg, out);
|
||||
if (errCtx && errCtx.ec != glz::error_code::none)
|
||||
_log->error("Error occurred while writing init msg");
|
||||
else
|
||||
webSocket.send(out);
|
||||
break;
|
||||
}
|
||||
case ix::WebSocketMessageType::Close:
|
||||
_log->verbose("Websocket connection close");
|
||||
break;
|
||||
case ix::WebSocketMessageType::Message:
|
||||
{
|
||||
WSMessages::Request req;
|
||||
auto err = glz::read_json(req, msg->str);
|
||||
if (err.ec != glz::error_code::none)
|
||||
{
|
||||
_log->error("Failed to parse websocket message");
|
||||
break;
|
||||
}
|
||||
switch (req.action)
|
||||
{
|
||||
case WSMessages::SYNC_STATE:
|
||||
{
|
||||
_camperItems = std::move(req.profile.camperItems);
|
||||
_camperAddons = std::move(req.profile.camperAddons);
|
||||
_slasherAddons = std::move(req.profile.slasherAddons);
|
||||
_camperOfferings = std::move(req.profile.camperOfferings);
|
||||
_slasherOfferings = std::move(req.profile.slasherOfferings);
|
||||
_globalOfferings = std::move(req.profile.globalOfferings);
|
||||
_camperPerks = std::move(req.profile.camperPerks);
|
||||
_slasherPerks = std::move(req.profile.slasherPerks);
|
||||
_catalogItemIds = std::move(req.profile.catalogItemIds);
|
||||
_dlcListGRDK = std::move(req.profile.dlcListGRDK);
|
||||
_dlcListEGS = std::move(req.profile.dlcListEGS);
|
||||
_dlcListSteam = std::move(req.profile.dlcListSteam);
|
||||
_unlockedCharacters = std::move(req.profile.unlockedCharacters);
|
||||
saveConfig();
|
||||
_log->verbose("Profile state synchronized.");
|
||||
break;
|
||||
}
|
||||
case WSMessages::SYNC_TOGGLES:
|
||||
{
|
||||
_spoofItems = req.toggles.spoofItems;
|
||||
_spoofPerks = req.toggles.spoofPerks;
|
||||
_spoofCatalog = req.toggles.spoofCatalog;
|
||||
_spoofDLCs = req.toggles.spoofDLCs;
|
||||
saveConfig();
|
||||
_log->verbose("Toggles synchronized.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
_log->warning("Unknown action: {}", static_cast<int>(req.action));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
proxy handlers
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user