|
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 |
|
9 | 9 | #include "lldb/Protocol/MCP/Server.h" |
| 10 | +#include "lldb/Host/File.h" |
| 11 | +#include "lldb/Host/FileSystem.h" |
| 12 | +#include "lldb/Host/HostInfo.h" |
| 13 | +#include "lldb/Host/JSONTransport.h" |
10 | 14 | #include "lldb/Protocol/MCP/MCPError.h" |
11 | 15 | #include "lldb/Protocol/MCP/Protocol.h" |
| 16 | +#include "llvm/ADT/SmallString.h" |
| 17 | +#include "llvm/Support/FileSystem.h" |
12 | 18 | #include "llvm/Support/JSON.h" |
| 19 | +#include "llvm/Support/Signals.h" |
13 | 20 |
|
14 | | -using namespace lldb_protocol::mcp; |
15 | 21 | using namespace llvm; |
| 22 | +using namespace lldb_private; |
| 23 | +using namespace lldb_protocol::mcp; |
| 24 | + |
| 25 | +ServerInfoHandle::ServerInfoHandle() : ServerInfoHandle("") {} |
| 26 | + |
| 27 | +ServerInfoHandle::ServerInfoHandle(StringRef filename) : m_filename(filename) { |
| 28 | + if (!m_filename.empty()) |
| 29 | + sys::RemoveFileOnSignal(m_filename); |
| 30 | +} |
| 31 | + |
| 32 | +ServerInfoHandle::~ServerInfoHandle() { |
| 33 | + if (m_filename.empty()) |
| 34 | + return; |
| 35 | + |
| 36 | + sys::fs::remove(m_filename); |
| 37 | + sys::DontRemoveFileOnSignal(m_filename); |
| 38 | + m_filename.clear(); |
| 39 | +} |
| 40 | + |
| 41 | +ServerInfoHandle::ServerInfoHandle(ServerInfoHandle &&other) |
| 42 | + : m_filename(other.m_filename) { |
| 43 | + *this = std::move(other); |
| 44 | +} |
16 | 45 |
|
17 | | -llvm::json::Value lldb_protocol::mcp::toJSON(const ServerInfo &SM) { |
18 | | - return llvm::json::Object{{"connection_uri", SM.connection_uri}, |
19 | | - {"pid", SM.pid}}; |
| 46 | +ServerInfoHandle & |
| 47 | +ServerInfoHandle::operator=(ServerInfoHandle &&other) noexcept { |
| 48 | + m_filename = other.m_filename; |
| 49 | + other.m_filename.clear(); |
| 50 | + return *this; |
20 | 51 | } |
21 | 52 |
|
22 | | -bool lldb_protocol::mcp::fromJSON(const llvm::json::Value &V, ServerInfo &SM, |
23 | | - llvm::json::Path P) { |
24 | | - llvm::json::ObjectMapper O(V, P); |
25 | | - return O && O.map("connection_uri", SM.connection_uri) && |
26 | | - O.map("pid", SM.pid); |
| 53 | +json::Value lldb_protocol::mcp::toJSON(const ServerInfo &SM) { |
| 54 | + return json::Object{{"connection_uri", SM.connection_uri}}; |
| 55 | +} |
| 56 | + |
| 57 | +bool lldb_protocol::mcp::fromJSON(const json::Value &V, ServerInfo &SM, |
| 58 | + json::Path P) { |
| 59 | + json::ObjectMapper O(V, P); |
| 60 | + return O && O.map("connection_uri", SM.connection_uri); |
| 61 | +} |
| 62 | + |
| 63 | +Expected<ServerInfoHandle> ServerInfo::Write(const ServerInfo &info) { |
| 64 | + std::string buf = formatv("{0}", toJSON(info)).str(); |
| 65 | + size_t num_bytes = buf.size(); |
| 66 | + |
| 67 | + FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir(); |
| 68 | + |
| 69 | + Status error(sys::fs::create_directory(user_lldb_dir.GetPath())); |
| 70 | + if (error.Fail()) |
| 71 | + return error.takeError(); |
| 72 | + |
| 73 | + FileSpec mcp_registry_entry_path = user_lldb_dir.CopyByAppendingPathComponent( |
| 74 | + formatv("lldb-mcp-{0}.json", getpid()).str()); |
| 75 | + |
| 76 | + const File::OpenOptions flags = File::eOpenOptionWriteOnly | |
| 77 | + File::eOpenOptionCanCreate | |
| 78 | + File::eOpenOptionTruncate; |
| 79 | + Expected<lldb::FileUP> file = |
| 80 | + FileSystem::Instance().Open(mcp_registry_entry_path, flags); |
| 81 | + if (!file) |
| 82 | + return file.takeError(); |
| 83 | + if (llvm::Error error = (*file)->Write(buf.data(), num_bytes).takeError()) |
| 84 | + return error; |
| 85 | + return ServerInfoHandle{mcp_registry_entry_path.GetPath()}; |
| 86 | +} |
| 87 | + |
| 88 | +Expected<std::vector<ServerInfo>> ServerInfo::Load() { |
| 89 | + namespace path = llvm::sys::path; |
| 90 | + FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir(); |
| 91 | + FileSystem &fs = FileSystem::Instance(); |
| 92 | + std::error_code EC; |
| 93 | + vfs::directory_iterator it = fs.DirBegin(user_lldb_dir, EC); |
| 94 | + vfs::directory_iterator end; |
| 95 | + std::vector<ServerInfo> infos; |
| 96 | + for (; it != end && !EC; it.increment(EC)) { |
| 97 | + auto &entry = *it; |
| 98 | + auto path = entry.path(); |
| 99 | + auto name = path::filename(path); |
| 100 | + if (!name.starts_with("lldb-mcp-") || !name.ends_with(".json")) |
| 101 | + continue; |
| 102 | + |
| 103 | + auto buffer = fs.CreateDataBuffer(path); |
| 104 | + auto info = json::parse<ServerInfo>(toStringRef(buffer->GetData())); |
| 105 | + if (!info) |
| 106 | + return info.takeError(); |
| 107 | + |
| 108 | + infos.emplace_back(std::move(*info)); |
| 109 | + } |
| 110 | + |
| 111 | + return infos; |
27 | 112 | } |
28 | 113 |
|
29 | 114 | Server::Server(std::string name, std::string version, |
|
0 commit comments