Class: PlatformosCheck::LanguageServer::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/platformos_check/language_server/server.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(messenger:, should_raise_errors: false, number_of_threads: 2) ⇒ Server



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/platformos_check/language_server/server.rb', line 16

def initialize(
  messenger:,
  should_raise_errors: false,
  number_of_threads: 2
)
  # This is what does the IO
  @messenger = messenger

  # This is what you use to communicate with the language client
  @bridge = Bridge.new(@messenger)

  # The handler handles messages from the language client
  @handler = Handler.new(@bridge)

  # The queue holds the JSON RPC messages
  @queue = Queue.new

  # The JSON RPC thread pushes messages onto the queue
  @json_rpc_thread = nil

  # The handler threads read messages from the queue
  @number_of_threads = number_of_threads
  @handlers = []

  # The error queue holds blocks the main thread. When filled, we exit the program.
  @error = SizedQueue.new(number_of_threads)

  @should_raise_errors = should_raise_errors
end

Instance Attribute Details

#handlerObject (readonly)

Returns the value of attribute handler.



14
15
16
# File 'lib/platformos_check/language_server/server.rb', line 14

def handler
  @handler
end

#should_raise_errorsObject (readonly)

Returns the value of attribute should_raise_errors.



14
15
16
# File 'lib/platformos_check/language_server/server.rb', line 14

def should_raise_errors
  @should_raise_errors
end

Instance Method Details

#handle_messagesObject



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/platformos_check/language_server/server.rb', line 103

def handle_messages
  loop do
    message = @queue.pop
    return if @queue.closed? && @queue.empty?

    handle_message(message)
  end
rescue Exception => e # rubocop:disable Lint/RescueException
  @bridge.log("rescuing #{e} in handler thread")
  @error << e
end

#listenObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/platformos_check/language_server/server.rb', line 46

def listen
  start_handler_threads
  start_json_rpc_thread
  err = @error.pop
  status_code = status_code_from_error(err)

  if status_code > 0
    # For a reason I can't comprehend, this hangs but prints
    # anyway. So it's wrapped in this ugly timeout...
    Timeout.timeout(1) do
      warn err.full_message
    end

    # Warn user of error, otherwise server might restart
    # without telling you.
    @bridge.send_notification("window/showMessage", {
                                type: 1,
                                message: "A platformos-check-language-server error has occurred, search OUTPUT logs for details."
                              })
  end

  cleanup(status_code)
rescue SignalException
  0
rescue StandardError
  2
end

#start_handler_threadsObject



95
96
97
98
99
100
101
# File 'lib/platformos_check/language_server/server.rb', line 95

def start_handler_threads
  @number_of_threads.times do
    @handlers << Thread.new do
      handle_messages
    end
  end
end

#start_json_rpc_threadObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/platformos_check/language_server/server.rb', line 74

def start_json_rpc_thread
  @json_rpc_thread = Thread.new do
    loop do
      message = @bridge.read_message
      if message[:method] == 'initialize'
        handle_message(message)
      elsif message.key?(:result)
        # Responses are handled on the main thread to prevent
        # a potential deadlock caused by all handlers waiting
        # for a responses.
        handle_response(message)
      else
        @queue << message
      end
    end
  rescue Exception => e # rubocop:disable Lint/RescueException
    @bridge.log("rescuing #{e.class} in jsonrpc thread")
    @error << e
  end
end

#status_code_from_error(e) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/platformos_check/language_server/server.rb', line 115

def status_code_from_error(e)
  raise e

# support ctrl+c and stuff
rescue SignalException, DoneStreaming
  0
rescue Exception => e # rubocop:disable Lint/RescueException
  raise e if should_raise_errors

  @bridge.log("Fatal #{e.class}")
  2
end