From c2b9b5a9e81322dfb1bd0aab26e29174a123ce51 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 12 Apr 2018 22:11:11 -0700 Subject: [PATCH] Debugger: Serve a simple log listener WebSocket. Planning to add more functionality to it, and sharing the reporting port is possibly not ideal - although it would make discovery easier. --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 ++ Core/Debugger/WebSocket.cpp | 127 ++++++++++++++++++++++++++++++++++++ Core/Debugger/WebSocket.h | 24 +++++++ Core/WebServer.cpp | 4 ++ Core/WebServer.h | 3 +- android/jni/Android.mk | 1 + 8 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 Core/Debugger/WebSocket.cpp create mode 100644 Core/Debugger/WebSocket.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e0db28925..c4ef3860bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1402,6 +1402,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Debugger/SymbolMap.h Core/Debugger/DisassemblyManager.cpp Core/Debugger/DisassemblyManager.h + Core/Debugger/WebSocket.cpp + Core/Debugger/WebSocket.h Core/Dialog/PSPDialog.cpp Core/Dialog/PSPDialog.h Core/Dialog/PSPGamedataInstallDialog.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index b068e321e9..0d5a5c1940 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -184,6 +184,7 @@ + @@ -532,6 +533,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index fe637033f8..914b2e7ea1 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -692,6 +692,9 @@ Core + + Debugger + @@ -1274,6 +1277,9 @@ Core + + Debugger + diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp new file mode 100644 index 0000000000..3d9cb95a6f --- /dev/null +++ b/Core/Debugger/WebSocket.cpp @@ -0,0 +1,127 @@ +// Copyright (c) 2017- 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 +#include +#include "json/json_writer.h" +#include "net/websocket_server.h" +#include "Core/Debugger/WebSocket.h" +#include "Common/LogManager.h" + +// TODO: Move this to its own file? +class DebuggerLogListener : public LogListener { +public: + void Log(const LogMessage &msg) override { + std::lock_guard guard(lock_); + messages_[nextMessage_] = msg; + nextMessage_++; + if (nextMessage_ >= BUFFER_SIZE) + nextMessage_ -= BUFFER_SIZE; + count_++; + } + + std::vector GetMessages() { + std::lock_guard 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 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; +}; + +struct DebuggerLogEvent { + std::string header; + std::string message; + int level; + const char *channel; + + 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(); + } +}; + +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); + + // TODO: Handle incoming messages. + ws->SetTextHandler([&](const std::string &t) { + ws->Send(R"({"event":"error","message":"Bad message","level":2})"); + }); + ws->SetBinaryHandler([&](const std::vector &d) { + ws->Send(R"({"event":"error","message":"Bad message","level":2})"); + }); + + 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; + } + + if (LogManager::GetInstance()) + LogManager::GetInstance()->RemoveListener(logListener); + delete logListener; + delete ws; +} diff --git a/Core/Debugger/WebSocket.h b/Core/Debugger/WebSocket.h new file mode 100644 index 0000000000..73b4e5fe8f --- /dev/null +++ b/Core/Debugger/WebSocket.h @@ -0,0 +1,24 @@ +// Copyright (c) 2017- 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 + +namespace http { +class Request; +} + +void HandleDebuggerRequest(const http::Request &request); diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index 6b20646f2e..d0f7c39fe7 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -29,6 +29,7 @@ #include "Common/FileUtil.h" #include "Common/Log.h" #include "Core/Config.h" +#include "Core/Debugger/WebSocket.h" #include "Core/WebServer.h" enum class ServerStatus { @@ -188,6 +189,9 @@ static void ExecuteWebServer() { if (serverFlags & (int)WebServerFlags::DISCS) { RegisterDiscHandlers(http, &discPaths); } + if (serverFlags & (int)WebServerFlags::DEBUGGER) { + http->RegisterHandler("/debugger", &HandleDebuggerRequest); + } if (!http->Listen(g_Config.iRemoteISOPort)) { if (!http->Listen(0)) { diff --git a/Core/WebServer.h b/Core/WebServer.h index db0967cbf2..07c2efb4f0 100644 --- a/Core/WebServer.h +++ b/Core/WebServer.h @@ -17,8 +17,9 @@ enum class WebServerFlags { DISCS = 1, + DEBUGGER = 2, - ALL = 1, + ALL = 1 | 2, }; bool StartWebServer(WebServerFlags flags); diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 428134fbcb..2d6fa3f9f6 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -300,6 +300,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/WebServer.cpp \ $(SRC)/Core/Debugger/Breakpoints.cpp \ $(SRC)/Core/Debugger/SymbolMap.cpp \ + $(SRC)/Core/Debugger/WebSocket.cpp \ $(SRC)/Core/Dialog/PSPDialog.cpp \ $(SRC)/Core/Dialog/PSPGamedataInstallDialog.cpp \ $(SRC)/Core/Dialog/PSPMsgDialog.cpp \