tsl-devkit/lsp-server/src/core/server.cpp

315 lines
10 KiB
C++

#include <exception>
#include <iostream>
#include <spdlog/spdlog.h>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#endif
#include "../provider/base/bootstrap.hpp"
#include "../service/base/bootstrap.hpp"
#include "../protocol/transform/facade.hpp"
#include "./server.hpp"
namespace lsp::core
{
LspServer::LspServer(size_t concurrency) :
async_executor_(4)
{
spdlog::info("Initializing LSP server with {} worker threads", concurrency);
InitializeCoreServices();
InitializeExtensionServices();
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetAllSupportedMethods().size());
}
LspServer::~LspServer()
{
is_shutting_down_ = true;
spdlog::info("LSP server shutting down...");
}
void LspServer::Run()
{
spdlog::info("LSP server starting main loop...");
// 设置二进制模式
#ifdef _WIN32
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stdin), _O_BINARY);
#endif
while (!is_shutting_down_)
{
try
{
std::optional<std::string> message = ReadMessage();
if (!message)
{
if (std::cin.eof())
{
spdlog::info("End of input stream, exiting main loop");
break; // EOF
}
spdlog::debug("No message received, continuing...");
continue;
}
HandleMessage(*message);
}
catch (const std::exception& e)
{
spdlog::error("Error in main loop: {}", e.what());
}
}
spdlog::info("LSP server main loop ended");
}
std::optional<std::string> LspServer::ReadMessage()
{
std::string line;
size_t content_length = 0;
// 读取 LSP Header
while (std::getline(std::cin, line))
{
// 去掉尾部 \r
if (!line.empty() && line.back() == '\r')
{
line.pop_back();
}
if (line.empty())
{
break; // 空行表示 header 结束
}
if (line.find("Content-Length:") == 0)
{
std::string length_str = line.substr(15); // 跳过 "Content-Length:"
size_t start = length_str.find_first_not_of(" ");
if (start != std::string::npos)
{
length_str = length_str.substr(start);
try
{
content_length = std::stoul(length_str);
spdlog::trace("Content-Length: {}", content_length);
}
catch (const std::exception& e)
{
spdlog::error("Failed to parse Content-Length: {}", e.what());
return std::nullopt;
}
}
}
}
if (content_length == 0)
{
spdlog::debug("No Content-Length found in header");
return std::nullopt;
}
// 读取内容体
std::string body(content_length, '\0');
std::cin.read(&body[0], content_length);
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
{
spdlog::error("Read incomplete message body, expected: {}, got: {}", content_length, std::cin.gcount());
return std::nullopt;
}
spdlog::trace("Received message: {}", body);
return body;
}
void LspServer::HandleMessage(const std::string& raw_message)
{
if (auto notification = transform::Deserialize<protocol::NotificationMessage>(raw_message))
HandleNotification(*notification);
else if (auto request = transform::Deserialize<protocol::RequestMessage>(raw_message))
HandleRequest(*request);
else if (auto response = transform::Deserialize<protocol::ResponseMessage>(raw_message))
HandleResponse(*response);
else
spdlog::error("Failed to deserialize message as any LSP message type");
}
void LspServer::HandleRequest(const protocol::RequestMessage& request)
{
std::string request_id = transform::debug::GetIdString(request.id);
spdlog::debug("Processing request - id: {}, method: {}", request_id, request.method);
// 检查是否可以处理请求
if (!CanProcessRequest(request.method))
{
SendStateError(request);
}
else
{
// 决定同步还是异步处理
if (RequiresSyncProcessing(request.method))
{
SendResponse(dispatcher_.Dispatch(request));
}
else
{
// 异步处理
async_executor_.Submit(request_id, [this, request]() -> std::optional<std::string> {
if (is_shutting_down_)
{
spdlog::debug("Skipping request {} due to shutdown", request.method);
return std::nullopt;
}
try
{
return dispatcher_.Dispatch(request);
}
catch (const std::exception& e)
{
spdlog::error("Request processing failed: {}", e.what());
return provider::BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, e.what());
} }, [this](const std::string& response) { SendResponse(response); });
}
spdlog::debug("Processing request method: {}", request.method);
}
}
void LspServer::HandleNotification(const protocol::NotificationMessage& notification)
{
spdlog::debug("Processing notification - method: {}", notification.method);
try
{
dispatcher_.Dispatch(notification);
}
catch (const std::exception& e)
{
spdlog::error("Notification processing failed for '{}': {}", notification.method, e.what());
}
}
void LspServer::HandleResponse(const protocol::ResponseMessage& response)
{
std::string id_str = transform::debug::GetIdString(response.id);
spdlog::debug("Received response - id: {}", id_str);
}
void LspServer::OnLifecycleEvent(provider::ServerLifecycleEvent event)
{
switch (event)
{
case provider::ServerLifecycleEvent::kInitializing:
spdlog::info("Server initializing...");
break;
case provider::ServerLifecycleEvent::kInitialized:
is_initialized_ = true;
spdlog::info("Server initialized successfully");
break;
case provider::ServerLifecycleEvent::kInitializeFailed:
is_initialized_ = false;
spdlog::error("Server initialization failed");
break;
case provider::ServerLifecycleEvent::kShuttingDown:
is_shutting_down_ = true;
spdlog::info("Server entering shutdown state");
break;
case provider::ServerLifecycleEvent::kShutdown:
is_shutting_down_ = true;
spdlog::info("Server shutdown complete");
break;
}
}
bool LspServer::RequiresSyncProcessing(const std::string& method) const
{
static const std::unordered_set<std::string> sync_methods = {
"initialize",
"shutdown"
};
return sync_methods.count(method) > 0;
}
bool LspServer::CanProcessRequest(const std::string& method) const
{
if (!is_initialized_)
return method == "initialize" || method == "exit";
if (is_shutting_down_)
return method == "exit";
return true;
}
void LspServer::HandleCancelRequest(const protocol::NotificationMessage& notification)
{
spdlog::info("Handle cancel request - method: {}", notification.method);
}
void LspServer::SendResponse(const std::string& response)
{
std::lock_guard<std::mutex> lock(output_mutex_);
size_t byte_length = response.length();
std::string header = "Content-Length: " + std::to_string(byte_length) + "\r\n\r\n";
// 发送 header 和 body
std::cout.write(header.c_str(), header.length());
std::cout.write(response.c_str(), response.length());
std::cout.flush();
spdlog::trace("Response sent - length: {}", byte_length);
spdlog::trace("Response sent - body: {}", response);
}
void LspServer::InitializeCoreServices()
{
spdlog::debug("Initializing core services...");
dispatcher_.SetRequestScheduler(&async_executor_);
dispatcher_.RegisterLifecycleCallback(
[this](provider::ServerLifecycleEvent event) {
OnLifecycleEvent(event);
});
provider::RegisterAllProviders(dispatcher_);
spdlog::debug("Core services initialized");
}
void LspServer::InitializeExtensionServices()
{
spdlog::debug("Initializing extension services...");
service::RegisterAllServices(service_registry_, async_executor_);
dispatcher_.SetSeviceRegistry(&service_registry_);
spdlog::debug("Extension services initialized");
}
void LspServer::SendError(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message)
{
spdlog::warn("Sending error response - method: {}, code: {}, message: {}", request.method, static_cast<int>(code), message);
std::string error_response = provider::BuildErrorResponseMessage(request, code, message);
SendResponse(error_response);
}
void LspServer::SendStateError(const protocol::RequestMessage& request)
{
if (!is_initialized_)
SendError(request, protocol::ErrorCodes::ServerNotInitialized, "Server not initialized");
else if (is_shutting_down_)
SendError(request, protocol::ErrorCodes::InvalidRequest, "Server is shutting down, only 'exit' is allowed");
else
SendError(request, protocol::ErrorCodes::InternalError, "Request not allowed in current state");
}
}