itsi-server 0.1.1 → 0.1.3
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 +4 -4
- data/exe/itsi +88 -28
- data/ext/itsi_error/Cargo.toml +2 -0
- data/ext/itsi_error/src/from.rs +70 -0
- data/ext/itsi_error/src/lib.rs +10 -37
- data/ext/itsi_instrument_entry/Cargo.toml +15 -0
- data/ext/itsi_instrument_entry/src/lib.rs +31 -0
- data/ext/itsi_rb_helpers/Cargo.toml +2 -0
- data/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
- data/ext/itsi_rb_helpers/src/lib.rs +90 -10
- data/ext/itsi_scheduler/Cargo.toml +24 -0
- data/ext/itsi_scheduler/extconf.rb +6 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
- data/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
- data/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
- data/ext/itsi_scheduler/src/lib.rs +38 -0
- data/ext/itsi_server/Cargo.toml +14 -2
- data/ext/itsi_server/extconf.rb +1 -1
- data/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
- data/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
- data/ext/itsi_server/src/body_proxy/mod.rs +2 -0
- data/ext/itsi_server/src/lib.rs +58 -7
- data/ext/itsi_server/src/request/itsi_request.rs +238 -104
- data/ext/itsi_server/src/response/itsi_response.rs +347 -0
- data/ext/itsi_server/src/response/mod.rs +1 -0
- data/ext/itsi_server/src/server/bind.rs +50 -20
- data/ext/itsi_server/src/server/bind_protocol.rs +37 -0
- data/ext/itsi_server/src/server/io_stream.rs +104 -0
- data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
- data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
- data/ext/itsi_server/src/server/itsi_server.rs +196 -134
- data/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
- data/ext/itsi_server/src/server/listener.rs +184 -127
- data/ext/itsi_server/src/server/mod.rs +7 -1
- data/ext/itsi_server/src/server/process_worker.rs +196 -0
- data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
- data/ext/itsi_server/src/server/signal.rs +70 -0
- data/ext/itsi_server/src/server/thread_worker.rs +368 -0
- data/ext/itsi_server/src/server/tls.rs +42 -28
- data/ext/itsi_tracing/Cargo.toml +4 -0
- data/ext/itsi_tracing/src/lib.rs +36 -6
- data/lib/itsi/request.rb +30 -14
- data/lib/itsi/server/rack/handler/itsi.rb +25 -0
- data/lib/itsi/server/scheduler_mode.rb +6 -0
- data/lib/itsi/server/version.rb +1 -1
- data/lib/itsi/server.rb +82 -2
- data/lib/itsi/signals.rb +23 -0
- data/lib/itsi/stream_io.rb +38 -0
- metadata +38 -25
- data/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
- data/ext/itsi_server/src/stream_writer/mod.rs +0 -21
data/lib/itsi/server.rb
CHANGED
@@ -2,12 +2,92 @@
|
|
2
2
|
|
3
3
|
require_relative "server/version"
|
4
4
|
require_relative "server/itsi_server"
|
5
|
+
require_relative "signals"
|
6
|
+
require_relative "request"
|
7
|
+
require_relative "stream_io"
|
8
|
+
require_relative "server/rack/handler/itsi"
|
5
9
|
|
6
10
|
module Itsi
|
7
11
|
class Server
|
8
|
-
|
12
|
+
|
13
|
+
def self.running?
|
14
|
+
@running ||= false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.start(app:, **opts)
|
18
|
+
server = new(app: ->{app}, **opts)
|
19
|
+
@running = true
|
20
|
+
Signal.trap('INT', 'DEFAULT')
|
21
|
+
server.start
|
22
|
+
ensure
|
23
|
+
@running = false
|
24
|
+
end
|
25
|
+
|
9
26
|
def self.call(app, request)
|
10
|
-
app.call(request.to_env)
|
27
|
+
respond request, app.call(request.to_env)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.streaming_body?(body)
|
31
|
+
body.respond_to?(:call) && !body.respond_to?(:each)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.respond(request, (status, headers, body))
|
35
|
+
response = request.response
|
36
|
+
|
37
|
+
# Don't try and respond if we've been hijacked.
|
38
|
+
# The hijacker is now responsible for this.
|
39
|
+
return if request.hijacked
|
40
|
+
|
41
|
+
# 1. Set Status
|
42
|
+
response.status = status
|
43
|
+
|
44
|
+
# 2. Set Headers
|
45
|
+
headers.each do |key, value|
|
46
|
+
next response.add_header(key, value) unless value.is_a?(Array)
|
47
|
+
|
48
|
+
value.each do |v|
|
49
|
+
response.add_header(key, v)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# 3. Set Body
|
54
|
+
# As soon as we start setting the response
|
55
|
+
# the server will begin to stream it to the client.
|
56
|
+
|
57
|
+
# If we're partially hijacked or returned a streaming body,
|
58
|
+
# stream this response.
|
59
|
+
|
60
|
+
if (body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack"))
|
61
|
+
body_streamer.call(StreamIO.new(response))
|
62
|
+
|
63
|
+
# If we're enumerable with more than one chunk
|
64
|
+
# also stream, otherwise write in a single chunk
|
65
|
+
elsif body.respond_to?(:each) || body.respond_to?(:to_ary)
|
66
|
+
unless body.respond_to?(:each)
|
67
|
+
body = body.to_ary
|
68
|
+
raise "Body #to_ary didn't return an array" unless body.is_a?(Array)
|
69
|
+
end
|
70
|
+
# We offset this iteration intentionally,
|
71
|
+
# to optimize for the case where there's only one chunk.
|
72
|
+
buffer = nil
|
73
|
+
body.each do |part|
|
74
|
+
response.send_frame(buffer.to_s) if buffer
|
75
|
+
buffer = part
|
76
|
+
end
|
77
|
+
|
78
|
+
response.send_and_close(buffer.to_s)
|
79
|
+
else
|
80
|
+
response.send_and_close(body.to_s)
|
81
|
+
end
|
82
|
+
ensure
|
83
|
+
response.close_write
|
84
|
+
body.close if body.respond_to?(:close)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.start_scheduler_loop(scheduler_class, scheduler_task)
|
88
|
+
scheduler = scheduler_class.new
|
89
|
+
Fiber.set_scheduler(scheduler)
|
90
|
+
[scheduler, Fiber.schedule(&scheduler_task)]
|
11
91
|
end
|
12
92
|
|
13
93
|
# If scheduler is enabled
|
data/lib/itsi/signals.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Itsi
|
2
|
+
module Signals
|
3
|
+
DEFAULT_SIGNALS = ["DEFAULT", ""].freeze
|
4
|
+
module SignalTrap
|
5
|
+
def self.trap(signal, *args, &block)
|
6
|
+
if DEFAULT_SIGNALS.include?(command.to_s) && block.nil?
|
7
|
+
Itsi::Server.reset_signal_handlers
|
8
|
+
nil
|
9
|
+
else
|
10
|
+
super(signal, *args, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
[Kernel, Signal].each do |receiver|
|
18
|
+
receiver.singleton_class.prepend(Itsi::Signals::SignalTrap)
|
19
|
+
end
|
20
|
+
|
21
|
+
[Object].each do |receiver|
|
22
|
+
receiver.include(Itsi::Signals::SignalTrap)
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Itsi
|
2
|
+
class StreamIO
|
3
|
+
attr :response
|
4
|
+
def initialize(response)
|
5
|
+
@response = response
|
6
|
+
end
|
7
|
+
|
8
|
+
def read
|
9
|
+
response.recv_frame
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(string)
|
13
|
+
response.send_frame(string)
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(string)
|
17
|
+
response.send_frame(string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def flush
|
21
|
+
# No-op
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
close_read
|
26
|
+
close_write
|
27
|
+
end
|
28
|
+
|
29
|
+
def close_read
|
30
|
+
response.close_read
|
31
|
+
end
|
32
|
+
|
33
|
+
def close_write
|
34
|
+
response.close_write
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itsi-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter Coppieters
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-14 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
|
-
name:
|
13
|
+
name: rack
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - "
|
16
|
+
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '
|
18
|
+
version: '1.6'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
|
-
- - "
|
23
|
+
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
25
|
+
version: '1.6'
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rb_sys
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,20 +37,6 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: 0.9.91
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: rack
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '2'
|
47
|
-
type: :runtime
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '2'
|
54
40
|
description: Itsi Server - A light-weight Rack Server implementation for Ruby
|
55
41
|
email:
|
56
42
|
- wc@pico.net.nz
|
@@ -69,30 +55,57 @@ files:
|
|
69
55
|
- exe/itsi
|
70
56
|
- ext/itsi_error/Cargo.lock
|
71
57
|
- ext/itsi_error/Cargo.toml
|
58
|
+
- ext/itsi_error/src/from.rs
|
72
59
|
- ext/itsi_error/src/lib.rs
|
60
|
+
- ext/itsi_instrument_entry/Cargo.toml
|
61
|
+
- ext/itsi_instrument_entry/src/lib.rs
|
73
62
|
- ext/itsi_rb_helpers/Cargo.lock
|
74
63
|
- ext/itsi_rb_helpers/Cargo.toml
|
64
|
+
- ext/itsi_rb_helpers/src/heap_value.rs
|
75
65
|
- ext/itsi_rb_helpers/src/lib.rs
|
66
|
+
- ext/itsi_scheduler/Cargo.toml
|
67
|
+
- ext/itsi_scheduler/extconf.rb
|
68
|
+
- ext/itsi_scheduler/src/itsi_scheduler.rs
|
69
|
+
- ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs
|
70
|
+
- ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs
|
71
|
+
- ext/itsi_scheduler/src/itsi_scheduler/timer.rs
|
72
|
+
- ext/itsi_scheduler/src/lib.rs
|
76
73
|
- ext/itsi_server/Cargo.toml
|
77
74
|
- ext/itsi_server/extconf.rb
|
75
|
+
- ext/itsi_server/src/body_proxy/big_bytes.rs
|
76
|
+
- ext/itsi_server/src/body_proxy/itsi_body_proxy.rs
|
77
|
+
- ext/itsi_server/src/body_proxy/mod.rs
|
78
78
|
- ext/itsi_server/src/lib.rs
|
79
79
|
- ext/itsi_server/src/request/itsi_request.rs
|
80
80
|
- ext/itsi_server/src/request/mod.rs
|
81
|
+
- ext/itsi_server/src/response/itsi_response.rs
|
82
|
+
- ext/itsi_server/src/response/mod.rs
|
81
83
|
- ext/itsi_server/src/server/bind.rs
|
84
|
+
- ext/itsi_server/src/server/bind_protocol.rs
|
85
|
+
- ext/itsi_server/src/server/io_stream.rs
|
82
86
|
- ext/itsi_server/src/server/itsi_ca/itsi_ca.crt
|
83
87
|
- ext/itsi_server/src/server/itsi_ca/itsi_ca.key
|
84
88
|
- ext/itsi_server/src/server/itsi_server.rs
|
89
|
+
- ext/itsi_server/src/server/lifecycle_event.rs
|
85
90
|
- ext/itsi_server/src/server/listener.rs
|
86
91
|
- ext/itsi_server/src/server/mod.rs
|
92
|
+
- ext/itsi_server/src/server/process_worker.rs
|
93
|
+
- ext/itsi_server/src/server/serve_strategy/cluster_mode.rs
|
94
|
+
- ext/itsi_server/src/server/serve_strategy/mod.rs
|
95
|
+
- ext/itsi_server/src/server/serve_strategy/single_mode.rs
|
96
|
+
- ext/itsi_server/src/server/signal.rs
|
97
|
+
- ext/itsi_server/src/server/thread_worker.rs
|
87
98
|
- ext/itsi_server/src/server/tls.rs
|
88
|
-
- ext/itsi_server/src/server/transfer_protocol.rs
|
89
|
-
- ext/itsi_server/src/stream_writer/mod.rs
|
90
99
|
- ext/itsi_tracing/Cargo.lock
|
91
100
|
- ext/itsi_tracing/Cargo.toml
|
92
101
|
- ext/itsi_tracing/src/lib.rs
|
93
102
|
- lib/itsi/request.rb
|
94
103
|
- lib/itsi/server.rb
|
104
|
+
- lib/itsi/server/rack/handler/itsi.rb
|
105
|
+
- lib/itsi/server/scheduler_mode.rb
|
95
106
|
- lib/itsi/server/version.rb
|
107
|
+
- lib/itsi/signals.rb
|
108
|
+
- lib/itsi/stream_io.rb
|
96
109
|
- sig/itsi_server.rbs
|
97
110
|
homepage: https://itsi.fyi
|
98
111
|
licenses:
|
@@ -108,12 +121,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
121
|
requirements:
|
109
122
|
- - ">="
|
110
123
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
124
|
+
version: 2.7.0
|
112
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
126
|
requirements:
|
114
127
|
- - ">="
|
115
128
|
- !ruby/object:Gem::Version
|
116
|
-
version: 3.
|
129
|
+
version: '3.1'
|
117
130
|
requirements: []
|
118
131
|
rubygems_version: 3.6.2
|
119
132
|
specification_version: 4
|
@@ -1,23 +0,0 @@
|
|
1
|
-
use itsi_error::ItsiError;
|
2
|
-
use std::str::FromStr;
|
3
|
-
|
4
|
-
#[derive(Debug, Default, Clone)]
|
5
|
-
pub enum TransferProtocol {
|
6
|
-
#[default]
|
7
|
-
Https,
|
8
|
-
Http,
|
9
|
-
Unix,
|
10
|
-
}
|
11
|
-
|
12
|
-
impl FromStr for TransferProtocol {
|
13
|
-
type Err = ItsiError;
|
14
|
-
|
15
|
-
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
16
|
-
match s {
|
17
|
-
"http" => Ok(TransferProtocol::Http),
|
18
|
-
"https" => Ok(TransferProtocol::Https),
|
19
|
-
"unix" => Ok(TransferProtocol::Unix),
|
20
|
-
_ => Err(ItsiError::UnsupportedProtocol(s.to_string())),
|
21
|
-
}
|
22
|
-
}
|
23
|
-
}
|
@@ -1,21 +0,0 @@
|
|
1
|
-
use bytes::Bytes;
|
2
|
-
use magnus::{error::Result as MagnusResult, exception::io_error, Error};
|
3
|
-
use tokio::sync::mpsc::Sender;
|
4
|
-
|
5
|
-
#[magnus::wrap(class = "Itsi::StreamWriter", free_immediately, size)]
|
6
|
-
pub struct StreamWriter {
|
7
|
-
sender: Sender<Bytes>,
|
8
|
-
}
|
9
|
-
|
10
|
-
impl StreamWriter {
|
11
|
-
pub fn new(sender: Sender<Bytes>) -> Self {
|
12
|
-
StreamWriter { sender }
|
13
|
-
}
|
14
|
-
|
15
|
-
pub fn write(&self, bytes: Bytes) -> MagnusResult<()> {
|
16
|
-
self.sender
|
17
|
-
.blocking_send(bytes)
|
18
|
-
.map_err(|e| Error::new(io_error(), format!("{:?}", e)))?;
|
19
|
-
Ok(())
|
20
|
-
}
|
21
|
-
}
|