itsi-server 0.1.1 → 0.1.2
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 +181 -133
- data/ext/itsi_server/src/server/lifecycle_event.rs +8 -0
- data/ext/itsi_server/src/server/listener.rs +169 -128
- 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 +253 -0
- data/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
- data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +238 -0
- data/ext/itsi_server/src/server/signal.rs +57 -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 +68 -2
- data/lib/itsi/signals.rb +18 -0
- data/lib/itsi/stream_io.rb +38 -0
- metadata +41 -14
- 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,78 @@
|
|
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
|
-
# Call our Rack app with our request ENV.
|
9
12
|
def self.call(app, request)
|
10
|
-
app.call(request.to_env)
|
13
|
+
respond request, app.call(request.to_env)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.streaming_body?(body)
|
17
|
+
body.respond_to?(:call) && !body.respond_to?(:each)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.respond(request, (status, headers, body))
|
21
|
+
response = request.response
|
22
|
+
|
23
|
+
# Don't try and respond if we've been hijacked.
|
24
|
+
# The hijacker is now responsible for this.
|
25
|
+
return if request.hijacked
|
26
|
+
|
27
|
+
# 1. Set Status
|
28
|
+
response.status = status
|
29
|
+
|
30
|
+
# 2. Set Headers
|
31
|
+
headers.each do |key, value|
|
32
|
+
next response.add_header(key, value) unless value.is_a?(Array)
|
33
|
+
|
34
|
+
value.each do |v|
|
35
|
+
response.add_header(key, v)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# 3. Set Body
|
40
|
+
# As soon as we start setting the response
|
41
|
+
# the server will begin to stream it to the client.
|
42
|
+
|
43
|
+
# If we're partially hijacked or returned a streaming body,
|
44
|
+
# stream this response.
|
45
|
+
|
46
|
+
if (body_streamer = streaming_body?(body) ? body : headers.delete("rack.hijack"))
|
47
|
+
body_streamer.call(StreamIO.new(response))
|
48
|
+
|
49
|
+
# If we're enumerable with more than one chunk
|
50
|
+
# also stream, otherwise write in a single chunk
|
51
|
+
elsif body.respond_to?(:each) || body.respond_to?(:to_ary)
|
52
|
+
unless body.respond_to?(:each)
|
53
|
+
body = body.to_ary
|
54
|
+
raise "Body #to_ary didn't return an array" unless body.is_a?(Array)
|
55
|
+
end
|
56
|
+
# We offset this iteration intentionally,
|
57
|
+
# to optimize for the case where there's only one chunk.
|
58
|
+
buffer = nil
|
59
|
+
body.each do |part|
|
60
|
+
response.send_frame(buffer.to_s) if buffer
|
61
|
+
buffer = part
|
62
|
+
end
|
63
|
+
|
64
|
+
response.send_and_close(buffer.to_s)
|
65
|
+
else
|
66
|
+
response.send_and_close(body.to_s)
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
response.close_write
|
70
|
+
body.close if body.respond_to?(:close)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.start_scheduler_loop(scheduler_class, scheduler_task)
|
74
|
+
scheduler = scheduler_class.new
|
75
|
+
Fiber.set_scheduler(scheduler)
|
76
|
+
[scheduler, Fiber.schedule(&scheduler_task)]
|
11
77
|
end
|
12
78
|
|
13
79
|
# If scheduler is enabled
|
data/lib/itsi/signals.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Itsi
|
2
|
+
module Signals
|
3
|
+
DEFAULT_SIGNALS = ["DEFAULT", ""].freeze
|
4
|
+
module TrapInterceptor
|
5
|
+
def trap(signal, command = nil, &block)
|
6
|
+
return super unless DEFAULT_SIGNALS.include?(command.to_s) && block.nil?
|
7
|
+
Itsi::Server.reset_signal_handlers
|
8
|
+
end
|
9
|
+
end
|
10
|
+
[Kernel, Signal].each do |receiver|
|
11
|
+
receiver.singleton_class.prepend(TrapInterceptor)
|
12
|
+
end
|
13
|
+
|
14
|
+
[Object].each do |receiver|
|
15
|
+
receiver.include(TrapInterceptor)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
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,13 +1,13 @@
|
|
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.2
|
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-13 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: libclang
|
@@ -24,33 +24,33 @@ dependencies:
|
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '14.0'
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
|
-
name:
|
27
|
+
name: rack
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- - "
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: '1.6'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - "
|
37
|
+
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: '1.6'
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
|
-
name:
|
41
|
+
name: rb_sys
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 0.9.91
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 0.9.91
|
54
54
|
description: Itsi Server - A light-weight Rack Server implementation for Ruby
|
55
55
|
email:
|
56
56
|
- wc@pico.net.nz
|
@@ -69,30 +69,57 @@ files:
|
|
69
69
|
- exe/itsi
|
70
70
|
- ext/itsi_error/Cargo.lock
|
71
71
|
- ext/itsi_error/Cargo.toml
|
72
|
+
- ext/itsi_error/src/from.rs
|
72
73
|
- ext/itsi_error/src/lib.rs
|
74
|
+
- ext/itsi_instrument_entry/Cargo.toml
|
75
|
+
- ext/itsi_instrument_entry/src/lib.rs
|
73
76
|
- ext/itsi_rb_helpers/Cargo.lock
|
74
77
|
- ext/itsi_rb_helpers/Cargo.toml
|
78
|
+
- ext/itsi_rb_helpers/src/heap_value.rs
|
75
79
|
- ext/itsi_rb_helpers/src/lib.rs
|
80
|
+
- ext/itsi_scheduler/Cargo.toml
|
81
|
+
- ext/itsi_scheduler/extconf.rb
|
82
|
+
- ext/itsi_scheduler/src/itsi_scheduler.rs
|
83
|
+
- ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs
|
84
|
+
- ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs
|
85
|
+
- ext/itsi_scheduler/src/itsi_scheduler/timer.rs
|
86
|
+
- ext/itsi_scheduler/src/lib.rs
|
76
87
|
- ext/itsi_server/Cargo.toml
|
77
88
|
- ext/itsi_server/extconf.rb
|
89
|
+
- ext/itsi_server/src/body_proxy/big_bytes.rs
|
90
|
+
- ext/itsi_server/src/body_proxy/itsi_body_proxy.rs
|
91
|
+
- ext/itsi_server/src/body_proxy/mod.rs
|
78
92
|
- ext/itsi_server/src/lib.rs
|
79
93
|
- ext/itsi_server/src/request/itsi_request.rs
|
80
94
|
- ext/itsi_server/src/request/mod.rs
|
95
|
+
- ext/itsi_server/src/response/itsi_response.rs
|
96
|
+
- ext/itsi_server/src/response/mod.rs
|
81
97
|
- ext/itsi_server/src/server/bind.rs
|
98
|
+
- ext/itsi_server/src/server/bind_protocol.rs
|
99
|
+
- ext/itsi_server/src/server/io_stream.rs
|
82
100
|
- ext/itsi_server/src/server/itsi_ca/itsi_ca.crt
|
83
101
|
- ext/itsi_server/src/server/itsi_ca/itsi_ca.key
|
84
102
|
- ext/itsi_server/src/server/itsi_server.rs
|
103
|
+
- ext/itsi_server/src/server/lifecycle_event.rs
|
85
104
|
- ext/itsi_server/src/server/listener.rs
|
86
105
|
- ext/itsi_server/src/server/mod.rs
|
106
|
+
- ext/itsi_server/src/server/process_worker.rs
|
107
|
+
- ext/itsi_server/src/server/serve_strategy/cluster_mode.rs
|
108
|
+
- ext/itsi_server/src/server/serve_strategy/mod.rs
|
109
|
+
- ext/itsi_server/src/server/serve_strategy/single_mode.rs
|
110
|
+
- ext/itsi_server/src/server/signal.rs
|
111
|
+
- ext/itsi_server/src/server/thread_worker.rs
|
87
112
|
- 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
113
|
- ext/itsi_tracing/Cargo.lock
|
91
114
|
- ext/itsi_tracing/Cargo.toml
|
92
115
|
- ext/itsi_tracing/src/lib.rs
|
93
116
|
- lib/itsi/request.rb
|
94
117
|
- lib/itsi/server.rb
|
118
|
+
- lib/itsi/server/rack/handler/itsi.rb
|
119
|
+
- lib/itsi/server/scheduler_mode.rb
|
95
120
|
- lib/itsi/server/version.rb
|
121
|
+
- lib/itsi/signals.rb
|
122
|
+
- lib/itsi/stream_io.rb
|
96
123
|
- sig/itsi_server.rbs
|
97
124
|
homepage: https://itsi.fyi
|
98
125
|
licenses:
|
@@ -108,12 +135,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
135
|
requirements:
|
109
136
|
- - ">="
|
110
137
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
138
|
+
version: 2.7.0
|
112
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
140
|
requirements:
|
114
141
|
- - ">="
|
115
142
|
- !ruby/object:Gem::Version
|
116
|
-
version: 3.
|
143
|
+
version: '3.1'
|
117
144
|
requirements: []
|
118
145
|
rubygems_version: 3.6.2
|
119
146
|
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
|
-
}
|