315 lines
10 KiB
C++
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");
|
|
}
|
|
}
|