itsi 0.1.0 → 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.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +524 -44
  3. data/Rakefile +22 -33
  4. data/crates/itsi_error/Cargo.toml +2 -0
  5. data/crates/itsi_error/src/from.rs +70 -0
  6. data/crates/itsi_error/src/lib.rs +10 -37
  7. data/crates/itsi_instrument_entry/Cargo.toml +15 -0
  8. data/crates/itsi_instrument_entry/src/lib.rs +31 -0
  9. data/crates/itsi_rb_helpers/Cargo.toml +2 -0
  10. data/crates/itsi_rb_helpers/src/heap_value.rs +121 -0
  11. data/crates/itsi_rb_helpers/src/lib.rs +90 -10
  12. data/crates/itsi_scheduler/Cargo.toml +9 -1
  13. data/crates/itsi_scheduler/extconf.rb +1 -1
  14. data/crates/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  15. data/crates/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  16. data/crates/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  17. data/crates/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  18. data/crates/itsi_scheduler/src/lib.rs +31 -10
  19. data/crates/itsi_server/Cargo.toml +14 -2
  20. data/crates/itsi_server/extconf.rb +1 -1
  21. data/crates/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  22. data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  23. data/crates/itsi_server/src/body_proxy/mod.rs +2 -0
  24. data/crates/itsi_server/src/lib.rs +58 -7
  25. data/crates/itsi_server/src/request/itsi_request.rs +238 -104
  26. data/crates/itsi_server/src/response/itsi_response.rs +347 -0
  27. data/crates/itsi_server/src/response/mod.rs +1 -0
  28. data/crates/itsi_server/src/server/bind.rs +50 -20
  29. data/crates/itsi_server/src/server/bind_protocol.rs +37 -0
  30. data/crates/itsi_server/src/server/io_stream.rs +104 -0
  31. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
  32. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
  33. data/crates/itsi_server/src/server/itsi_server.rs +196 -134
  34. data/crates/itsi_server/src/server/lifecycle_event.rs +9 -0
  35. data/crates/itsi_server/src/server/listener.rs +184 -127
  36. data/crates/itsi_server/src/server/mod.rs +7 -1
  37. data/crates/itsi_server/src/server/process_worker.rs +196 -0
  38. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  39. data/crates/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  40. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  41. data/crates/itsi_server/src/server/signal.rs +70 -0
  42. data/crates/itsi_server/src/server/thread_worker.rs +368 -0
  43. data/crates/itsi_server/src/server/tls.rs +42 -28
  44. data/crates/itsi_tracing/Cargo.toml +4 -0
  45. data/crates/itsi_tracing/src/lib.rs +36 -6
  46. data/gems/scheduler/Cargo.lock +219 -23
  47. data/gems/scheduler/Rakefile +7 -1
  48. data/gems/scheduler/ext/itsi_error/Cargo.toml +2 -0
  49. data/gems/scheduler/ext/itsi_error/src/from.rs +70 -0
  50. data/gems/scheduler/ext/itsi_error/src/lib.rs +10 -37
  51. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +15 -0
  52. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +31 -0
  53. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +2 -0
  54. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  55. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +90 -10
  56. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +9 -1
  57. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +1 -1
  58. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  59. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  60. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  61. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  62. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +31 -10
  63. data/gems/scheduler/ext/itsi_server/Cargo.toml +41 -0
  64. data/gems/scheduler/ext/itsi_server/extconf.rb +6 -0
  65. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  66. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  67. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  68. data/gems/scheduler/ext/itsi_server/src/lib.rs +103 -0
  69. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +277 -0
  70. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +1 -0
  71. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +347 -0
  72. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +1 -0
  73. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +168 -0
  74. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  75. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +104 -0
  76. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +13 -0
  77. data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +5 -0
  78. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +244 -0
  79. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
  80. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +275 -0
  81. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +11 -0
  82. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +196 -0
  83. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  84. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  85. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  86. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +70 -0
  87. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +368 -0
  88. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +152 -0
  89. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +4 -0
  90. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +36 -6
  91. data/gems/scheduler/itsi-scheduler.gemspec +2 -3
  92. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  93. data/gems/scheduler/lib/itsi/scheduler.rb +137 -1
  94. data/gems/scheduler/test/helpers/test_helper.rb +24 -0
  95. data/gems/scheduler/test/test_active_record.rb +158 -0
  96. data/gems/scheduler/test/test_address_resolve.rb +23 -0
  97. data/gems/scheduler/test/test_block_unblock.rb +229 -0
  98. data/gems/scheduler/test/test_file_io.rb +193 -0
  99. data/gems/scheduler/test/test_itsi_scheduler.rb +24 -1
  100. data/gems/scheduler/test/test_kernel_sleep.rb +91 -0
  101. data/gems/scheduler/test/test_nested_fibers.rb +286 -0
  102. data/gems/scheduler/test/test_network_io.rb +274 -0
  103. data/gems/scheduler/test/test_process_wait.rb +26 -0
  104. data/gems/server/exe/itsi +88 -28
  105. data/gems/server/ext/itsi_error/Cargo.toml +2 -0
  106. data/gems/server/ext/itsi_error/src/from.rs +70 -0
  107. data/gems/server/ext/itsi_error/src/lib.rs +10 -37
  108. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +15 -0
  109. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +31 -0
  110. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +2 -0
  111. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
  112. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +90 -10
  113. data/gems/server/ext/itsi_scheduler/Cargo.toml +24 -0
  114. data/gems/server/ext/itsi_scheduler/extconf.rb +6 -0
  115. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
  116. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
  117. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
  118. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
  119. data/gems/server/ext/itsi_scheduler/src/lib.rs +38 -0
  120. data/gems/server/ext/itsi_server/Cargo.toml +14 -2
  121. data/gems/server/ext/itsi_server/extconf.rb +1 -1
  122. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
  123. data/gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
  124. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +2 -0
  125. data/gems/server/ext/itsi_server/src/lib.rs +58 -7
  126. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +238 -104
  127. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +347 -0
  128. data/gems/server/ext/itsi_server/src/response/mod.rs +1 -0
  129. data/gems/server/ext/itsi_server/src/server/bind.rs +50 -20
  130. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +37 -0
  131. data/gems/server/ext/itsi_server/src/server/io_stream.rs +104 -0
  132. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
  133. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
  134. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +196 -134
  135. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
  136. data/gems/server/ext/itsi_server/src/server/listener.rs +184 -127
  137. data/gems/server/ext/itsi_server/src/server/mod.rs +7 -1
  138. data/gems/server/ext/itsi_server/src/server/process_worker.rs +196 -0
  139. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
  140. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
  141. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
  142. data/gems/server/ext/itsi_server/src/server/signal.rs +70 -0
  143. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +368 -0
  144. data/gems/server/ext/itsi_server/src/server/tls.rs +42 -28
  145. data/gems/server/ext/itsi_tracing/Cargo.toml +4 -0
  146. data/gems/server/ext/itsi_tracing/src/lib.rs +36 -6
  147. data/gems/server/itsi-server.gemspec +4 -5
  148. data/gems/server/lib/itsi/request.rb +30 -14
  149. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +25 -0
  150. data/gems/server/lib/itsi/server/scheduler_mode.rb +6 -0
  151. data/gems/server/lib/itsi/server/version.rb +1 -1
  152. data/gems/server/lib/itsi/server.rb +82 -2
  153. data/gems/server/lib/itsi/signals.rb +23 -0
  154. data/gems/server/lib/itsi/stream_io.rb +38 -0
  155. data/gems/server/test/test_helper.rb +2 -0
  156. data/gems/server/test/test_itsi_server.rb +1 -1
  157. data/lib/itsi/version.rb +1 -1
  158. data/tasks.txt +18 -0
  159. metadata +102 -12
  160. data/crates/itsi_server/src/server/transfer_protocol.rs +0 -23
  161. data/crates/itsi_server/src/stream_writer/mod.rs +0 -21
  162. data/gems/scheduler/test/test_helper.rb +0 -6
  163. data/gems/server/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
  164. data/gems/server/ext/itsi_server/src/stream_writer/mod.rs +0 -21
