racer-rb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,250 @@
1
+ require "json"
2
+
3
+ class Racer::Agent
4
+ def initialize(server_path, collectors)
5
+ @queue = Queue.new
6
+ @server_path = server_path
7
+ @server = nil
8
+ @collectors = collectors
9
+ @should_stop = false
10
+ @agent_threads = []
11
+ end
12
+
13
+ def start
14
+ unless @server.nil?
15
+ raise "tried to start server again"
16
+ end
17
+ Process.setproctitle("Racer: Agent")
18
+
19
+ @server = UNIXServer.new(@server_path)
20
+
21
+ worker_thread =
22
+ Thread.new do
23
+ while (trace = @queue.pop) do
24
+ @collectors.each do |collector|
25
+ collector.collect(trace)
26
+ end
27
+ end
28
+
29
+ @collectors.each do |collector|
30
+ collector.stop
31
+ end
32
+ end
33
+
34
+ trap "HUP" do
35
+ exit
36
+ end
37
+
38
+ at_exit do
39
+ # puts "Shutting down agent. Waiting for all clients to finish sending messages..."
40
+ @agent_threads.each(&:join)
41
+ # puts "Closed server. Waiting for collectors to process messages..."
42
+ @server.close
43
+ @queue.close if @queue.empty?
44
+ File.unlink(@server_path)
45
+ worker_thread.join
46
+ # puts "Done"
47
+ end
48
+
49
+ main_loop
50
+ end
51
+
52
+ private
53
+
54
+ def main_loop
55
+ loop do
56
+ connection = @server.accept
57
+ # this is not really good because new clients need to wait until first client finished but for now its okay
58
+ @agent_threads <<
59
+ Thread.new do
60
+ worker_loop(connection)
61
+ end
62
+ end
63
+ end
64
+
65
+ def worker_loop(connection)
66
+ pending_message = nil
67
+ loop do
68
+ # TODO: Difference between connection.read connection.recv and connection.recvmsg
69
+ received_message = connection.read(1024)
70
+ # TODO: Is this an error? I would expect it waits until there is something to read?
71
+ if received_message.nil?
72
+ # warn "received nil as message"
73
+ next
74
+ end
75
+
76
+ # File.write("messages", "#{received_message}\n\n", mode: "a+")
77
+
78
+ *messages, last_message = received_message.split("\0")
79
+
80
+ if pending_message
81
+ if messages.empty?
82
+ last_message = "#{pending_message}#{last_message}"
83
+ else
84
+ first_message = messages.shift
85
+ messages.prepend(*("#{pending_message}#{first_message}".split("\0")))
86
+ end
87
+
88
+ pending_message = nil
89
+ end
90
+
91
+ if received_message.end_with?("\0")
92
+ messages << last_message
93
+ else
94
+ pending_message = last_message
95
+ end
96
+
97
+ messages.each do |data|
98
+ if data == "stop"
99
+ # puts "Received last message from one worker"
100
+ # Exits the thread
101
+ return
102
+ end
103
+
104
+ data = JSON.parse(data)
105
+ # File.write("parsed_messages", "#{data}\n\n", mode: "a+")
106
+
107
+ method_name = data.shift
108
+ method_kind =
109
+ Racer::Trace::KINDS.fetch(data.shift) do |index|
110
+ warn "Unexpected method kind received #{index}"
111
+ Racer::Trace::KINDS.first
112
+ end
113
+
114
+ method_visibility =
115
+ Racer::Trace::VISIBILITIES.fetch(data.shift) do |index|
116
+ warn "Unexpected method visibility received #{index}"
117
+ Racer::Trace::VISIBILITIES.first
118
+ end
119
+
120
+ return_type = shift_constant_instance(data)
121
+ method_owner = shift_constant_instance(data)
122
+ method_callee =
123
+ if data.first
124
+ shift_constant_instance(data)
125
+ else
126
+ # pop nil from data
127
+ data.shift
128
+ end
129
+
130
+ constant_updates = shift_constant_updates(data)
131
+
132
+ params, block_param = shift_params(data)
133
+
134
+
135
+ unless data.empty?
136
+ warn "Received more data then expected: #{data}"
137
+ end
138
+
139
+ @queue.push(
140
+ Racer::Trace.new(
141
+ method_owner:,
142
+ method_callee:,
143
+ method_name:,
144
+ method_kind:,
145
+ method_visibility:,
146
+ return_type:,
147
+ params:,
148
+ block_param:,
149
+ constant_updates:
150
+ )
151
+ )
152
+ end
153
+ end
154
+ end
155
+
156
+ def shift_block_trace(data)
157
+ self_type = shift_constant_instance(data)
158
+ return_type = shift_constant_instance(data)
159
+ params, block_param = shift_params(data)
160
+
161
+ Racer::Trace::BlockTrace.new(self_type:, return_type:, params:, block_param:)
162
+ end
163
+
164
+ def shift_params(data)
165
+ params_size = data.shift
166
+ params = params_size.times.map { shift_param(data) }
167
+
168
+ block_present = data.shift
169
+ block_param =
170
+ if block_present
171
+ block_name = data.shift
172
+ traces_count = data.shift
173
+ traces = traces_count.times.map { shift_block_trace(data) }
174
+
175
+ Racer::Trace::BlockParam.new(
176
+ name: block_name,
177
+ traces:
178
+ )
179
+ end
180
+
181
+ [params, block_param]
182
+ end
183
+
184
+ def shift_param(data)
185
+ name = data.shift
186
+ type = Racer::Trace::Param::TYPES.fetch(data.shift) do |key|
187
+ warn "Unexpected return type received #{key}"
188
+ Racer::Trace::Param::TYPES.first
189
+ end
190
+
191
+ type_name = shift_constant_instance(data)
192
+
193
+ Racer::Trace::Param.new(name: name&.to_sym, type_name:, type:)
194
+ end
195
+
196
+ def shift_constant_updates(data)
197
+ constant_update_count = data.shift
198
+ constant_update_count.times.map do
199
+ shift_constant(data)
200
+ end
201
+ end
202
+
203
+ def shift_constant(data)
204
+ name = data.shift
205
+ anonymous = data.shift
206
+ type = data.shift
207
+
208
+ superclass = data.shift
209
+
210
+ included_modules_count = data.shift
211
+ included_modules = included_modules_count.times.map { data.shift }
212
+
213
+ prepended_modules_count = data.shift
214
+ prepended_modules = prepended_modules_count.times.map { data.shift }
215
+
216
+ extended_modules_count = data.shift
217
+ extended_modules = extended_modules_count.times.map { data.shift }
218
+
219
+ Racer::Trace::Constant.new(
220
+ name:,
221
+ anonymous:,
222
+ type: Racer::Trace::Constant::TYPES.fetch(type),
223
+ superclass:,
224
+ included_modules:,
225
+ prepended_modules:,
226
+ extended_modules:
227
+ )
228
+ end
229
+
230
+ def shift_constant_instance(data)
231
+ name = data.shift
232
+ singleton = data.shift
233
+ generic_argument_count = data.shift
234
+
235
+ generic_arguments =
236
+ generic_argument_count.times.map do
237
+ union_size = data.shift
238
+
239
+ union_size.times.map do
240
+ shift_constant_instance(data)
241
+ end
242
+ end
243
+
244
+ Racer::Trace::ConstantInstance.new(
245
+ name:,
246
+ singleton:,
247
+ generic_arguments:
248
+ )
249
+ end
250
+ end