hyraft-server 0.1.0.alpha2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 20e0fd054edbbb37389e76f612452213bf57158e3c4ace4c9afb0b83e6ceb0fd
4
+ data.tar.gz: 6ffc679b1999fa1d57bc53ca0074cad794091a9467b3266e0f7b714d9c3a1345
5
+ SHA512:
6
+ metadata.gz: 6a411d02e246c8e4e5d2f7ced20d3c1669f1584b53ab91c08301adf85921a55d729f0b985e956a56de3d8d1246009842f1c4f0fd2db2988c42c6772f293952cf
7
+ data.tar.gz: d4f332baaec6d52c5b75596d2f17cf28e14ad7c03b4e48fdd606935d3f949ff5fb4e5ac44bc1016e27cd08e4732af0df8f330b52967b13dca0442b28d98e3c71
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Hyraft Server
2
+
3
+ Web server for Hyraft framework
4
+
5
+ Dual-server web stack implementing hexagonal architecture. Supports simultaneous web and API servers across multiple Ruby backends (Puma, Thin, Falcon, Iodine) for the Hyraft platform.
6
+
7
+ ## Installation
8
+
9
+ Open Gemfile:
10
+ put:
11
+
12
+ ```bash
13
+ gem 'hyraft-server'
14
+ ```
15
+
16
+ Install the gem and add to the application's Gemfile by executing:
17
+
18
+ ```bash
19
+ bundle install
20
+ ```
21
+
22
+
23
+ ## Usage
24
+
25
+ Command Variants
26
+ Hotkey:
27
+
28
+ ```rb
29
+
30
+ hyr s [server-name] Start web server
31
+ hyr s [server-name] --api Start API server directly
32
+ hyr s-v Show version
33
+ hyr s-h Show this help
34
+ Shortkey:
35
+
36
+ hyr-serve [server-name] Start web server
37
+ hyr-serve [server-name] --api Start API server directly
38
+ hyr-serve s-v Show version
39
+ hyr-serve s-h Show this help
40
+ Standard:
41
+
42
+ hyraft-server [server-name] [options] Start web server
43
+ hyraft-server [server-name] --api [options] Start API server directly
44
+ hyraft-server server-version Show version
45
+ hyraft-server server-help Show this help
46
+ Examples
47
+ hyr s thin # Start web server with Thin
48
+ hyr-serve thin # Start web server with Thin
49
+ hyraft-server thin # Start web server with Thin
50
+ hyraft-server thin --api # Start API server with Thin
51
+ hyraft-server puma -p 1091 # Start web server on port 1091
52
+ hyraft-server falcon --http2 # Start with HTTP/2 (Falcon)
53
+
54
+
55
+ ```
56
+ ## Development
57
+
58
+ After checking out the repo, run `bundle install` to install dependencies.
59
+
60
+ Then, run `rake test` to run the tests.
61
+
62
+ ## Contributing
63
+
64
+ Bug reports and pull requests are welcome on GitHub at https://github.com/demjhonsilver/hyraft-server. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/demjhonsilver/hyraft-server/blob/master/CODE_OF_CONDUCT.md).
65
+
66
+ ## License
67
+
68
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
69
+
70
+ ## Code of Conduct
71
+
72
+ Everyone interacting in the Hyraft::Server project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/demjhonsilver/hyraft-server/blob/master/CODE_OF_CONDUCT.md).
data/bin/hyr ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # exe/hyr
5
+ # Short alias for hyraft-server command
6
+
7
+ require "hyraft/server"
8
+ require "hyraft/server/launcher"
9
+
10
+ # This is just an alias - pass all arguments to hyraft-server
11
+ cmd = ARGV.shift
12
+ launcher = Hyraft::Server::Launcher.new
13
+ launcher.start(cmd, ARGV)
data/bin/hyr-serve ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # exe/hyr-serve
5
+ # Short alias for hyraft-server command
6
+
7
+ require "hyraft/server"
8
+ require "hyraft/server/launcher"
9
+
10
+ # This is just an alias - pass all arguments to hyraft-server
11
+ cmd = ARGV.shift
12
+ launcher = Hyraft::Server::Launcher.new
13
+ launcher.start(cmd, ARGV)
data/bin/hyraft-server ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "hyraft/server"
5
+ require "hyraft/server/launcher"
6
+
7
+ cmd = ARGV.shift
8
+ launcher = Hyraft::Server::Launcher.new
9
+ launcher.start(cmd, ARGV)
@@ -0,0 +1,340 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+
5
+ module Hyraft
6
+ module Server
7
+ # Main server launcher for Hyraft framework
8
+ #
9
+ # Handles starting web and API servers with support for multiple
10
+ # Ruby server backends (Puma, Thin, Falcon, Iodine)
11
+ #
12
+ # == Usage Examples
13
+ #
14
+ # hyr s thin # Start web server with Thin
15
+ # hyr s thin --api # Start API server with Thin
16
+ # hyraft-server puma -p 3000 # Start on custom port
17
+ # hyraft-server falcon --http2 # Start with HTTP/2
18
+ #
19
+ # @example Start a web server
20
+ # launcher = Hyraft::Server::Launcher.new
21
+ # launcher.start('thin', [])
22
+ #
23
+ # @example Start an API server
24
+ # launcher = Hyraft::Server::Launcher.new
25
+ # launcher.start('puma', ['--api'])
26
+ class Launcher
27
+ # ANSI color codes for terminal output
28
+ COLORS = {
29
+ lime: "\033[92m",
30
+ yellow: "\033[93m",
31
+ reset: "\033[0m"
32
+ }
33
+
34
+ # Initialize a new launcher instance
35
+ #
36
+ # @param options [Hash] Configuration options
37
+ # @option options [String] :server Server type (puma, thin, falcon, iodine)
38
+ # @option options [String] :host Host to bind to (default: "localhost")
39
+ # @option options [Integer] :port Web server port (default: 1091)
40
+ # @option options [Integer] :port_api API server port (default: 1092)
41
+ # @option options [String] :rack_socket Rack config file for web server
42
+ # @option options [String] :rack_socket_api Rack config file for API server
43
+ # @option options [Boolean] :http2 Enable HTTP/2 (Falcon only)
44
+ # @option options [Boolean] :http3 Enable HTTP/3 (Falcon only)
45
+ # @option options [Boolean] :api Enable API server mode
46
+ #
47
+ # @example Basic initialization
48
+ # Launcher.new
49
+ #
50
+ # @example With custom options
51
+ # Launcher.new(port: 3000, server: 'puma')
52
+ def initialize(options = {})
53
+ @options = {
54
+ server: nil,
55
+ host: "localhost",
56
+ port: 1091,
57
+ port_api: 1092,
58
+ rack_socket: "infra/server/web-server.ru",
59
+ rack_socket_api: "infra/server/api-server.ru",
60
+ http2: false,
61
+ http3: false,
62
+ api: false
63
+ }.merge(options)
64
+ end
65
+
66
+ # Start the server with given command and arguments
67
+ #
68
+ # Supports multiple command formats and server types with
69
+ # comprehensive error handling and user feedback.
70
+ #
71
+ # @param cmd [String] Command to execute
72
+ # - Server name: 'puma', 'thin', 'falcon', 'iodine'
73
+ # - Action: 'server', 's', 'svr', 'serve', 'server-help', 'server-version'
74
+ # @param args [Array<String>] Command line arguments
75
+ #
76
+ # @return [void]
77
+ #
78
+ # @example Start web server with Thin
79
+ # start('thin', [])
80
+ #
81
+ # @example Start API server with Puma
82
+ # start('puma', ['--api'])
83
+ #
84
+ # @example Show help
85
+ # start('server-help', [])
86
+ #
87
+ # @example Show version
88
+ # start('server-version', [])
89
+ #
90
+ # @raise [OptionParser::InvalidOption] When invalid options are provided
91
+ # @raise [OptionParser::MissingArgument] When required arguments are missing
92
+ def start(cmd, args)
93
+ begin
94
+ # Check if command is a direct server name
95
+ if %w[thin puma falcon iodine].include?(cmd)
96
+ @options[:server] = cmd
97
+ parse_server_options!(args)
98
+ launch_server
99
+ else
100
+ case cmd
101
+ when 'server', 's', 'svr', 'serve'
102
+ parse_server_options!(args)
103
+ launch_server
104
+ when 'server-version', 'server-v', 's-v'
105
+ show_version
106
+ when 'server-help', 'server-h', 's-h'
107
+ show_usage
108
+ when nil, ''
109
+ puts "#{COLORS[:yellow]}[!] No command provided. Showing help...#{COLORS[:reset]}"
110
+ show_usage
111
+ else
112
+ puts "#{COLORS[:yellow]}[!] Unknown command: '#{cmd}'. Showing help...#{COLORS[:reset]}"
113
+ show_usage
114
+ end
115
+ end
116
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
117
+ puts "#{COLORS[:yellow]}[!] #{e.message}#{COLORS[:reset]}"
118
+ puts "#{COLORS[:yellow]}[!] Falling back to help info...#{COLORS[:reset]}"
119
+ show_usage
120
+ rescue => e
121
+ puts "#{COLORS[:yellow]}[!] Unexpected error: #{e.message}#{COLORS[:reset]}"
122
+ puts "#{COLORS[:yellow]}[!] Showing help for reference...#{COLORS[:reset]}"
123
+ show_usage
124
+ end
125
+ end
126
+
127
+ # Display comprehensive usage information
128
+ #
129
+ # Shows available commands, options, and examples for the Hyraft server.
130
+ # Includes colorized output when not in test environment.
131
+ #
132
+ # == Command Variants
133
+ #
134
+ # Hotkey:
135
+ # hyr s [server-name] Start web server
136
+ # hyr s [server-name] --api Start API server directly
137
+ # hyr s-v Show version
138
+ # hyr s-h Show this help
139
+ #
140
+ # Shortkey:
141
+ # hyr-serve [server-name] Start web server
142
+ # hyr-serve [server-name] --api Start API server directly
143
+ # hyr-serve s-v Show version
144
+ # hyr-serve s-h Show this help
145
+ #
146
+ # Standard:
147
+ # hyraft-server [server-name] [options] Start web server
148
+ # hyraft-server [server-name] --api [options] Start API server directly
149
+ # hyraft-server server-version Show version
150
+ # hyraft-server server-help Show this help
151
+ #
152
+ # == Examples
153
+ #
154
+ # hyr s thin # Start web server with Thin
155
+ # hyr-serve thin # Start web server with Thin
156
+ # hyraft-server thin # Start web server with Thin
157
+ # hyraft-server thin --api # Start API server with Thin
158
+ # hyraft-server puma -p 1091 # Start web server on port 1091
159
+ # hyraft-server falcon --http2 # Start with HTTP/2 (Falcon)
160
+ #
161
+ # @return [void]
162
+ def show_usage
163
+ title_color = colorize? ? COLORS[:lime] : ""
164
+ header_color = colorize? ? COLORS[:yellow] : ""
165
+ reset_color = colorize? ? COLORS[:reset] : ""
166
+
167
+ puts "#{title_color}Hyraft Server #{Hyraft::Server::VERSION}#{reset_color}"
168
+ puts "High-performance web server with hexagonal architecture"
169
+ puts ""
170
+ puts "#{header_color}Usage:#{reset_color}"
171
+ puts " hyraft-server [server-name] [options]"
172
+ puts ""
173
+ puts "#{header_color}Hotkey:#{reset_color}"
174
+ puts " hyr s [server-name] Start web server (legacy)"
175
+ puts " hyr s [server-name] --api Start API server directly"
176
+ puts " hyr s-v Show version"
177
+ puts " hyr s-h Show this help"
178
+ puts ""
179
+ puts "#{header_color}Shortkey:#{reset_color}"
180
+ puts " hyr-serve [server-name] Start web server (legacy)"
181
+ puts " hyr-serve [server-name] --api Start API server directly"
182
+ puts " hyr-serve s-v Show version"
183
+ puts " hyr-serve s-h Show this help"
184
+ puts ""
185
+ puts "#{header_color}Standard Key:#{reset_color}"
186
+ puts " hyraft-server [server-name] [options] Start web server (legacy)"
187
+ puts " hyraft-server [server-name] --api [options] Start API server directly"
188
+ puts " hyraft-server server-version Show version"
189
+ puts " hyraft-server server-help Show this help"
190
+ puts ""
191
+ puts "#{header_color}Servers:#{reset_color} puma, thin, falcon, iodine"
192
+ puts ""
193
+ puts "#{header_color}Options:#{reset_color}"
194
+ puts " -s, --server SERVER Server (puma, thin, falcon, iodine)"
195
+ puts " -b, --bind HOST Host (default: localhost)"
196
+ puts " -p, --port PORT Port (default: 1091)"
197
+ puts " --port-api PORT API Port (default: 1092)"
198
+ puts " -c, --config FILE Rack config file"
199
+ puts " --config-api FILE API Rack config file"
200
+ puts " --api Enable API server"
201
+ puts " --http2 Enable HTTP/2 (Falcon only)"
202
+ puts " --http3 Enable HTTP/3 (Falcon only)"
203
+ puts ""
204
+ puts "#{header_color}Examples:#{reset_color}"
205
+ example_color = colorize? ? COLORS[:lime] : ""
206
+ puts "#{example_color} hyr s thin #{reset_color}# Start web server with Thin - Hotkey"
207
+ puts "#{example_color} hyr-serve thin #{reset_color}# Start web server with Thin - Shortkey"
208
+ puts "#{example_color} hyraft-server thin #{reset_color}# Start web server with Thin"
209
+ puts "#{example_color} hyraft-server thin --api #{reset_color}# Start API server with Thin"
210
+ puts "#{example_color} hyraft-server puma -p 1091 #{reset_color}# Start web server on port 1091"
211
+ puts "#{example_color} hyraft-server falcon --http2 #{reset_color}# Start with HTTP/2 (Falcon)"
212
+ puts "#{example_color} hyraft-server s thin #{reset_color}# Legacy syntax (still works)"
213
+ end
214
+
215
+ private
216
+
217
+ # Check if terminal output should be colorized
218
+ #
219
+ # @return [Boolean] true if colors should be used
220
+ # @!visibility private
221
+ def colorize?
222
+ ENV["RACK_ENV"] != "test" && ENV["APP_ENV"] != "test"
223
+ end
224
+
225
+ # Parse server-specific command line options
226
+ #
227
+ # @param args [Array<String>] Command line arguments
228
+ # @return [void]
229
+ # @!visibility private
230
+ def parse_server_options!(args)
231
+ # Only look for server in args if not already set
232
+ unless @options[:server]
233
+ first_arg = args[0]
234
+ if %w[thin puma falcon iodine].include?(first_arg)
235
+ @options[:server] = args.shift
236
+ end
237
+ end
238
+
239
+ OptionParser.new do |opts|
240
+ opts.banner = "Usage: hyraft-server [server] [options]"
241
+ opts.on("-s", "--server SERVER", "Server (puma, thin, falcon, iodine)") { |v| @options[:server] = v }
242
+ opts.on("-b", "--bind HOST", "Host") { |v| @options[:host] = v }
243
+ opts.on("-p", "--port PORT", Integer, "Port") { |v| @options[:port] = v }
244
+ opts.on("--port-api PORT", Integer, "API Port (default: 1092)") { |v| @options[:port_api] = v }
245
+ opts.on("-c", "--config FILE", "Rack config file") { |v| @options[:rack_socket] = v }
246
+ opts.on("--config-api FILE", "API Rack config file") { |v| @options[:rack_socket_api] = v }
247
+ opts.on("--api", "Enable API server") { |v| @options[:api] = v }
248
+ opts.on("--http2", "Enable HTTP/2 (Falcon only)") { |v| @options[:http2] = v }
249
+ opts.on("--http3", "Enable HTTP/3 (Falcon only)") { |v| @options[:http3] = v }
250
+ end.parse!(args)
251
+
252
+ unless @options[:server]
253
+ abort "Error: No server specified. Use -s SERVER or provide a server name (puma, thin, falcon, iodine)."
254
+ end
255
+ end
256
+
257
+ # Launch the appropriate server (web or API)
258
+ #
259
+ # @return [void]
260
+ # @!visibility private
261
+ def launch_server
262
+ if @options[:api]
263
+ launch_api_server
264
+ else
265
+ launch_web_server
266
+ end
267
+ end
268
+
269
+ # Launch web server
270
+ #
271
+ # @return [void]
272
+ # @!visibility private
273
+ def launch_web_server
274
+ puts "[ WEB ] - Hyraft"
275
+ puts "* Using server: #{@options[:server].capitalize}"
276
+ puts "* Listening on #{COLORS[:yellow]}http://#{@options[:host]}:#{@options[:port]}#{COLORS[:reset]}"
277
+
278
+ case @options[:server]
279
+ when "puma"
280
+ exec "bundle exec puma -b tcp://#{@options[:host]}:#{@options[:port]} #{@options[:rack_socket]}"
281
+ when "thin"
282
+ exec "bundle exec thin start -p #{@options[:port]} -R #{@options[:rack_socket]}"
283
+ when "falcon"
284
+ if @options[:http3]
285
+ puts "#{COLORS[:lime]}* HTTP/3 enabled!#{COLORS[:reset]}"
286
+ exec "bundle exec falcon serve --protocol HTTP3 --bind https://#{@options[:host]}:#{@options[:port]} --config #{@options[:rack_socket]}"
287
+ elsif @options[:http2]
288
+ puts "#{COLORS[:lime]}* HTTP/2 enabled!#{COLORS[:reset]}"
289
+ exec "bundle exec falcon serve --protocol HTTP2 --bind http://#{@options[:host]}:#{@options[:port]} --config #{@options[:rack_socket]}"
290
+ else
291
+ exec "bundle exec falcon serve --bind http://#{@options[:host]}:#{@options[:port]} --config #{@options[:rack_socket]}"
292
+ end
293
+ when "iodine"
294
+ exec "bundle exec iodine -p #{@options[:port]} -t 1 -w 1 #{@options[:rack_socket]}"
295
+ else
296
+ abort "Unknown server: #{@options[:server]}"
297
+ end
298
+ end
299
+
300
+ # Launch API server
301
+ #
302
+ # @return [void]
303
+ # @!visibility private
304
+ def launch_api_server
305
+ puts "[ API ] - Hyraft"
306
+ puts "* Using server: #{@options[:server].capitalize}"
307
+ puts "* Listening on #{COLORS[:yellow]}http://#{@options[:host]}:#{@options[:port_api]}#{COLORS[:reset]}"
308
+
309
+ case @options[:server]
310
+ when "puma"
311
+ exec "bundle exec puma -b tcp://#{@options[:host]}:#{@options[:port_api]} #{@options[:rack_socket_api]}"
312
+ when "thin"
313
+ exec "bundle exec thin start -p #{@options[:port_api]} -R #{@options[:rack_socket_api]}"
314
+ when "falcon"
315
+ if @options[:http3]
316
+ puts "#{COLORS[:lime]}* HTTP/3 enabled!#{COLORS[:reset]}"
317
+ exec "bundle exec falcon serve --protocol HTTP3 --bind https://#{@options[:host]}:#{@options[:port_api]} --config #{@options[:rack_socket_api]}"
318
+ elsif @options[:http2]
319
+ puts "#{COLORS[:lime]}* HTTP/2 enabled!#{COLORS[:reset]}"
320
+ exec "bundle exec falcon serve --protocol HTTP2 --bind http://#{@options[:host]}:#{@options[:port_api]} --config #{@options[:rack_socket_api]}"
321
+ else
322
+ exec "bundle exec falcon serve --bind http://#{@options[:host]}:#{@options[:port_api]} --config #{@options[:rack_socket_api]}"
323
+ end
324
+ when "iodine"
325
+ exec "bundle exec iodine -p #{@options[:port_api]} -t 1 -w 1 #{@options[:rack_socket_api]}"
326
+ else
327
+ abort "Unknown server: #{@options[:server]}"
328
+ end
329
+ end
330
+
331
+ # Show version information
332
+ #
333
+ # @return [void]
334
+ # @!visibility private
335
+ def show_version
336
+ puts "Hyraft Server v#{Hyraft::Server::VERSION}"
337
+ end
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,75 @@
1
+ module Hyraft
2
+ module Server
3
+ class ApiLogger
4
+ COLORS = {
5
+ reset: "\e[0m",
6
+ blue: "\e[34m",
7
+ cyan: "\e[36m",
8
+ green: "\e[32m",
9
+ yellow: "\e[33m",
10
+ red: "\e[31m",
11
+ magenta: "\e[35m"
12
+ }
13
+
14
+ def initialize(app)
15
+ @app = app
16
+ end
17
+
18
+ def call(env)
19
+ start_time = Time.now
20
+ status, headers, response = @app.call(env)
21
+ end_time = Time.now
22
+
23
+ # Calculate metrics
24
+ duration_ms = ((end_time - start_time) * 1000).round(2)
25
+ content_length = headers['Content-Length'] || response_body_length(response)
26
+
27
+ # Convert bytes to KB
28
+ content_length_kb = if content_length.is_a?(Numeric)
29
+ "#{(content_length / 1024.0).round(2)} KB"
30
+ else
31
+ content_length
32
+ end
33
+
34
+ path = env['PATH_INFO']
35
+ method = env['REQUEST_METHOD']
36
+ status_code = status.to_i
37
+
38
+ # Method-specific colors
39
+ method_color = case method
40
+ when 'GET' then :green
41
+ when 'POST' then :blue
42
+ when 'PUT', 'PATCH' then :cyan
43
+ when 'DELETE' then :red
44
+ else :yellow
45
+ end
46
+
47
+ # Status-specific colors
48
+ status_color = case status_code
49
+ when 200..299 then :green
50
+ when 300..399 then :cyan
51
+ when 400..499 then :yellow
52
+ when 500..599 then :red
53
+ else :magenta
54
+ end
55
+
56
+ # Log with colors and metrics
57
+ log_message = "#{COLORS[method_color]}#{method}#{COLORS[:reset]} #{path} → #{COLORS[status_color]}#{status_code}#{COLORS[:reset]} | #{duration_ms}ms | #{content_length_kb}"
58
+ puts log_message
59
+
60
+ [status, headers, response]
61
+ end
62
+
63
+ private
64
+
65
+ def response_body_length(response)
66
+ response.inject(0) { |sum, part| sum + part.bytesize }
67
+ rescue
68
+ 'unknown'
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ # Define top-level constant here
75
+ ::ApiLogger = Hyraft::Server::ApiLogger unless defined?(::ApiLogger)
@@ -0,0 +1,80 @@
1
+ # hyraft-server/lib/hyraft/server/middleware/web_logger.rb
2
+ module Hyraft
3
+ module Server
4
+ class WebLogger
5
+ COLORS = {
6
+ reset: "\e[0m",
7
+ blue: "\e[34m",
8
+ cyan: "\e[36m",
9
+ green: "\e[32m",
10
+ yellow: "\e[33m",
11
+ red: "\e[31m",
12
+ magenta: "\e[35m"
13
+ }
14
+
15
+ def initialize(app)
16
+ @app = app
17
+ end
18
+
19
+ def call(env)
20
+ start_time = Time.now
21
+ status, headers, response = @app.call(env)
22
+ end_time = Time.now
23
+
24
+ duration_ms = ((end_time - start_time) * 1000).round(2)
25
+ content_length = headers['Content-Length'] || response_body_length(response)
26
+
27
+ # Convert bytes to KB
28
+ content_length_kb = if content_length.is_a?(Numeric)
29
+ "#{(content_length / 1024.0).round(2)} KB"
30
+ else
31
+ content_length
32
+ end
33
+
34
+ path = env['PATH_INFO']
35
+ method = env['REQUEST_METHOD']
36
+ status_code = status.to_i
37
+
38
+ # Method-specific colors
39
+ method_color = case method
40
+ when 'GET' then :green
41
+ when 'POST' then :blue
42
+ when 'PUT', 'PATCH' then :cyan
43
+ when 'DELETE' then :red
44
+ else :yellow
45
+ end
46
+
47
+ # Status-specific colors
48
+ status_color = case status_code
49
+ when 200..299 then :green
50
+ when 300..399 then :cyan
51
+ when 400..499 then :yellow
52
+ when 500..599 then :red
53
+ else :magenta
54
+ end
55
+
56
+ puts "#{COLORS[method_color]}#{method}#{COLORS[:reset]} #{path} → #{COLORS[status_color]}#{status_code}#{COLORS[:reset]} | #{duration_ms}ms | #{content_length_kb}"
57
+
58
+ [status, headers, response]
59
+ end
60
+
61
+ private
62
+
63
+ def response_body_length(response)
64
+ if response.respond_to?(:each)
65
+ total = 0
66
+ response.each { |part| total += part.bytesize }
67
+ total
68
+ elsif response.respond_to?(:to_path) && File.file?(response.to_path)
69
+ File.size(response.to_path)
70
+ else
71
+ 'unknown'
72
+ end
73
+ rescue
74
+ 'unknown'
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ ::WebLogger = Hyraft::Server::WebLogger unless defined?(::WebLogger)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyraft
4
+ module Server
5
+ VERSION = "0.1.0.alpha2"
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "server/version"
4
+
5
+
6
+ module Hyraft
7
+ module Server
8
+ class Error < StandardError; end
9
+ # Your code goes here...
10
+
11
+
12
+ end
13
+ end
14
+
15
+ require_relative 'server/middleware/web_logger'
16
+ require_relative 'server/middleware/api_logger'
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hyraft-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.alpha2
5
+ platform: ruby
6
+ authors:
7
+ - Demjhon Silver
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.3'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.26'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '5.26'
54
+ - !ruby/object:Gem::Dependency
55
+ name: yard
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.9.34
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.9.34
68
+ - !ruby/object:Gem::Dependency
69
+ name: redcarpet
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.6'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.6'
82
+ description: Dual-server web stack implementing hexagonal architecture. Supports simultaneous
83
+ web and API servers across multiple Ruby backends (Puma, Thin, Falcon, Iodine) for
84
+ the Hyraft platform.
85
+ executables:
86
+ - hyr
87
+ - hyr-serve
88
+ - hyraft-server
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - LICENSE.txt
93
+ - README.md
94
+ - bin/hyr
95
+ - bin/hyr-serve
96
+ - bin/hyraft-server
97
+ - lib/hyraft/server.rb
98
+ - lib/hyraft/server/launcher.rb
99
+ - lib/hyraft/server/middleware/api_logger.rb
100
+ - lib/hyraft/server/middleware/web_logger.rb
101
+ - lib/hyraft/server/version.rb
102
+ homepage: https://github.com/demjhonsilver/hyraft-server
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ homepage_uri: https://github.com/demjhonsilver/hyraft-server
107
+ source_code_uri: https://github.com/demjhonsilver/hyraft-server
108
+ changelog_uri: https://github.com/demjhonsilver/hyraft-server/releases
109
+ documentation_uri: https://rubydoc.info/gems/hyraft-server
110
+ rubygems_mfa_required: 'true'
111
+ yard.run: yri
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: 3.4.0
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubygems_version: 3.6.9
127
+ specification_version: 4
128
+ summary: Web server for Hyraft framework
129
+ test_files: []