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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/bin/hyr +13 -0
- data/bin/hyr-serve +13 -0
- data/bin/hyraft-server +9 -0
- data/lib/hyraft/server/launcher.rb +340 -0
- data/lib/hyraft/server/middleware/api_logger.rb +75 -0
- data/lib/hyraft/server/middleware/web_logger.rb +80 -0
- data/lib/hyraft/server/version.rb +7 -0
- data/lib/hyraft/server.rb +16 -0
- metadata +129 -0
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,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,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: []
|