class Yoda::Server::RootHandler

Constants

NOT_INITIALIZED
NotImplementedMethod

Attributes

future_map[R]

@return [Concurrent::Map{ String => Future }]

thread_pool[R]

@return [Concurrent::ThreadPoolExecutor]

writer[R]

@return [ConcurrentWriter]

Public Class Methods

default_thread_pool() click to toggle source

@return [Concurrent::ThreadPoolExecutor]

# File lib/yoda/server/root_handler.rb, line 20
def self.default_thread_pool
  Concurrent.global_fast_executor
end
new(writer:, thread_pool: nil) click to toggle source

@param writer [ConcurrentWriter] @param thread_pool [Concurrent::ThreadPoolExecutor]

# File lib/yoda/server/root_handler.rb, line 26
def initialize(writer:, thread_pool: nil)
  @thread_pool = thread_pool || self.class.default_thread_pool
  @writer = writer
  @future_map = Concurrent::Map.new
end

Public Instance Methods

cancel_all_requests() click to toggle source
# File lib/yoda/server/root_handler.rb, line 60
def cancel_all_requests
  future_map.each_value { |future| future&.cancel }
end
cancel_request(id) click to toggle source

@param id [String]

# File lib/yoda/server/root_handler.rb, line 56
def cancel_request(id)
  future_map[id]&.cancel
end
handle(id:, method:, params:) click to toggle source

@param id [String] @param method [Symbol] @param params [Hash] @return [Concurrent::Future, nil]

# File lib/yoda/server/root_handler.rb, line 36
def handle(id:, method:, params:)
  if lifecycle_handler.handle?(method)
    return write_response(id, lifecycle_handler.handle(method: method, params: params))
  end

  return write_response(id, build_error_response(NOT_INITIALIZED)) unless session

  if provider = Providers.build_provider(notifier: notifier, session: session, method: method)
    provide_async(provider: provider, id: id, method: method, params: params)
  else
    write_response(id, build_error_response(NotImplementedMethod.new(method)))
  end
end
notifier() click to toggle source

@return [Notifier]

# File lib/yoda/server/root_handler.rb, line 51
def notifier
  @notifier ||= Notifier.new(writer)
end

Private Instance Methods

build_error_response(reason) click to toggle source

@param reason [Exception, Symbol, Struct]

# File lib/yoda/server/root_handler.rb, line 108
def build_error_response(reason)
  case reason
  when Concurrent::CancelledOperationError
    LanguageServer::Protocol::Interface::ResponseError.new(
      code: LanguageServer::Protocol::Constant::ErrorCodes::REQUEST_CANCELLED,
      message: 'Request is canceled',
    )
  when NOT_INITIALIZED
    LanguageServer::Protocol::Interface::ResponseError.new(
      code: LanguageServer::Protocol::Constant::ErrorCodes::SERVER_NOT_INITIALIZED,
      message: "Server is not initialized",
    )
  when NotImplementedMethod
    LanguageServer::Protocol::Interface::ResponseError.new(
      code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
      message: "Method (#{reason.method_name}) is not implemented",
    )
  else
    LanguageServer::Protocol::Interface::ResponseError.new(
      code: LanguageServer::Protocol::Constant::ErrorCodes::INTERNAL_ERROR,
      message: reason.respond_to?(:message) ? message : 'Internal error',
    )
  end
end
lifecycle_handler() click to toggle source

@return [LifecycleHandler]

# File lib/yoda/server/root_handler.rb, line 70
def lifecycle_handler
  @lifecycle_handler ||= LifecycleHandler.new(self)
end
provide_async(provider:, id:, method:, params:) click to toggle source

@return [Concurrent::Future]

# File lib/yoda/server/root_handler.rb, line 75
def provide_async(provider:, id:, method:, params:)
  future = Concurrent::Future.new(executor: thread_pool) do
    notifier.busy(type: method, id: id) { provider.provide(params) }
  end
  future.add_observer do |_time, value, reason|
    begin
      reason ? write_response(id, build_error_response(reason)) : write_response(id, value)
    ensure
      future_map.delete(id)
    end
  end
  future_map.put_if_absent(id, future)
  Concurrent::ScheduledTask.execute(provider.timeout, executor: thread_pool) { future.cancel } if provider.timeout
  
  future.execute
  future
end
write_response(id, result) click to toggle source

@param id [Object] @param result [Object] @return [nil]

# File lib/yoda/server/root_handler.rb, line 96
def write_response(id, result)
  return if result == NO_RESPONSE
  if result.is_a?(LanguageServer::Protocol::Interface::ResponseError)
    writer.write(id: id, error: result)
  else
    writer.write(id: id, result: result)
  end

  nil
end