Permalink
Browse files

Debugger: Organize WebSocket event handling.

Just a starting point to organize it.  Trying to keep it simple.
  • Loading branch information...
unknownbrackets committed Apr 14, 2018
1 parent c2b9b5a commit b37d59e8fab30d5cb514e2eab591dd7d10b6cde2
View
@@ -1404,6 +1404,13 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Debugger/DisassemblyManager.h
Core/Debugger/WebSocket.cpp
Core/Debugger/WebSocket.h
Core/Debugger/WebSocket/Common.h
Core/Debugger/WebSocket/GameBroadcaster.cpp
Core/Debugger/WebSocket/GameBroadcaster.h
Core/Debugger/WebSocket/LogBroadcaster.cpp
Core/Debugger/WebSocket/LogBroadcaster.h
Core/Debugger/WebSocket/SteppingBroadcaster.cpp
Core/Debugger/WebSocket/SteppingBroadcaster.h
Core/Dialog/PSPDialog.cpp
Core/Dialog/PSPDialog.h
Core/Dialog/PSPGamedataInstallDialog.cpp
View
@@ -185,6 +185,9 @@
<ClCompile Include="..\ext\udis86\udis86.c" />
<ClCompile Include="AVIDump.cpp" />
<ClCompile Include="Debugger\WebSocket.cpp" />
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\LogBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\SteppingBroadcaster.cpp" />
<ClCompile Include="FileSystems\BlobFileSystem.cpp" />
<ClCompile Include="HLE\KUBridge.cpp" />
<ClCompile Include="HLE\sceUsbCam.cpp" />
@@ -534,6 +537,10 @@
<ClInclude Include="..\ext\udis86\udis86.h" />
<ClInclude Include="AVIDump.h" />
<ClInclude Include="Debugger\WebSocket.h" />
<ClInclude Include="Debugger\WebSocket\Common.h" />
<ClInclude Include="Debugger\WebSocket\GameBroadcaster.h" />
<ClInclude Include="Debugger\WebSocket\LogBroadcaster.h" />
<ClInclude Include="Debugger\WebSocket\SteppingBroadcaster.h" />
<ClInclude Include="FileSystems\BlobFileSystem.h" />
<ClInclude Include="HLE\KUBridge.h" />
<ClInclude Include="HLE\sceUsbCam.h" />
View
@@ -70,6 +70,9 @@
<Filter Include="MIPS\IR">
<UniqueIdentifier>{119ac973-e457-4025-9e1e-4fb34022ae23}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\WebSocket">
<UniqueIdentifier>{c21d9bb5-614d-451b-8c0b-3078b29122d8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ELF\ElfReader.cpp">
@@ -695,6 +698,15 @@
<ClCompile Include="Debugger\WebSocket.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\WebSocket\LogBroadcaster.cpp">
<Filter>Debugger\WebSocket</Filter>
</ClCompile>
<ClCompile Include="Debugger\WebSocket\SteppingBroadcaster.cpp">
<Filter>Debugger\WebSocket</Filter>
</ClCompile>
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp">
<Filter>Debugger\WebSocket</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@@ -1280,6 +1292,18 @@
<ClInclude Include="Debugger\WebSocket.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\LogBroadcaster.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\SteppingBroadcaster.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\GameBroadcaster.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\Common.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
View
@@ -15,113 +15,63 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <string>
#include "json/json_writer.h"
#include "net/websocket_server.h"
#include "Core/Debugger/WebSocket.h"
#include "Common/LogManager.h"
#include "Core/Debugger/WebSocket/Common.h"
// TODO: Move this to its own file?
class DebuggerLogListener : public LogListener {
public:
void Log(const LogMessage &msg) override {
std::lock_guard<std::mutex> guard(lock_);
messages_[nextMessage_] = msg;
nextMessage_++;
if (nextMessage_ >= BUFFER_SIZE)
nextMessage_ -= BUFFER_SIZE;
count_++;
}
std::vector<LogMessage> GetMessages() {
std::lock_guard<std::mutex> guard(lock_);
int splitPoint;
int readCount;
if (read_ + BUFFER_SIZE < count_) {
// We'll start with our oldest then.
splitPoint = nextMessage_;
readCount = Count();
} else {
splitPoint = read_;
readCount = count_ - read_;
}
read_ = count_;
std::vector<LogMessage> results;
int splitEnd = std::min(splitPoint + readCount, (int)BUFFER_SIZE);
for (int i = splitPoint; i < splitEnd; ++i) {
results.push_back(messages_[i]);
readCount--;
}
for (int i = 0; i < readCount; ++i) {
results.push_back(messages_[i]);
}
return results;
}
int Count() const {
return count_ < BUFFER_SIZE ? count_ : BUFFER_SIZE;
}
private:
enum { BUFFER_SIZE = 128 };
LogMessage messages_[BUFFER_SIZE];
std::mutex lock_;
int nextMessage_ = 0;
int count_ = 0;
int read_ = 0;
};
#include "Core/Debugger/WebSocket/GameBroadcaster.h"
#include "Core/Debugger/WebSocket/LogBroadcaster.h"
#include "Core/Debugger/WebSocket/SteppingBroadcaster.h"
struct DebuggerLogEvent {
std::string header;
std::string message;
int level;
const char *channel;
// TODO: Just for now, testing...
static void WebSocketTestEvent(net::WebSocketServer *ws, const JsonGet &data) {
ws->Send(DebuggerErrorEvent("Test message", LogTypes::LNOTICE));
}
operator std::string() {
JsonWriter j;
j.begin();
j.writeString("event", "log");
j.writeString("header", header);
j.writeString("message", message);
j.writeInt("level", level);
j.writeString("channel", channel);
j.end();
return j.str();
}
};
typedef void (*DebuggerEventHandler)(net::WebSocketServer *ws, const JsonGet &data);
static const std::unordered_map<std::string, DebuggerEventHandler> debuggerEvents({
{"test", &WebSocketTestEvent},
});
void HandleDebuggerRequest(const http::Request &request) {
net::WebSocketServer *ws = net::WebSocketServer::CreateAsUpgrade(request, "debugger.ppsspp.org");
if (!ws)
return;
DebuggerLogListener *logListener = new DebuggerLogListener();
if (LogManager::GetInstance())
LogManager::GetInstance()->AddListener(logListener);
LogBroadcaster logger;
GameBroadcaster game;
SteppingBroadcaster stepping;
// TODO: Handle incoming messages.
ws->SetTextHandler([&](const std::string &t) {
ws->Send(R"({"event":"error","message":"Bad message","level":2})");
JsonReader reader(t.c_str(), t.size());
if (!reader.ok()) {
ws->Send(DebuggerErrorEvent("Bad message: invalid JSON", LogTypes::LERROR));
return;
}
const JsonGet root = reader.root();
const char *event = root ? root.getString("event", nullptr) : nullptr;
if (!event) {
ws->Send(DebuggerErrorEvent("Bad message: no event property", LogTypes::LERROR));
return;
}
auto eventFunc = debuggerEvents.find(event);
if (eventFunc != debuggerEvents.end()) {
eventFunc->second(ws, root);
} else {
ws->Send(DebuggerErrorEvent("Bad message: unknown event", LogTypes::LERROR));
}
});
ws->SetBinaryHandler([&](const std::vector<uint8_t> &d) {
ws->Send(R"({"event":"error","message":"Bad message","level":2})");
ws->Send(DebuggerErrorEvent("Bad message", LogTypes::LERROR));
});
while (ws->Process(0.1f)) {
auto messages = logListener->GetMessages();
// TODO: Check for other conditions?
for (auto msg : messages) {
ws->Send(DebuggerLogEvent{msg.header, msg.msg, msg.level, msg.log});
}
continue;
while (ws->Process(1.0f / 60.0f)) {
// These send events that aren't just responses to requests.
logger.Broadcast(ws);
game.Broadcast(ws);
stepping.Broadcast(ws);
}
if (LogManager::GetInstance())
LogManager::GetInstance()->RemoveListener(logListener);
delete logListener;
delete ws;
}
@@ -0,0 +1,42 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string>
#include "json/json_reader.h"
#include "json/json_writer.h"
#include "net/websocket_server.h"
#include "Common/Log.h"
struct DebuggerErrorEvent {
DebuggerErrorEvent(const std::string m, LogTypes::LOG_LEVELS l) : message(m), level(l) {
}
std::string message;
LogTypes::LOG_LEVELS level;
operator std::string() {
JsonWriter j;
j.begin();
j.writeString("event", "error");
j.writeString("message", message);
j.writeInt("level", level);
j.end();
return j.str();
}
};
@@ -0,0 +1,38 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/Debugger/WebSocket/Common.h"
#include "Core/Debugger/WebSocket/GameBroadcaster.h"
#include "Core/System.h"
void GameBroadcaster::Broadcast(net::WebSocketServer *ws) {
// TODO: This is ugly. Implement proper information instead.
// TODO: Should probably include info about which game, etc.
GlobalUIState state = GetUIState();
if (prevState_ != state) {
if (state == UISTATE_PAUSEMENU) {
ws->Send(R"({"event":"game_pause"})");
} else if (state == UISTATE_INGAME && prevState_ == UISTATE_PAUSEMENU) {
ws->Send(R"({"event":"game_resume"})");
} else if (state == UISTATE_INGAME) {
ws->Send(R"({"event":"game_start"})");
} else if (state == UISTATE_MENU) {
ws->Send(R"({"event":"game_quit"})");
}
prevState_ = state;
}
}
@@ -0,0 +1,36 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Core/System.h"
namespace net {
class WebSocketServer;
}
struct GameBroadcaster {
public:
GameBroadcaster() {
prevState_ = GetUIState();
}
void Broadcast(net::WebSocketServer *ws);
private:
GlobalUIState prevState_;
};
Oops, something went wrong.

0 comments on commit b37d59e

Please sign in to comment.