@@ -0,0 +1,244 @@
1
+ use super::{
2
+ bind::Bind,
3
+ listener::Listener,
4
+ serve_strategy::{cluster_mode::ClusterMode, single_mode::SingleMode},
5
+ signal::{clear_signal_handlers, reset_signal_handlers, SIGNAL_HANDLER_CHANNEL},
6
+ };
7
+ use crate::{request::itsi_request::ItsiRequest, server::serve_strategy::ServeStrategy};
8
+ use derive_more::Debug;
9
+ use itsi_rb_helpers::call_without_gvl;
10
+ use itsi_tracing::error;
11
+ use magnus::{
12
+ block::Proc,
13
+ error::Result,
14
+ scan_args::{get_kwargs, scan_args, Args, KwArgs},
15
+ value::{InnerValue, Opaque, ReprValue},
16
+ RHash, Ruby, Symbol, Value,
17
+ };
18
+ use parking_lot::Mutex;
19
+ use std::{cmp::max, ops::Deref, sync::Arc};
20
+ use tracing::{info, instrument};
21
+
22
+ static DEFAULT_BIND: &str = "localhost:3000";
23
+
24
+ #[magnus::wrap(class = "Itsi::Server", free_immediately, size)]
25
+ #[derive(Clone)]
26
+ pub struct Server {
27
+ pub config: Arc<ServerConfig>,
28
+ }
29
+
30
+ impl Deref for Server {
31
+ type Target = ServerConfig;
32
+
33
+ fn deref(&self) -> &Self::Target {
34
+ &self.config
35
+ }
36
+ }
37
+ type AfterFork = Mutex<Arc<Option<Box<dyn Fn() + Send + Sync>>>>;
38
+
39
+ #[derive(Debug)]
40
+ pub struct ServerConfig {
41
+ #[debug(skip)]
42
+ pub app: Opaque<Value>,
43
+ #[allow(unused)]
44
+ pub workers: u8,
45
+ #[allow(unused)]
46
+ pub threads: u8,
47
+ #[allow(unused)]
48
+ pub shutdown_timeout: f64,
49
+ pub script_name: String,
50
+ pub(crate) binds: Mutex<Vec<Bind>>,
51
+ #[debug(skip)]
52
+ pub before_fork: Mutex<Option<Box<dyn FnOnce() + Send + Sync>>>,
53
+ #[debug(skip)]
54
+ pub after_fork: AfterFork,
55
+ pub scheduler_class: Option<String>,
56
+ pub stream_body: Option<bool>,
57
+ pub worker_memory_limit: Option<u64>,
58
+ }
59
+
60
+ #[derive(Debug)]
61
+ pub enum RequestJob {
62
+ ProcessRequest(ItsiRequest),
63
+ Shutdown,
64
+ }
65
+
66
+ impl Server {
67
+ #[instrument(
68
+ name = "Itsi",
69
+ parent=None,
70
+ skip(args),
71
+ fields(workers = 1, threads = 1, shutdown_timeout = 5)
72
+ )]
73
+ pub fn new(args: &[Value]) -> Result<Self> {
74
+ let scan_args: Args<(), (), (), (), RHash, ()> = scan_args(args)?;
75
+
76
+ type ArgSet1 = (
77
+ Option<u8>,
78
+ Option<u8>,
79
+ Option<f64>,
80
+ Option<String>,
81
+ Option<Vec<String>>,
82
+ Option<Proc>,
83
+ Option<Proc>,
84
+ Option<String>,
85
+ Option<bool>,
86
+ );
87
+
88
+ type ArgSet2 = (Option<u64>,);
89
+
90
+ let args1: KwArgs<(Value,), ArgSet1, ()> = get_kwargs(
91
+ scan_args
92
+ .keywords
93
+ .funcall::<_, _, RHash>(
94
+ "slice",
95
+ (
96
+ Symbol::new("app"),
97
+ Symbol::new("workers"),
98
+ Symbol::new("threads"),
99
+ Symbol::new("shutdown_timeout"),
100
+ Symbol::new("script_name"),
101
+ Symbol::new("binds"),
102
+ Symbol::new("before_fork"),
103
+ Symbol::new("after_fork"),
104
+ Symbol::new("scheduler_class"),
105
+ Symbol::new("stream_body"),
106
+ ),
107
+ )
108
+ .unwrap(),
109
+ &["app"],
110
+ &[
111
+ "workers",
112
+ "threads",
113
+ "shutdown_timeout",
114
+ "script_name",
115
+ "binds",
116
+ "before_fork",
117
+ "after_fork",
118
+ "scheduler_class",
119
+ "stream_body",
120
+ ],
121
+ )?;
122
+
123
+ let args2: KwArgs<(), ArgSet2, ()> = get_kwargs(
124
+ scan_args
125
+ .keywords
126
+ .funcall::<_, _, RHash>("slice", (Symbol::new("worker_memory_limit"),))
127
+ .unwrap(),
128
+ &[],
129
+ &["worker_memory_limit"],
130
+ )?;
131
+
132
+ let config = ServerConfig {
133
+ app: Opaque::from(args1.required.0),
134
+ workers: max(args1.optional.0.unwrap_or(1), 1),
135
+ threads: max(args1.optional.1.unwrap_or(1), 1),
136
+ shutdown_timeout: args1.optional.2.unwrap_or(5.0),
137
+ script_name: args1.optional.3.unwrap_or("".to_string()),
138
+ binds: Mutex::new(
139
+ args1
140
+ .optional
141
+ .4
142
+ .unwrap_or_else(|| vec![DEFAULT_BIND.to_string()])
143
+ .into_iter()
144
+ .map(|s| s.parse())
145
+ .collect::<itsi_error::Result<Vec<Bind>>>()?,
146
+ ),
147
+ before_fork: Mutex::new(args1.optional.5.map(|p| {
148
+ let opaque_proc = Opaque::from(p);
149
+ Box::new(move || {
150
+ opaque_proc
151
+ .get_inner_with(&Ruby::get().unwrap())
152
+ .call::<_, Value>(())
153
+ .unwrap();
154
+ }) as Box<dyn FnOnce() + Send + Sync>
155
+ })),
156
+ after_fork: Mutex::new(Arc::new(args1.optional.6.map(|p| {
157
+ let opaque_proc = Opaque::from(p);
158
+ Box::new(move || {
159
+ opaque_proc
160
+ .get_inner_with(&Ruby::get().unwrap())
161
+ .call::<_, Value>(())
162
+ .unwrap();
163
+ }) as Box<dyn Fn() + Send + Sync>
164
+ }))),
165
+ scheduler_class: args1.optional.7.clone(),
166
+ stream_body: args1.optional.8,
167
+ worker_memory_limit: args2.optional.0,
168
+ };
169
+
170
+ if let Some(scheduler_class) = args1.optional.7 {
171
+ info!(scheduler_class, fiber_scheduler = true);
172
+ } else {
173
+ info!(fiber_scheduler = false);
174
+ }
175
+
176
+ Ok(Server {
177
+ config: Arc::new(config),
178
+ })
179
+ }
180
+
181
+ #[instrument(name = "Bind", skip_all, fields(binds=format!("{:?}", self.config.binds.lock())))]
182
+ pub(crate) fn listeners(&self) -> Result<Arc<Vec<Arc<Listener>>>> {
183
+ let listeners = self
184
+ .config
185
+ .binds
186
+ .lock()
187
+ .iter()
188
+ .cloned()
189
+ .map(Listener::try_from)
190
+ .collect::<std::result::Result<Vec<Listener>, _>>()?
191
+ .into_iter()
192
+ .map(Arc::new)
193
+ .collect::<Vec<_>>();
194
+ info!("Bound {:?} listeners", listeners.len());
195
+ Ok(Arc::new(listeners))
196
+ }
197
+
198
+ pub(crate) fn build_strategy(
199
+ self,
200
+ listeners: Arc<Vec<Arc<Listener>>>,
201
+ ) -> Result<ServeStrategy> {
202
+ let server = Arc::new(self);
203
+
204
+ let strategy = if server.config.workers == 1 {
205
+ ServeStrategy::Single(Arc::new(SingleMode::new(
206
+ server,
207
+ listeners,
208
+ SIGNAL_HANDLER_CHANNEL.0.clone(),
209
+ )?))
210
+ } else {
211
+ ServeStrategy::Cluster(Arc::new(ClusterMode::new(
212
+ server,
213
+ listeners,
214
+ SIGNAL_HANDLER_CHANNEL.0.clone(),
215
+ )))
216
+ };
217
+ Ok(strategy)
218
+ }
219
+
220
+ pub fn start(&self) -> Result<()> {
221
+ reset_signal_handlers();
222
+ let rself = self.clone();
223
+ let listeners = self.listeners()?;
224
+ let listeners_clone = listeners.clone();
225
+ call_without_gvl(move || -> Result<()> {
226
+ let strategy = rself.build_strategy(listeners_clone)?;
227
+ if let Err(e) = strategy.run() {
228
+ error!("Error running server: {}", e);
229
+ strategy.stop()?;
230
+ }
231
+ drop(strategy);
232
+ Ok(())
233
+ })?;
234
+ if let Ok(listeners) = Arc::try_unwrap(listeners) {
235
+ listeners.into_iter().for_each(|listener| {
236
+ if let Ok(listener) = Arc::try_unwrap(listener) {
237
+ listener.unbind()
238
+ };
239
+ });
240
+ }
241
+ clear_signal_handlers();
242
+ Ok(())
243
+ }
244
+ }
@@ -0,0 +1,9 @@
1
+ #[derive(Debug, Clone)]
2
+ pub enum LifecycleEvent {
3
+ Start,
4
+ Shutdown,
5
+ Restart,
6
+ IncreaseWorkers,
7
+ DecreaseWorkers,
8
+ ForceShutdown,
9
+ }
@@ -0,0 +1,275 @@
1
+ use super::bind::{Bind, BindAddress};
2
+ use super::bind_protocol::BindProtocol;
3
+ use super::io_stream::IoStream;
4
+ use itsi_error::Result;
5
+ use itsi_tracing::info;
6
+ use socket2::{Domain, Protocol, Socket, Type};
7
+ use std::net::{IpAddr, SocketAddr, TcpListener};
8
+ use std::sync::Arc;
9
+ use std::{os::unix::net::UnixListener, path::PathBuf};
10
+ use tokio::net::TcpListener as TokioTcpListener;
11
+ use tokio::net::UnixListener as TokioUnixListener;
12
+ use tokio::net::{unix, TcpStream, UnixStream};
13
+ use tokio_rustls::TlsAcceptor;
14
+
15
+ pub(crate) enum Listener {
16
+ Tcp(TcpListener),
17
+ TcpTls((TcpListener, TlsAcceptor)),
18
+ Unix(UnixListener),
19
+ UnixTls((UnixListener, TlsAcceptor)),
20
+ }
21
+
22
+ pub(crate) enum TokioListener {
23
+ Tcp {
24
+ listener: TokioTcpListener,
25
+ host: String,
26
+ port: u16,
27
+ },
28
+ TcpTls {
29
+ listener: TokioTcpListener,
30
+ acceptor: TlsAcceptor,
31
+ host: String,
32
+ port: u16,
33
+ },
34
+ Unix {
35
+ listener: TokioUnixListener,
36
+ },
37
+ UnixTls {
38
+ listener: TokioUnixListener,
39
+ acceptor: TlsAcceptor,
40
+ },
41
+ }
42
+
43
+ impl TokioListener {
44
+ pub fn unbind(self) {
45
+ match self {
46
+ TokioListener::Tcp { listener, .. } => drop(listener.into_std().unwrap()),
47
+ TokioListener::TcpTls { listener, .. } => drop(listener.into_std().unwrap()),
48
+ TokioListener::Unix { listener } => drop(listener.into_std().unwrap()),
49
+ TokioListener::UnixTls { listener, .. } => drop(listener.into_std().unwrap()),
50
+ };
51
+ }
52
+ pub(crate) async fn accept(&self) -> Result<IoStream> {
53
+ match self {
54
+ TokioListener::Tcp { listener, .. } => TokioListener::accept_tcp(listener).await,
55
+ TokioListener::TcpTls {
56
+ listener, acceptor, ..
57
+ } => TokioListener::accept_tls(listener, acceptor).await,
58
+ TokioListener::Unix { listener, .. } => TokioListener::accept_unix(listener).await,
59
+ TokioListener::UnixTls {
60
+ listener, acceptor, ..
61
+ } => TokioListener::accept_unix_tls(listener, acceptor).await,
62
+ }
63
+ }
64
+
65
+ async fn accept_tcp(listener: &TokioTcpListener) -> Result<IoStream> {
66
+ let tcp_stream = listener.accept().await?;
67
+ Self::to_tokio_io(Stream::TcpStream(tcp_stream), None).await
68
+ }
69
+
70
+ async fn accept_tls(listener: &TokioTcpListener, acceptor: &TlsAcceptor) -> Result<IoStream> {
71
+ let tcp_stream = listener.accept().await?;
72
+ Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(acceptor)).await
73
+ }
74
+
75
+ async fn accept_unix(listener: &TokioUnixListener) -> Result<IoStream> {
76
+ let unix_stream = listener.accept().await?;
77
+ Self::to_tokio_io(Stream::UnixStream(unix_stream), None).await
78
+ }
79
+
80
+ async fn accept_unix_tls(
81
+ listener: &TokioUnixListener,
82
+ acceptor: &TlsAcceptor,
83
+ ) -> Result<IoStream> {
84
+ let unix_stream = listener.accept().await?;
85
+ Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(acceptor)).await
86
+ }
87
+
88
+ async fn to_tokio_io(
89
+ input_stream: Stream,
90
+ tls_acceptor: Option<&TlsAcceptor>,
91
+ ) -> Result<IoStream> {
92
+ match tls_acceptor {
93
+ Some(acceptor) => match input_stream {
94
+ Stream::TcpStream((tcp_stream, socket_address)) => {
95
+ match acceptor.accept(tcp_stream).await {
96
+ Ok(tls_stream) => Ok(IoStream::TcpTls {
97
+ stream: tls_stream,
98
+ addr: SockAddr::Tcp(Arc::new(socket_address)),
99
+ }),
100
+ Err(err) => Err(err.into()),
101
+ }
102
+ }
103
+ Stream::UnixStream((unix_stream, socket_address)) => {
104
+ match acceptor.accept(unix_stream).await {
105
+ Ok(tls_stream) => Ok(IoStream::UnixTls {
106
+ stream: tls_stream,
107
+ addr: SockAddr::Unix(Arc::new(socket_address)),
108
+ }),
109
+ Err(err) => Err(err.into()),
110
+ }
111
+ }
112
+ },
113
+ None => match input_stream {
114
+ Stream::TcpStream((tcp_stream, socket_address)) => Ok(IoStream::Tcp {
115
+ stream: tcp_stream,
116
+ addr: SockAddr::Tcp(Arc::new(socket_address)),
117
+ }),
118
+ Stream::UnixStream((unix_stream, socket_address)) => Ok(IoStream::Unix {
119
+ stream: unix_stream,
120
+ addr: SockAddr::Unix(Arc::new(socket_address)),
121
+ }),
122
+ },
123
+ }
124
+ }
125
+
126
+ pub(crate) fn scheme(&self) -> String {
127
+ match self {
128
+ TokioListener::Tcp { .. } => "http".to_string(),
129
+ TokioListener::TcpTls { .. } => "https".to_string(),
130
+ TokioListener::Unix { .. } => "http".to_string(),
131
+ TokioListener::UnixTls { .. } => "https".to_string(),
132
+ }
133
+ }
134
+
135
+ pub(crate) fn port(&self) -> u16 {
136
+ match self {
137
+ TokioListener::Tcp { port, .. } => *port,
138
+ TokioListener::TcpTls { port, .. } => *port,
139
+ TokioListener::Unix { .. } => 0,
140
+ TokioListener::UnixTls { .. } => 0,
141
+ }
142
+ }
143
+
144
+ pub(crate) fn host(&self) -> String {
145
+ match self {
146
+ TokioListener::Tcp { host, .. } => host.to_string(),
147
+ TokioListener::TcpTls { host, .. } => host.to_string(),
148
+ TokioListener::Unix { .. } => "unix".to_string(),
149
+ TokioListener::UnixTls { .. } => "unix".to_string(),
150
+ }
151
+ }
152
+ }
153
+
154
+ enum Stream {
155
+ TcpStream((TcpStream, SocketAddr)),
156
+ UnixStream((UnixStream, unix::SocketAddr)),
157
+ }
158
+
159
+ #[derive(Clone, Debug)]
160
+ pub enum SockAddr {
161
+ Tcp(Arc<SocketAddr>),
162
+ Unix(Arc<unix::SocketAddr>),
163
+ }
164
+ impl std::fmt::Display for SockAddr {
165
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166
+ match self {
167
+ SockAddr::Tcp(socket_addr) => write!(f, "{}", socket_addr.ip().to_canonical()),
168
+ SockAddr::Unix(socket_addr) => match socket_addr.as_pathname() {
169
+ Some(path) => write!(f, "{:?}", path),
170
+ None => write!(f, ""),
171
+ },
172
+ }
173
+ }
174
+ }
175
+
176
+ impl Listener {
177
+ pub fn unbind(self) {
178
+ match self {
179
+ Listener::Tcp(listener) => drop(listener),
180
+ Listener::TcpTls((listener, _)) => drop(listener),
181
+ Listener::Unix(listener) => drop(listener),
182
+ Listener::UnixTls((listener, _)) => drop(listener),
183
+ };
184
+ }
185
+ pub fn to_tokio_listener(&self) -> TokioListener {
186
+ match self {
187
+ Listener::Tcp(listener) => TokioListener::Tcp {
188
+ listener: TokioTcpListener::from_std(TcpListener::try_clone(listener).unwrap())
189
+ .unwrap(),
190
+ host: listener
191
+ .local_addr()
192
+ .unwrap()
193
+ .ip()
194
+ .to_canonical()
195
+ .to_string(),
196
+ port: listener.local_addr().unwrap().port(),
197
+ },
198
+ Listener::TcpTls((listener, acceptor)) => TokioListener::TcpTls {
199
+ listener: TokioTcpListener::from_std(TcpListener::try_clone(listener).unwrap())
200
+ .unwrap(),
201
+ acceptor: acceptor.clone(),
202
+ host: listener
203
+ .local_addr()
204
+ .unwrap()
205
+ .ip()
206
+ .to_canonical()
207
+ .to_string(),
208
+ port: listener.local_addr().unwrap().port(),
209
+ },
210
+ Listener::Unix(listener) => TokioListener::Unix {
211
+ listener: TokioUnixListener::from_std(UnixListener::try_clone(listener).unwrap())
212
+ .unwrap(),
213
+ },
214
+ Listener::UnixTls((listener, acceptor)) => TokioListener::UnixTls {
215
+ listener: TokioUnixListener::from_std(UnixListener::try_clone(listener).unwrap())
216
+ .unwrap(),
217
+ acceptor: acceptor.clone(),
218
+ },
219
+ }
220
+ }
221
+ }
222
+
223
+ impl TryFrom<Bind> for Listener {
224
+ type Error = itsi_error::ItsiError;
225
+
226
+ fn try_from(bind: Bind) -> std::result::Result<Self, Self::Error> {
227
+ let bound = match bind.address {
228
+ BindAddress::Ip(addr) => match bind.protocol {
229
+ BindProtocol::Http => Listener::Tcp(connect_tcp_socket(addr, bind.port.unwrap())?),
230
+ BindProtocol::Https => {
231
+ let tcp_listener = connect_tcp_socket(addr, bind.port.unwrap())?;
232
+ let tls_acceptor = TlsAcceptor::from(Arc::new(bind.tls_config.unwrap()));
233
+ Listener::TcpTls((tcp_listener, tls_acceptor))
234
+ }
235
+ _ => unreachable!(),
236
+ },
237
+ BindAddress::UnixSocket(path) => match bind.tls_config {
238
+ Some(tls_config) => {
239
+ let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));
240
+ Listener::UnixTls((connect_unix_socket(&path)?, tls_acceptor))
241
+ }
242
+ None => Listener::Unix(connect_unix_socket(&path)?),
243
+ },
244
+ };
245
+ Ok(bound)
246
+ }
247
+ }
248
+
249
+ fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
250
+ let domain = match addr {
251
+ IpAddr::V4(_) => Domain::IPV4,
252
+ IpAddr::V6(_) => Domain::IPV6,
253
+ };
254
+ let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
255
+ let socket_address: SocketAddr = SocketAddr::new(addr, port);
256
+ socket.set_nonblocking(true).ok();
257
+ socket.set_nodelay(true).ok();
258
+ socket.set_recv_buffer_size(1_048_576).ok();
259
+ socket.bind(&socket_address.into())?;
260
+ socket.listen(1024)?;
261
+ Ok(socket.into())
262
+ }
263
+
264
+ fn connect_unix_socket(path: &PathBuf) -> Result<UnixListener> {
265
+ let _ = std::fs::remove_file(path);
266
+ let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
267
+ socket.set_nonblocking(true).ok();
268
+ let socket_address = socket2::SockAddr::unix(path)?;
269
+
270
+ info!("Binding to {:?}", path);
271
+ socket.bind(&socket_address)?;
272
+ socket.listen(1024)?;
273
+
274
+ Ok(socket.into())
275
+ }
@@ -0,0 +1,11 @@
1
+ pub mod bind;
2
+ pub mod bind_protocol;
3
+ pub mod io_stream;
4
+ pub mod itsi_server;
5
+ pub mod lifecycle_event;
6
+ pub mod listener;
7
+ pub mod process_worker;
8
+ pub mod serve_strategy;
9
+ pub mod signal;
10
+ pub mod thread_worker;
11
+ pub mod tls;