feat: support concurrency
This commit is contained in:
@@ -59,24 +59,27 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".so")
|
||||
find_package(glaze CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(Taskflow REQUIRED)
|
||||
|
||||
if(NOT TARGET spdlog::spdlog_header_only)
|
||||
message(WARNING "spdlog header-only target not found, using shared library")
|
||||
message(WARNING "spdlog header-only target not found, using shared library")
|
||||
endif()
|
||||
if(NOT TARGET fmt::fmt-header-only)
|
||||
message(WARNING "fmt header-only target not found, using shared library")
|
||||
message(WARNING "fmt header-only target not found, using shared library")
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/utils/args_parser.cpp
|
||||
src/language/tsl_keywords.cpp
|
||||
src/lsp/dispacther.cpp
|
||||
src/lsp/server.cpp
|
||||
src/lsp/request_scheduler.cpp
|
||||
src/provider/base/provider_registry.cpp
|
||||
src/provider/base/provider_interface.cpp
|
||||
src/provider/initialize/initialize_provider.cpp
|
||||
@@ -84,6 +87,7 @@ set(SOURCES
|
||||
src/provider/text_document/did_open_provider.cpp
|
||||
src/provider/text_document/did_change_provider.cpp
|
||||
src/provider/text_document/completion_provider.cpp
|
||||
src/provider/shutdown/shutdown_provider.cpp
|
||||
src/provider/trace/set_trace_provider.cpp)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
@@ -93,8 +97,8 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
||||
FMT_HEADER_ONLY)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME} PRIVATE glaze::glaze spdlog::spdlog_header_only
|
||||
fmt::fmt-header-only)
|
||||
${PROJECT_NAME} PRIVATE glaze::glaze Taskflow::Taskflow
|
||||
spdlog::spdlog_header_only fmt::fmt-header-only)
|
||||
|
||||
# Linux 需要链接 pthread
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
||||
@@ -5,29 +5,51 @@
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
void RequestDispatcher::RegisterProvider(const std::string& method, RequestProvider handler)
|
||||
void RequestDispatcher::RegisterProvider(std::shared_ptr<providers::ILspProvider> provider)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
providers_[method] = std::move(handler);
|
||||
std::string method = provider->GetMethod();
|
||||
|
||||
// 如果是生命周期感知的 Provider,设置回调
|
||||
if (auto lifecycle_aware = std::dynamic_pointer_cast<providers::ILifecycleAwareProvider>(provider))
|
||||
{
|
||||
lifecycle_aware->SetLifecycleCallback(
|
||||
[this](ServerLifecycleEvent event) {
|
||||
NotifyAllLifecycleListeners(event);
|
||||
});
|
||||
spdlog::debug("Registered lifecycle-aware provider for method: {}", method);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::debug("Registered standard provider for method: {}", method);
|
||||
}
|
||||
providers_[method] = provider;
|
||||
spdlog::debug("Registered provider for method: {}", method);
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterLifecycleCallback(LifecycleCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
lifecycle_callbacks_.push_back(std::move(callback));
|
||||
spdlog::debug("Registered lifecycle callback, total callbacks: {}", lifecycle_callbacks_.size());
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
auto it = providers_.find(request.method);
|
||||
if (it != providers_.end())
|
||||
{
|
||||
RequestProvider provider = it->second;
|
||||
auto provider = it->second;
|
||||
lock.unlock();
|
||||
try
|
||||
{
|
||||
return provider(request);
|
||||
return provider->ProvideResponse(request);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Provider error for method {}: {}", request.method, e.what());
|
||||
return HandleException(request, e.what());
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
|
||||
}
|
||||
}
|
||||
return HandleUnknownMethod(request);
|
||||
@@ -51,36 +73,52 @@ namespace lsp
|
||||
return methods;
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::HandleUnknownMethod(const protocol::RequestMessage& request)
|
||||
void RequestDispatcher::NotifyAllLifecycleListeners(ServerLifecycleEvent event)
|
||||
{
|
||||
return BuildErrorResponse(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
|
||||
std::string RequestDispatcher::HandleException(const protocol::RequestMessage& request, const std::string& error_message)
|
||||
{
|
||||
return BuildErrorResponse(request, protocol::ErrorCode::kInternalError, "Internal error: " + error_message);
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::BuildErrorResponse(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
||||
{
|
||||
protocol::ResponseMessage response;
|
||||
response.jsonrpc = "2.0";
|
||||
response.id = request.id;
|
||||
|
||||
protocol::ResponseError error;
|
||||
error.code = code;
|
||||
error.message = message;
|
||||
response.error = error;
|
||||
|
||||
std::string json;
|
||||
auto ec = glz::write_json(response, json);
|
||||
if (ec)
|
||||
std::string event_name;
|
||||
switch (event)
|
||||
{
|
||||
spdlog::error("Failed to serialize error response: {}", glz::format_error(ec, json));
|
||||
// 返回一个硬编码的错误响应作为后备
|
||||
return R"({"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to serialize error response"}})";
|
||||
case ServerLifecycleEvent::kInitializing:
|
||||
event_name = "Initializing";
|
||||
break;
|
||||
case ServerLifecycleEvent::kInitialized:
|
||||
event_name = "Initialized";
|
||||
break;
|
||||
case ServerLifecycleEvent::kInitializeFailed:
|
||||
event_name = "InitializeFailed";
|
||||
break;
|
||||
case ServerLifecycleEvent::kShuttingDown:
|
||||
event_name = "ShuttingDown";
|
||||
break;
|
||||
case ServerLifecycleEvent::kShutdown:
|
||||
event_name = "Shutdown";
|
||||
break;
|
||||
}
|
||||
|
||||
return json;
|
||||
spdlog::info("Lifecycle event: {}", event_name);
|
||||
|
||||
for (const auto& callback : lifecycle_callbacks_)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(event);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Lifecycle callback error: {}", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::HandleUnknownMethod(const protocol::RequestMessage& request)
|
||||
{
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
||||
{
|
||||
return providers::ILspProvider::BuildErrorResponseMessage(request, code, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <shared_mutex>
|
||||
#include "../protocol/protocol.hpp"
|
||||
#include "../provider/base/provider_interface.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
// 请求处理函数类型 - 返回序列化后的 JSON 字符串
|
||||
using RequestProvider = std::function<std::string(const protocol::RequestMessage&)>;
|
||||
|
||||
using ServerLifecycleEvent = providers::ServerLifecycleEvent;
|
||||
using LifecycleCallback = providers::LifecycleCallback;
|
||||
|
||||
class RequestDispatcher
|
||||
{
|
||||
public:
|
||||
RequestDispatcher() = default;
|
||||
|
||||
void RegisterProvider(const std::string& method, RequestProvider provider);
|
||||
void RegisterProvider(std::shared_ptr<providers::ILspProvider> provider);
|
||||
void RegisterLifecycleCallback(LifecycleCallback callback);
|
||||
std::string Dispatch(const protocol::RequestMessage& request);
|
||||
bool SupportsMethod(const std::string& method) const;
|
||||
std::vector<std::string> GetSupportedMethods() const;
|
||||
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
||||
|
||||
private:
|
||||
void NotifyAllLifecycleListeners(ServerLifecycleEvent event);
|
||||
std::string HandleUnknownMethod(const protocol::RequestMessage& request);
|
||||
std::string HandleException(const protocol::RequestMessage& request, const std::string& error_message);
|
||||
std::string BuildErrorResponse(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex providers_mutex_;
|
||||
std::unordered_map<std::string, RequestProvider> providers_;
|
||||
std::unordered_map<std::string, std::shared_ptr<providers::ILspProvider>> providers_;
|
||||
|
||||
std::mutex callbacks_mutex_;
|
||||
std::vector<LifecycleCallback> lifecycle_callbacks_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,56 +1,101 @@
|
||||
#include <mutex>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "./request_scheduler.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
|
||||
RequestScheduler::RequestScheduler(size_t concurrency) :
|
||||
executor_(concurrency)
|
||||
{
|
||||
spdlog::info("RequestScheduler initialized with {} threads", concurrency);
|
||||
}
|
||||
RequestScheduler::~RequestScheduler() = default;
|
||||
|
||||
void RequestScheduler::Sumbit(const std::string& request_id, TaskFunc task)
|
||||
RequestScheduler::~RequestScheduler()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(task_mutex_);
|
||||
auto future = executor_.silent_async([this, request_id, task = std::move(task)] {
|
||||
WaitAll();
|
||||
}
|
||||
|
||||
void RequestScheduler::Submit(const std::string& request_id, TaskFunc task)
|
||||
{
|
||||
auto context = std::make_shared<TaskContext>();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
// 取消旧任务
|
||||
auto it = running_tasks_.find(request_id);
|
||||
if (it != running_tasks_.end())
|
||||
{
|
||||
it->second->cancelled.store(true);
|
||||
}
|
||||
|
||||
running_tasks_[request_id] = context;
|
||||
}
|
||||
|
||||
executor_.async([this, request_id, task = std::move(task), context]() {
|
||||
try
|
||||
{
|
||||
if (context->cancelled.load())
|
||||
{
|
||||
spdlog::debug("Task {} was cancelled", request_id);
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = task();
|
||||
if (result)
|
||||
|
||||
if (!context->cancelled.load() && result)
|
||||
{
|
||||
SendResponse(*result);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Task {} failed: {}", request_id, e.what());
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(cancel_mutex_);
|
||||
running_tasks_.erase(request_id);
|
||||
|
||||
// 清理
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
running_tasks_.erase(request_id);
|
||||
}
|
||||
});
|
||||
running_tasks_[request_id] = std::move(future);
|
||||
}
|
||||
|
||||
void RequestScheduler::Cancel(const std::string& request_id)
|
||||
bool RequestScheduler::Cancel(const std::string& request_id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cancel_mutex_);
|
||||
// Taskflow doesn't support preemptive cancel yet; you can set a flag here for cooperative cancel
|
||||
spdlog::warn("Cancel not implemented for request_id = {} (requires cooperative cancel)", request_id);
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
auto it = running_tasks_.find(request_id);
|
||||
if (it != running_tasks_.end())
|
||||
{
|
||||
it->second->cancelled.store(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RequestScheduler::SetOutputFallback(std::function<void(const std::string&)> callback)
|
||||
void RequestScheduler::SetResponseCallback(ResponseCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(output_mutex_);
|
||||
send_response_ = std::move(callback);
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
response_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void RequestScheduler::WaitAll()
|
||||
{
|
||||
executor_.wait_for_all();
|
||||
}
|
||||
|
||||
void RequestScheduler::SendResponse(const std::string& response)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(output_mutex_);
|
||||
if (send_response_)
|
||||
send_response_(response);
|
||||
ResponseCallback callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callback = response_callback_;
|
||||
}
|
||||
|
||||
if (callback)
|
||||
callback(response);
|
||||
else
|
||||
spdlog::error("No response callback set! Unable to send: {}", response);
|
||||
spdlog::error("No response callback set!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// request_scheduler.hpp
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <taskflow/taskflow.hpp>
|
||||
|
||||
@@ -12,23 +14,28 @@ namespace lsp
|
||||
{
|
||||
public:
|
||||
using TaskFunc = std::function<std::optional<std::string>()>;
|
||||
explicit RequestScheduler(size_t concurrency);
|
||||
using ResponseCallback = std::function<void(const std::string&)>;
|
||||
|
||||
explicit RequestScheduler(size_t concurrency = std::thread::hardware_concurrency());
|
||||
~RequestScheduler();
|
||||
|
||||
void Sumbit(const std::string& request_id, TaskFunc task);
|
||||
void Cancel(const std::string& request_id);
|
||||
void SetOutputFallback(std::function<void(const std::string&)> callback);
|
||||
void Submit(const std::string& request_id, TaskFunc task);
|
||||
bool Cancel(const std::string& request_id);
|
||||
void SetResponseCallback(ResponseCallback callback);
|
||||
void WaitAll();
|
||||
|
||||
private:
|
||||
struct TaskContext
|
||||
{
|
||||
std::atomic<bool> cancelled{false};
|
||||
};
|
||||
|
||||
void SendResponse(const std::string& response);
|
||||
|
||||
private:
|
||||
tf::Executor executor_;
|
||||
std::mutex task_mutex_;
|
||||
std::mutex cancel_mutex_;
|
||||
std::mutex output_mutex_;
|
||||
|
||||
std::unordered_map<std::string, tf::Future<void>> running_tasks_;
|
||||
std::function<void(const std::string&)> send_response_;
|
||||
mutable std::mutex mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<TaskContext>> running_tasks_;
|
||||
ResponseCallback response_callback_;
|
||||
};
|
||||
}
|
||||
|
||||
+193
-62
@@ -1,3 +1,4 @@
|
||||
#include "request_scheduler.hpp"
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <spdlog/spdlog.h>
|
||||
@@ -11,13 +12,29 @@
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
LspServer::LspServer()
|
||||
LspServer::LspServer(size_t concurrency) :
|
||||
scheduler_(4)
|
||||
{
|
||||
spdlog::info("Initializing LSP server with {} worker threads", concurrency);
|
||||
|
||||
dispatcher_.RegisterLifecycleCallback(
|
||||
[this](providers::ServerLifecycleEvent event) {
|
||||
OnLifecycleEvent(event);
|
||||
});
|
||||
providers::RegisterAllProviders(dispatcher_);
|
||||
|
||||
scheduler_.SetResponseCallback([this](const std::string& response) {
|
||||
SendResponse(response);
|
||||
});
|
||||
|
||||
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetSupportedMethods().size());
|
||||
}
|
||||
|
||||
LspServer::~LspServer() = default;
|
||||
LspServer::~LspServer()
|
||||
{
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("LSP server shutting down...");
|
||||
}
|
||||
|
||||
void LspServer::Run()
|
||||
{
|
||||
@@ -29,7 +46,7 @@ namespace lsp
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
#endif
|
||||
|
||||
while (true)
|
||||
while (!is_shutting_down_)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -40,11 +57,7 @@ namespace lsp
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string response = HandleMessage(*message);
|
||||
if (!response.empty())
|
||||
{
|
||||
SendResponse(response);
|
||||
}
|
||||
HandleMessage(*message);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -106,9 +119,7 @@ namespace lsp
|
||||
|
||||
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
|
||||
{
|
||||
spdlog::error("Read incomplete message body, expected: {}, got: {}",
|
||||
content_length,
|
||||
std::cin.gcount());
|
||||
spdlog::error("Read incomplete message body, expected: {}, got: {}", content_length, std::cin.gcount());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -116,122 +127,242 @@ namespace lsp
|
||||
return body;
|
||||
}
|
||||
|
||||
std::string LspServer::HandleMessage(const std::string& raw_message)
|
||||
void LspServer::HandleMessage(const std::string& raw_message)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 首先尝试解析为通用的 JSON 来判断消息类型
|
||||
// 解析 JSON 判断消息类型
|
||||
glz::json_t doc;
|
||||
auto error = glz::read_json(doc, raw_message);
|
||||
if (error)
|
||||
{
|
||||
spdlog::error("Failed to parse message as JSON: {}",
|
||||
glz::format_error(error, raw_message));
|
||||
return "";
|
||||
spdlog::error("Failed to parse message as JSON: {}", glz::format_error(error, raw_message));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& obj = doc.get<glz::json_t::object_t>();
|
||||
|
||||
// 判断消息类型
|
||||
bool has_id = obj.contains("id");
|
||||
bool has_method = obj.contains("method");
|
||||
bool has_result = obj.contains("result");
|
||||
bool has_error = obj.contains("error");
|
||||
|
||||
if (has_method && has_id)
|
||||
if (has_method)
|
||||
{
|
||||
// Request
|
||||
protocol::RequestMessage request;
|
||||
error = glz::read_json(request, raw_message);
|
||||
if (error)
|
||||
bool has_id = obj.contains("id");
|
||||
|
||||
if (has_id)
|
||||
{
|
||||
spdlog::error("Failed to parse request: {}",
|
||||
glz::format_error(error, raw_message));
|
||||
return "";
|
||||
// RequestMessage
|
||||
protocol::RequestMessage request;
|
||||
error = glz::read_json(request, raw_message);
|
||||
if (error)
|
||||
{
|
||||
spdlog::error("Failed to parse request: {}", glz::format_error(error, raw_message));
|
||||
return;
|
||||
}
|
||||
HandleRequest(request);
|
||||
}
|
||||
return HandleRequest(request);
|
||||
}
|
||||
else if (has_method && !has_id)
|
||||
{
|
||||
// Notification
|
||||
protocol::NotificationMessage notification;
|
||||
error = glz::read_json(notification, raw_message);
|
||||
if (error)
|
||||
else
|
||||
{
|
||||
spdlog::error("Failed to parse notification: {}",
|
||||
glz::format_error(error, raw_message));
|
||||
return "";
|
||||
// NotificationMessage
|
||||
protocol::NotificationMessage notification;
|
||||
error = glz::read_json(notification, raw_message);
|
||||
if (error)
|
||||
{
|
||||
spdlog::error("Failed to parse notification: {}", glz::format_error(error, raw_message));
|
||||
return;
|
||||
}
|
||||
HandleNotification(notification);
|
||||
}
|
||||
return HandleNotification(notification);
|
||||
}
|
||||
else if (has_id && (has_result || has_error))
|
||||
else if (obj.contains("id") && (obj.contains("result") || obj.contains("error")))
|
||||
{
|
||||
// Response
|
||||
// ResponseMessage
|
||||
protocol::ResponseMessage response;
|
||||
error = glz::read_json(response, raw_message);
|
||||
if (error)
|
||||
{
|
||||
spdlog::error("Failed to parse response: {}",
|
||||
glz::format_error(error, raw_message));
|
||||
return "";
|
||||
glz::format_error(error, raw_message));
|
||||
return;
|
||||
}
|
||||
HandleResponse(response);
|
||||
return ""; // 响应不需要回复
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::error("Unknown message type");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Failed to handle message: {}", e.what());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string LspServer::HandleRequest(const protocol::RequestMessage& request)
|
||||
void LspServer::HandleRequest(const protocol::RequestMessage& request)
|
||||
{
|
||||
spdlog::debug("Processing request method: {}", request.method);
|
||||
std::string request_id = transform::debug::GetIdString(request.id);
|
||||
spdlog::debug("Processing request - id: {}, method: {}", request_id, request.method);
|
||||
|
||||
// 特殊处理 initialize 请求
|
||||
if (request.method == "initialize")
|
||||
// 检查是否可以处理请求
|
||||
if (!CanProcessRequest(request.method))
|
||||
{
|
||||
is_initialized_ = true;
|
||||
protocol::ErrorCode error_code;
|
||||
std::string message;
|
||||
|
||||
if (!is_initialized_)
|
||||
{
|
||||
error_code = protocol::ErrorCode::kServerNotInitialized;
|
||||
message = "Server not initialized";
|
||||
}
|
||||
else if (is_shutting_down_)
|
||||
{
|
||||
error_code = protocol::ErrorCode::kInvalidRequest;
|
||||
message = "Server is shutting down, only 'exit' is allowed";
|
||||
}
|
||||
else
|
||||
{
|
||||
error_code = protocol::ErrorCode::kInternalError;
|
||||
message = "Request not allowed in current state";
|
||||
}
|
||||
|
||||
SendResponse(dispatcher_.BuildErrorResponseMessage(request, error_code, message));
|
||||
return;
|
||||
}
|
||||
|
||||
return dispatcher_.Dispatch(request);
|
||||
// 决定同步还是异步处理
|
||||
if (RequiresSyncProcessing(request.method))
|
||||
{
|
||||
SendResponse(dispatcher_.Dispatch(request));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 异步处理
|
||||
scheduler_.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 dispatcher_.BuildErrorResponseMessage( request, protocol::ErrorCode::kInternalError, e.what());
|
||||
}
|
||||
});
|
||||
}
|
||||
spdlog::debug("Processing request method: {}", request.method);
|
||||
}
|
||||
|
||||
std::string LspServer::HandleNotification(const protocol::NotificationMessage& notification)
|
||||
void LspServer::HandleNotification(const protocol::NotificationMessage& notification)
|
||||
{
|
||||
spdlog::debug("Processing notification - method: {}", notification.method);
|
||||
|
||||
// 特殊处理某些通知
|
||||
// 处理 $/ 开头的通知
|
||||
if (notification.method.starts_with("$/"))
|
||||
{
|
||||
if (notification.method == "$/cancelRequest")
|
||||
{
|
||||
HandleCancelRequest(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::debug("Ignoring protocol-specific notification: {}", notification.method);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理标准通知
|
||||
if (notification.method == "initialized")
|
||||
{
|
||||
spdlog::info("Client initialized");
|
||||
spdlog::info("Client acknowledged initialization");
|
||||
}
|
||||
else if (notification.method == "exit")
|
||||
{
|
||||
spdlog::info("Exit notification received");
|
||||
is_shutting_down_ = true;
|
||||
// 给一点时间让任务完成
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::exit(0);
|
||||
}
|
||||
|
||||
// 通知不需要响应
|
||||
return "";
|
||||
}
|
||||
|
||||
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(ServerLifecycleEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ServerLifecycleEvent::kInitializing:
|
||||
spdlog::info("Server initializing...");
|
||||
break;
|
||||
|
||||
case ServerLifecycleEvent::kInitialized:
|
||||
is_initialized_ = true;
|
||||
spdlog::info("Server initialized successfully");
|
||||
break;
|
||||
|
||||
case ServerLifecycleEvent::kInitializeFailed:
|
||||
is_initialized_ = false;
|
||||
spdlog::error("Server initialization failed");
|
||||
break;
|
||||
|
||||
case ServerLifecycleEvent::kShuttingDown:
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("Server entering shutdown state");
|
||||
break;
|
||||
|
||||
case 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)
|
||||
{
|
||||
size_t byte_length = response.length();
|
||||
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
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "./dispacther.hpp"
|
||||
#include "./request_scheduler.hpp"
|
||||
#include "../provider/base/provider_registry.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
class LspServer
|
||||
{
|
||||
public:
|
||||
LspServer();
|
||||
LspServer(size_t concurrency = std::thread::hardware_concurrency());
|
||||
~LspServer();
|
||||
void Run();
|
||||
|
||||
@@ -17,18 +20,34 @@ namespace lsp
|
||||
std::optional<std::string> ReadMessage();
|
||||
|
||||
// 处理LSP请求 - 返回序列化的响应或空字符串(对于通知)
|
||||
std::string HandleMessage(const std::string& raw_message);
|
||||
void HandleMessage(const std::string& raw_message);
|
||||
|
||||
// 发送LSP响应
|
||||
void SendResponse(const std::string& response);
|
||||
|
||||
// 处理不同类型的消息
|
||||
std::string HandleRequest(const protocol::RequestMessage& request);
|
||||
std::string HandleNotification(const protocol::NotificationMessage& notification);
|
||||
void HandleRequest(const protocol::RequestMessage& request);
|
||||
void HandleNotification(const protocol::NotificationMessage& notification);
|
||||
void HandleResponse(const protocol::ResponseMessage& response);
|
||||
|
||||
// 生命周期事件处理
|
||||
void OnLifecycleEvent(providers::ServerLifecycleEvent event);
|
||||
|
||||
// 判断是否需要同步处理
|
||||
bool RequiresSyncProcessing(const std::string& method) const;
|
||||
|
||||
// 检查是否可以处理请求
|
||||
bool CanProcessRequest(const std::string& method) const;
|
||||
|
||||
// 处理取消请求
|
||||
void HandleCancelRequest(const protocol::NotificationMessage& notification);
|
||||
|
||||
private:
|
||||
RequestDispatcher dispatcher_;
|
||||
bool is_initialized_ = false;
|
||||
RequestScheduler scheduler_;
|
||||
|
||||
std::atomic<bool> is_initialized_ = false;
|
||||
std::atomic<bool> is_shutting_down_ = false;
|
||||
std::mutex output_mutex_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace lsp::protocol
|
||||
|
||||
struct WorkDoneProgressOptions
|
||||
{
|
||||
boolean workDoneProgress;
|
||||
std::optional<boolean> workDoneProgress;
|
||||
};
|
||||
|
||||
struct PartialResultParams
|
||||
|
||||
@@ -87,6 +87,16 @@ namespace lsp::transform
|
||||
return "null";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
inline std::string GetIdString(const std::variant<int, std::string>& id)
|
||||
{
|
||||
return std::visit([](const auto& value) -> std::string {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, int>)
|
||||
return std::to_string(value);
|
||||
else
|
||||
return value;
|
||||
}, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,37 @@
|
||||
namespace lsp::providers
|
||||
{
|
||||
|
||||
std::string ILspProvider::BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message)
|
||||
std::string ILspProvider::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
||||
{
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
|
||||
protocol::ResponseError error;
|
||||
error.code = code;
|
||||
error.message = message;
|
||||
response.error = error;
|
||||
std::string json;
|
||||
auto ec = glz::write_json(error, json);
|
||||
if (ec)
|
||||
{
|
||||
spdlog::error("{}: Error", GetProviderName());
|
||||
std::string errmsg = "Failed to serialize [" + GetProviderName() + "] error response: " + glz::format_error(ec);
|
||||
throw std::runtime_error(errmsg);
|
||||
spdlog::error("Failed to serialize error response: {}", glz::format_error(ec, json));
|
||||
return R"({"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to serialize error response"}})";
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
void ILifecycleAwareProvider::SetLifecycleCallback(LifecycleCallback callback)
|
||||
{
|
||||
lifecycle_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void ILifecycleAwareProvider::NotifyLifecycleEvent(ServerLifecycleEvent event)
|
||||
{
|
||||
if (lifecycle_callback_)
|
||||
{
|
||||
lifecycle_callback_(event);
|
||||
spdlog::debug("Provider {} triggered event: {}", GetProviderName(), static_cast<int>(event));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
|
||||
namespace lsp::providers
|
||||
{
|
||||
enum class ServerLifecycleEvent
|
||||
{
|
||||
kInitializing,
|
||||
kInitialized,
|
||||
kInitializeFailed,
|
||||
kShuttingDown,
|
||||
kShutdown
|
||||
};
|
||||
|
||||
using LifecycleCallback = std::function<void(ServerLifecycleEvent)>;
|
||||
|
||||
// LSP请求提供者接口基类
|
||||
class ILspProvider
|
||||
@@ -18,8 +28,24 @@ namespace lsp::providers
|
||||
// 获取提供者名称(用于日志和调试)
|
||||
virtual std::string GetProviderName() const = 0;
|
||||
|
||||
static std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
||||
};
|
||||
|
||||
// 生命周期感知的 Provider 接口
|
||||
class ILifecycleAwareProvider : public ILspProvider
|
||||
{
|
||||
public:
|
||||
virtual ~ILifecycleAwareProvider() = default;
|
||||
|
||||
// 设置生命周期回调
|
||||
void SetLifecycleCallback(LifecycleCallback callback);
|
||||
|
||||
protected:
|
||||
std::string BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message);
|
||||
// 触发生命周期事件
|
||||
void NotifyLifecycleEvent(ServerLifecycleEvent event);
|
||||
|
||||
private:
|
||||
LifecycleCallback lifecycle_callback_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../text_document/did_change_provider.hpp"
|
||||
#include "../text_document/completion_provider.hpp"
|
||||
#include "../trace/set_trace_provider.hpp"
|
||||
#include "../shutdown/shutdown_provider.hpp"
|
||||
|
||||
namespace lsp::providers
|
||||
{
|
||||
@@ -20,6 +21,7 @@ namespace lsp::providers
|
||||
RegisterProvider<text_document::DidChangeProvider>(dispatcher);
|
||||
RegisterProvider<text_document::CompletionProvider>(dispatcher);
|
||||
RegisterProvider<trace::SetTraceProvider>(dispatcher);
|
||||
RegisterProvider<shutdown::ShutdownProvider>(dispatcher);
|
||||
|
||||
spdlog::info("Successfully registered {} LSP providers", dispatcher.GetSupportedMethods().size());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
namespace lsp::providers
|
||||
{
|
||||
|
||||
// 模板函数:注册provider
|
||||
template<typename ProviderClass>
|
||||
void RegisterProvider(RequestDispatcher& dispatcher)
|
||||
@@ -14,14 +13,9 @@ namespace lsp::providers
|
||||
"Provider must inherit from ILspProvider");
|
||||
|
||||
auto provider = std::make_shared<ProviderClass>();
|
||||
dispatcher.RegisterProvider(provider);
|
||||
|
||||
spdlog::info("Registering {} for method: {}", provider->GetProviderName(), provider->GetMethod());
|
||||
|
||||
dispatcher.RegisterProvider(
|
||||
provider->GetMethod(),
|
||||
[provider](const protocol::RequestMessage& request) -> std::string {
|
||||
return provider->ProvideResponse(request);
|
||||
});
|
||||
}
|
||||
|
||||
// 批量注册provider
|
||||
|
||||
@@ -12,7 +12,13 @@ namespace lsp::providers::initialize
|
||||
response.result = transform::LSPAny(BuildInitializeResult());
|
||||
std::string json;
|
||||
auto ec = glz::write_json(response, json);
|
||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
if (ec)
|
||||
{
|
||||
NotifyLifecycleEvent(ServerLifecycleEvent::kInitializeFailed);
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error");
|
||||
}
|
||||
NotifyLifecycleEvent(ServerLifecycleEvent::kInitialized);
|
||||
return json;
|
||||
}
|
||||
|
||||
std::string InitializeProvider::GetMethod() const
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
namespace lsp::providers::initialize
|
||||
{
|
||||
using namespace lsp;
|
||||
class InitializeProvider : public ILspProvider
|
||||
class InitializeProvider : public ILifecycleAwareProvider
|
||||
{
|
||||
public:
|
||||
InitializeProvider() = default;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace lsp::providers::initialized
|
||||
std::string json;
|
||||
glz::obj empty_obj{}; // glaze的对象类型
|
||||
auto ec = glz::write_json(empty_obj, json);
|
||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
}
|
||||
|
||||
std::string InitializedProvider::GetMethod() const
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace lsp::providers::initialized
|
||||
{
|
||||
class InitializedProvider : public ILspProvider
|
||||
class InitializedProvider : public ILifecycleAwareProvider
|
||||
{
|
||||
public:
|
||||
InitializedProvider() = default;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "./shutdown_provider.hpp"
|
||||
#include "../../protocol/transform/facade.hpp"
|
||||
|
||||
namespace lsp::providers::shutdown
|
||||
{
|
||||
std::string ShutdownProvider::ProvideResponse(const protocol::RequestMessage& request)
|
||||
{
|
||||
spdlog::debug("ShutdownProvider: Providing response for method {}", request.method);
|
||||
|
||||
try
|
||||
{
|
||||
// 触发关闭事件
|
||||
NotifyLifecycleEvent(ServerLifecycleEvent::kShuttingDown);
|
||||
|
||||
// 构建响应 - shutdown 返回 null
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
|
||||
std::string json;
|
||||
auto ec = glz::write_json(response, json);
|
||||
if (ec)
|
||||
{
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
||||
}
|
||||
|
||||
spdlog::info("Shutdown request processed successfully");
|
||||
return json;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Shutdown request failed: {}", e.what());
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::string ShutdownProvider::GetMethod() const
|
||||
{
|
||||
return "shutdown";
|
||||
}
|
||||
|
||||
std::string ShutdownProvider::GetProviderName() const
|
||||
{
|
||||
return "ShutdownProvider";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "../base/provider_interface.hpp"
|
||||
|
||||
namespace lsp::providers::shutdown
|
||||
{
|
||||
class ShutdownProvider : public ILifecycleAwareProvider
|
||||
{
|
||||
public:
|
||||
ShutdownProvider() = default;
|
||||
|
||||
std::string ProvideResponse(const protocol::RequestMessage& request) override;
|
||||
std::string GetMethod() const override;
|
||||
std::string GetProviderName() const override;
|
||||
};
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace lsp::providers::text_document
|
||||
// 验证请求是否包含参数
|
||||
if (!request.params.has_value()) {
|
||||
spdlog::warn("{}: Missing params in request", GetProviderName());
|
||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Missing params");
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Missing params");
|
||||
}
|
||||
|
||||
// 从 variant 中提取参数
|
||||
@@ -28,17 +28,17 @@ namespace lsp::providers::text_document
|
||||
auto ec = glz::write_json(response, json);
|
||||
if (ec) {
|
||||
spdlog::error("{}: Failed to serialize response: {}", GetProviderName(), glz::format_error(ec, json));
|
||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
||||
}
|
||||
|
||||
return json;
|
||||
|
||||
} catch (const transform::ConversionError& e) {
|
||||
spdlog::error("{}: Failed to convert params: {}", GetProviderName(), e.what());
|
||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Invalid completion params");
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Invalid completion params");
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("{}: Unexpected error: {}", GetProviderName(), e.what());
|
||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error");
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace lsp::providers::text_document
|
||||
std::string json;
|
||||
glz::obj empty_obj{}; // glaze的对象类型
|
||||
auto ec = glz::write_json(empty_obj, json);
|
||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
}
|
||||
|
||||
std::string DidChangeProvider::GetMethod() const
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace lsp::providers::text_document
|
||||
std::string json;
|
||||
glz::obj empty_obj{}; // glaze的对象类型
|
||||
auto ec = glz::write_json(empty_obj, json);
|
||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
}
|
||||
|
||||
std::string DidOpenProvider::GetMethod() const
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace lsp::providers::trace
|
||||
std::string json;
|
||||
glz::obj empty_obj{}; // glaze的对象类型
|
||||
auto ec = glz::write_json(empty_obj, json);
|
||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||
}
|
||||
|
||||
std::string SetTraceProvider::GetMethod() const
|
||||
|
||||
Reference in New Issue
Block a user