itsi 0.1.0

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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +1541 -0
  3. data/Cargo.toml +13 -0
  4. data/README.md +82 -0
  5. data/Rakefile +87 -0
  6. data/crates/itsi_error/Cargo.lock +368 -0
  7. data/crates/itsi_error/Cargo.toml +9 -0
  8. data/crates/itsi_error/src/lib.rs +49 -0
  9. data/crates/itsi_rb_helpers/Cargo.lock +355 -0
  10. data/crates/itsi_rb_helpers/Cargo.toml +8 -0
  11. data/crates/itsi_rb_helpers/src/lib.rs +98 -0
  12. data/crates/itsi_scheduler/Cargo.toml +16 -0
  13. data/crates/itsi_scheduler/extconf.rb +6 -0
  14. data/crates/itsi_scheduler/src/lib.rs +17 -0
  15. data/crates/itsi_server/Cargo.toml +29 -0
  16. data/crates/itsi_server/extconf.rb +6 -0
  17. data/crates/itsi_server/src/lib.rs +52 -0
  18. data/crates/itsi_server/src/request/itsi_request.rs +143 -0
  19. data/crates/itsi_server/src/request/mod.rs +1 -0
  20. data/crates/itsi_server/src/server/bind.rs +138 -0
  21. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.crt +32 -0
  22. data/crates/itsi_server/src/server/itsi_ca/itsi_ca.key +52 -0
  23. data/crates/itsi_server/src/server/itsi_server.rs +182 -0
  24. data/crates/itsi_server/src/server/listener.rs +218 -0
  25. data/crates/itsi_server/src/server/mod.rs +5 -0
  26. data/crates/itsi_server/src/server/tls.rs +138 -0
  27. data/crates/itsi_server/src/server/transfer_protocol.rs +23 -0
  28. data/crates/itsi_server/src/stream_writer/mod.rs +21 -0
  29. data/crates/itsi_tracing/Cargo.lock +274 -0
  30. data/crates/itsi_tracing/Cargo.toml +12 -0
  31. data/crates/itsi_tracing/src/lib.rs +11 -0
  32. data/gems/scheduler/.gitignore +14 -0
  33. data/gems/scheduler/.rubocop.yml +8 -0
  34. data/gems/scheduler/CHANGELOG.md +5 -0
  35. data/gems/scheduler/CODE_OF_CONDUCT.md +132 -0
  36. data/gems/scheduler/Cargo.lock +745 -0
  37. data/gems/scheduler/Cargo.toml +3 -0
  38. data/gems/scheduler/LICENSE.txt +21 -0
  39. data/gems/scheduler/README.md +43 -0
  40. data/gems/scheduler/Rakefile +22 -0
  41. data/gems/scheduler/bin/console +11 -0
  42. data/gems/scheduler/bin/setup +8 -0
  43. data/gems/scheduler/ext/itsi_error/Cargo.lock +368 -0
  44. data/gems/scheduler/ext/itsi_error/Cargo.toml +9 -0
  45. data/gems/scheduler/ext/itsi_error/src/lib.rs +49 -0
  46. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +355 -0
  47. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +8 -0
  48. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +98 -0
  49. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +16 -0
  50. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +6 -0
  51. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +17 -0
  52. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +274 -0
  53. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +12 -0
  54. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +11 -0
  55. data/gems/scheduler/itsi-scheduler.gemspec +43 -0
  56. data/gems/scheduler/lib/itsi/scheduler/version.rb +7 -0
  57. data/gems/scheduler/lib/itsi/scheduler.rb +11 -0
  58. data/gems/scheduler/sig/itsi_scheduler.rbs +4 -0
  59. data/gems/scheduler/test/test_helper.rb +6 -0
  60. data/gems/scheduler/test/test_itsi_scheduler.rb +9 -0
  61. data/gems/server/.gitignore +14 -0
  62. data/gems/server/.rubocop.yml +8 -0
  63. data/gems/server/CHANGELOG.md +5 -0
  64. data/gems/server/CODE_OF_CONDUCT.md +132 -0
  65. data/gems/server/LICENSE.txt +21 -0
  66. data/gems/server/README.md +43 -0
  67. data/gems/server/Rakefile +22 -0
  68. data/gems/server/bin/console +11 -0
  69. data/gems/server/bin/setup +8 -0
  70. data/gems/server/exe/itsi +84 -0
  71. data/gems/server/ext/itsi_error/Cargo.lock +368 -0
  72. data/gems/server/ext/itsi_error/Cargo.toml +9 -0
  73. data/gems/server/ext/itsi_error/src/lib.rs +49 -0
  74. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +355 -0
  75. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +8 -0
  76. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +98 -0
  77. data/gems/server/ext/itsi_server/Cargo.toml +29 -0
  78. data/gems/server/ext/itsi_server/extconf.rb +6 -0
  79. data/gems/server/ext/itsi_server/src/lib.rs +52 -0
  80. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +143 -0
  81. data/gems/server/ext/itsi_server/src/request/mod.rs +1 -0
  82. data/gems/server/ext/itsi_server/src/server/bind.rs +138 -0
  83. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +32 -0
  84. data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +52 -0
  85. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +182 -0
  86. data/gems/server/ext/itsi_server/src/server/listener.rs +218 -0
  87. data/gems/server/ext/itsi_server/src/server/mod.rs +5 -0
  88. data/gems/server/ext/itsi_server/src/server/tls.rs +138 -0
  89. data/gems/server/ext/itsi_server/src/server/transfer_protocol.rs +23 -0
  90. data/gems/server/ext/itsi_server/src/stream_writer/mod.rs +21 -0
  91. data/gems/server/ext/itsi_tracing/Cargo.lock +274 -0
  92. data/gems/server/ext/itsi_tracing/Cargo.toml +12 -0
  93. data/gems/server/ext/itsi_tracing/src/lib.rs +11 -0
  94. data/gems/server/itsi-server.gemspec +45 -0
  95. data/gems/server/lib/itsi/request.rb +39 -0
  96. data/gems/server/lib/itsi/server/version.rb +7 -0
  97. data/gems/server/lib/itsi/server.rb +21 -0
  98. data/gems/server/sig/itsi_server.rbs +4 -0
  99. data/gems/server/test/test_helper.rb +5 -0
  100. data/gems/server/test/test_itsi_server.rb +9 -0
  101. data/lib/itsi/version.rb +3 -0
  102. data/lib/itsi.rb +6 -0
  103. metadata +172 -0
@@ -0,0 +1,138 @@
1
+ use base64::{engine::general_purpose, Engine as _};
2
+ use itsi_error::Result;
3
+ use itsi_tracing::{info, warn};
4
+ use rcgen::{CertificateParams, DnType, KeyPair, SanType};
5
+ use rustls_pemfile::{certs, pkcs8_private_keys};
6
+ use std::{collections::HashMap, fs, io::BufReader};
7
+ use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
8
+
9
+ const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
10
+ const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
11
+
12
+ // Generates a TLS configuration based on either :
13
+ // * Input "cert" and "key" options (either paths or Base64-encoded strings) or
14
+ // * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
15
+ // If a non-local host or optional domain parameter is provided,
16
+ // an automated certificate will attempt to be fetched using let's encrypt.
17
+ pub fn configure_tls(host: &str, query_params: &HashMap<String, String>) -> Result<ServerConfig> {
18
+ let (certs, key) = if let (Some(cert_path), Some(key_path)) =
19
+ (query_params.get("cert"), query_params.get("key"))
20
+ {
21
+ // Load from file or Base64
22
+ let certs = load_certs(cert_path);
23
+ let key = load_private_key(key_path);
24
+ (certs, key)
25
+ } else if query_params
26
+ .get("cert")
27
+ .map(|v| v == "auto")
28
+ .unwrap_or(false)
29
+ {
30
+ let domain_param = query_params.get("domain");
31
+ let host_string = host.to_string();
32
+ let domain = domain_param.or_else(|| {
33
+ if host_string != "localhost" {
34
+ Some(&host_string)
35
+ } else {
36
+ None
37
+ }
38
+ });
39
+
40
+ if let Some(domain) = domain {
41
+ retrieve_acme_cert(domain)?
42
+ } else {
43
+ generate_ca_signed_cert(host)?
44
+ }
45
+ } else {
46
+ generate_ca_signed_cert(host)?
47
+ };
48
+
49
+ let mut config = ServerConfig::builder()
50
+ .with_safe_defaults()
51
+ .with_no_client_auth()
52
+ .with_single_cert(certs, key)
53
+ .expect("Failed to build TLS config");
54
+
55
+ config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
56
+ Ok(config)
57
+ }
58
+
59
+ pub fn load_certs(path: &str) -> Vec<Certificate> {
60
+ let data = if let Some(stripped) = path.strip_prefix("base64:") {
61
+ general_purpose::STANDARD
62
+ .decode(stripped)
63
+ .expect("Invalid base64 certificate")
64
+ } else {
65
+ fs::read(path).expect("Failed to read certificate file")
66
+ };
67
+
68
+ if data.starts_with(b"-----BEGIN ") {
69
+ let mut reader = BufReader::new(&data[..]);
70
+ let certs_der: Vec<Vec<u8>> = certs(&mut reader)
71
+ .map(|r| {
72
+ r.map(|der| der.as_ref().to_vec())
73
+ .map_err(itsi_error::ItsiError::from)
74
+ })
75
+ .collect::<Result<_>>()
76
+ .expect("Failed to parse certificate file");
77
+ certs_der.into_iter().map(Certificate).collect()
78
+ } else {
79
+ vec![Certificate(data)]
80
+ }
81
+ }
82
+
83
+ /// Loads a private key from a file or Base64.
84
+ pub fn load_private_key(path: &str) -> PrivateKey {
85
+ let key_data = if let Some(stripped) = path.strip_prefix("base64:") {
86
+ general_purpose::STANDARD
87
+ .decode(stripped)
88
+ .expect("Invalid base64 private key")
89
+ } else {
90
+ fs::read(path).expect("Failed to read private key file")
91
+ };
92
+
93
+ if key_data.starts_with(b"-----BEGIN ") {
94
+ let mut reader = BufReader::new(&key_data[..]);
95
+ let keys: Vec<Vec<u8>> = pkcs8_private_keys(&mut reader)
96
+ .map(|r| {
97
+ r.map(|key| key.secret_pkcs8_der().to_vec())
98
+ .map_err(itsi_error::ItsiError::from)
99
+ })
100
+ .collect::<Result<_>>()
101
+ .expect("Failed to parse private key");
102
+ if !keys.is_empty() {
103
+ return PrivateKey(keys[0].clone());
104
+ }
105
+ }
106
+ PrivateKey(key_data)
107
+ }
108
+
109
+ pub fn generate_ca_signed_cert(domain: &str) -> Result<(Vec<Certificate>, PrivateKey)> {
110
+ info!("Generating New Itsi CA - Self signed Certificate. Use `itsi ca export` to export the CA certificate for import into your local trust store.");
111
+
112
+ let ca_kp = KeyPair::from_pem(ITS_CA_KEY).unwrap();
113
+ let params = CertificateParams::from_ca_cert_pem(ITS_CA_CERT).unwrap();
114
+
115
+ let ca_cert = params.self_signed(&ca_kp).unwrap();
116
+ let ee_key = KeyPair::generate().unwrap();
117
+ let mut ee_params = CertificateParams::default();
118
+
119
+ // Set the domain in the subject alternative names (SAN)
120
+ ee_params.subject_alt_names = vec![SanType::DnsName(domain.try_into()?)];
121
+ // Optionally, set the Common Name (CN) in the distinguished name:
122
+ ee_params
123
+ .distinguished_name
124
+ .push(DnType::CommonName, domain);
125
+
126
+ ee_params.use_authority_key_identifier_extension = true;
127
+
128
+ let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ee_key).unwrap();
129
+ let ee_cert_der = ee_cert.der().to_vec();
130
+ let ee_cert = Certificate(ee_cert_der);
131
+ Ok((vec![ee_cert], PrivateKey(ee_key.serialize_der())))
132
+ }
133
+
134
+ /// Retrieves an ACME certificate for a given domain.
135
+ pub fn retrieve_acme_cert(domain: &str) -> Result<(Vec<Certificate>, PrivateKey)> {
136
+ warn!("Retrieving ACME cert for {}", domain);
137
+ generate_ca_signed_cert(domain)
138
+ }
@@ -0,0 +1,23 @@
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
+ }
@@ -0,0 +1,21 @@
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
+ }
@@ -0,0 +1,274 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "aho-corasick"
7
+ version = "1.1.3"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
10
+ dependencies = [
11
+ "memchr",
12
+ ]
13
+
14
+ [[package]]
15
+ name = "cfg-if"
16
+ version = "1.0.0"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
19
+
20
+ [[package]]
21
+ name = "itsi_tracing"
22
+ version = "0.1.0"
23
+ dependencies = [
24
+ "tracing",
25
+ "tracing-subscriber",
26
+ ]
27
+
28
+ [[package]]
29
+ name = "lazy_static"
30
+ version = "1.5.0"
31
+ source = "registry+https://github.com/rust-lang/crates.io-index"
32
+ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
33
+
34
+ [[package]]
35
+ name = "log"
36
+ version = "0.4.26"
37
+ source = "registry+https://github.com/rust-lang/crates.io-index"
38
+ checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
39
+
40
+ [[package]]
41
+ name = "matchers"
42
+ version = "0.1.0"
43
+ source = "registry+https://github.com/rust-lang/crates.io-index"
44
+ checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
45
+ dependencies = [
46
+ "regex-automata 0.1.10",
47
+ ]
48
+
49
+ [[package]]
50
+ name = "memchr"
51
+ version = "2.7.4"
52
+ source = "registry+https://github.com/rust-lang/crates.io-index"
53
+ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
54
+
55
+ [[package]]
56
+ name = "nu-ansi-term"
57
+ version = "0.46.0"
58
+ source = "registry+https://github.com/rust-lang/crates.io-index"
59
+ checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
60
+ dependencies = [
61
+ "overload",
62
+ "winapi",
63
+ ]
64
+
65
+ [[package]]
66
+ name = "once_cell"
67
+ version = "1.20.3"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
70
+
71
+ [[package]]
72
+ name = "overload"
73
+ version = "0.1.1"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
76
+
77
+ [[package]]
78
+ name = "pin-project-lite"
79
+ version = "0.2.16"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
82
+
83
+ [[package]]
84
+ name = "proc-macro2"
85
+ version = "1.0.93"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
88
+ dependencies = [
89
+ "unicode-ident",
90
+ ]
91
+
92
+ [[package]]
93
+ name = "quote"
94
+ version = "1.0.38"
95
+ source = "registry+https://github.com/rust-lang/crates.io-index"
96
+ checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
97
+ dependencies = [
98
+ "proc-macro2",
99
+ ]
100
+
101
+ [[package]]
102
+ name = "regex"
103
+ version = "1.11.1"
104
+ source = "registry+https://github.com/rust-lang/crates.io-index"
105
+ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
106
+ dependencies = [
107
+ "aho-corasick",
108
+ "memchr",
109
+ "regex-automata 0.4.9",
110
+ "regex-syntax 0.8.5",
111
+ ]
112
+
113
+ [[package]]
114
+ name = "regex-automata"
115
+ version = "0.1.10"
116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
117
+ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
118
+ dependencies = [
119
+ "regex-syntax 0.6.29",
120
+ ]
121
+
122
+ [[package]]
123
+ name = "regex-automata"
124
+ version = "0.4.9"
125
+ source = "registry+https://github.com/rust-lang/crates.io-index"
126
+ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
127
+ dependencies = [
128
+ "aho-corasick",
129
+ "memchr",
130
+ "regex-syntax 0.8.5",
131
+ ]
132
+
133
+ [[package]]
134
+ name = "regex-syntax"
135
+ version = "0.6.29"
136
+ source = "registry+https://github.com/rust-lang/crates.io-index"
137
+ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
138
+
139
+ [[package]]
140
+ name = "regex-syntax"
141
+ version = "0.8.5"
142
+ source = "registry+https://github.com/rust-lang/crates.io-index"
143
+ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
144
+
145
+ [[package]]
146
+ name = "sharded-slab"
147
+ version = "0.1.7"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
150
+ dependencies = [
151
+ "lazy_static",
152
+ ]
153
+
154
+ [[package]]
155
+ name = "smallvec"
156
+ version = "1.14.0"
157
+ source = "registry+https://github.com/rust-lang/crates.io-index"
158
+ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
159
+
160
+ [[package]]
161
+ name = "syn"
162
+ version = "2.0.98"
163
+ source = "registry+https://github.com/rust-lang/crates.io-index"
164
+ checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
165
+ dependencies = [
166
+ "proc-macro2",
167
+ "quote",
168
+ "unicode-ident",
169
+ ]
170
+
171
+ [[package]]
172
+ name = "thread_local"
173
+ version = "1.1.8"
174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
175
+ checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
176
+ dependencies = [
177
+ "cfg-if",
178
+ "once_cell",
179
+ ]
180
+
181
+ [[package]]
182
+ name = "tracing"
183
+ version = "0.1.41"
184
+ source = "registry+https://github.com/rust-lang/crates.io-index"
185
+ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
186
+ dependencies = [
187
+ "pin-project-lite",
188
+ "tracing-attributes",
189
+ "tracing-core",
190
+ ]
191
+
192
+ [[package]]
193
+ name = "tracing-attributes"
194
+ version = "0.1.28"
195
+ source = "registry+https://github.com/rust-lang/crates.io-index"
196
+ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
197
+ dependencies = [
198
+ "proc-macro2",
199
+ "quote",
200
+ "syn",
201
+ ]
202
+
203
+ [[package]]
204
+ name = "tracing-core"
205
+ version = "0.1.33"
206
+ source = "registry+https://github.com/rust-lang/crates.io-index"
207
+ checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
208
+ dependencies = [
209
+ "once_cell",
210
+ "valuable",
211
+ ]
212
+
213
+ [[package]]
214
+ name = "tracing-log"
215
+ version = "0.2.0"
216
+ source = "registry+https://github.com/rust-lang/crates.io-index"
217
+ checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
218
+ dependencies = [
219
+ "log",
220
+ "once_cell",
221
+ "tracing-core",
222
+ ]
223
+
224
+ [[package]]
225
+ name = "tracing-subscriber"
226
+ version = "0.3.19"
227
+ source = "registry+https://github.com/rust-lang/crates.io-index"
228
+ checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
229
+ dependencies = [
230
+ "matchers",
231
+ "nu-ansi-term",
232
+ "once_cell",
233
+ "regex",
234
+ "sharded-slab",
235
+ "smallvec",
236
+ "thread_local",
237
+ "tracing",
238
+ "tracing-core",
239
+ "tracing-log",
240
+ ]
241
+
242
+ [[package]]
243
+ name = "unicode-ident"
244
+ version = "1.0.17"
245
+ source = "registry+https://github.com/rust-lang/crates.io-index"
246
+ checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
247
+
248
+ [[package]]
249
+ name = "valuable"
250
+ version = "0.1.1"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
253
+
254
+ [[package]]
255
+ name = "winapi"
256
+ version = "0.3.9"
257
+ source = "registry+https://github.com/rust-lang/crates.io-index"
258
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
259
+ dependencies = [
260
+ "winapi-i686-pc-windows-gnu",
261
+ "winapi-x86_64-pc-windows-gnu",
262
+ ]
263
+
264
+ [[package]]
265
+ name = "winapi-i686-pc-windows-gnu"
266
+ version = "0.4.0"
267
+ source = "registry+https://github.com/rust-lang/crates.io-index"
268
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
269
+
270
+ [[package]]
271
+ name = "winapi-x86_64-pc-windows-gnu"
272
+ version = "0.4.0"
273
+ source = "registry+https://github.com/rust-lang/crates.io-index"
274
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
@@ -0,0 +1,12 @@
1
+ [package]
2
+ name = "itsi_tracing"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+
6
+ [dependencies]
7
+ tracing = { version = "0.1.41", features = ["attributes"] }
8
+ tracing-subscriber = { version = "0.3.19", features = [
9
+ "env-filter",
10
+ "std",
11
+ "fmt",
12
+ ] }
@@ -0,0 +1,11 @@
1
+ pub use tracing::{debug, error, info, trace, warn};
2
+ use tracing_subscriber::{EnvFilter, fmt};
3
+
4
+ pub fn init() {
5
+ let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
6
+ let format = fmt::format().with_level(true).with_target(false).compact();
7
+ tracing_subscriber::fmt()
8
+ .with_env_filter(env_filter)
9
+ .event_format(format)
10
+ .init();
11
+ }
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/itsi/server/version"
4
+ require "debug"
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "itsi-server"
7
+ spec.version = Itsi::Server::VERSION
8
+ spec.authors = ["Wouter Coppieters"]
9
+ spec.email = ["wc@pico.net.nz"]
10
+
11
+ spec.summary = "Itsi Server - A light-weight Rack Server implementation for Ruby."
12
+ spec.description = "Itsi Server - A light-weight Rack Server implementation for Ruby"
13
+ spec.homepage = "https://itsi.fyi"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.1.0"
16
+ spec.required_rubygems_version = ">= 3.3.11"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/wouterken/itsi/server"
20
+ spec.metadata["changelog_uri"] = "https://github.com/wouterken/itsi/server/blob/main/CHANGELOG.md"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ gemspec = File.basename(__FILE__)
25
+ spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
26
+ ls.readlines("\x0", chomp: true).reject do |f|
27
+ (f == gemspec) ||
28
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
29
+ end
30
+ end
31
+
32
+ spec.bindir = "exe"
33
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ["lib"]
35
+ spec.extensions = ["ext/itsi_server/extconf.rb"]
36
+
37
+ # Uncomment to register a new dependency of your gem
38
+ # spec.add_dependency "example-gem", "~> 1.0"
39
+ spec.add_dependency "libclang", "~> 14.0"
40
+ spec.add_dependency "rb_sys", "~> 0.9.91"
41
+ spec.add_dependency "rack", "~> 2"
42
+
43
+ # For more information and examples about making a new gem, check out our
44
+ # guide at: https://bundler.io/guides/creating_gem.html
45
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Itsi
6
+ class Request
7
+ def to_env
8
+ {
9
+ "SERVER_SOFTWARE" => "Itsi",
10
+ "SCRIPT_NAME" => script_name,
11
+ "REQUEST_METHOD" => method,
12
+ "PATH_INFO" => path,
13
+ "REQUEST_PATH" => path,
14
+ "QUERY_STRING" => query_string,
15
+ "REMOTE_ADDR" => remote_addr,
16
+ "SERVER_NAME" => host,
17
+ "SERVER_PORT" => port.to_s,
18
+ "SERVER_PROTOCOL" => version,
19
+ "HTTP_VERSION" => version,
20
+ "HTTP_HOST" => host,
21
+ "rack.input" => StringIO.new(body),
22
+ "rack.errors" => $stderr,
23
+ "rack.version" => version,
24
+ "rack.multithread" => true,
25
+ "rack.multiprocess" => true,
26
+ "rack.run_once" => false,
27
+ "rack.multipart.buffer_size" => 16_384
28
+ }.merge(
29
+ headers.transform_keys do |k|
30
+ case k
31
+ when "content-length" then "CONTENT_LENGTH"
32
+ when "content-type" then "CONTENT_TYPE"
33
+ else "HTTP_#{k.upcase.tr("-", "_")}"
34
+ end
35
+ end
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Itsi
4
+ class Server
5
+ VERSION = "0.1.1"
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "server/version"
4
+ require_relative "server/itsi_server"
5
+
6
+ module Itsi
7
+ class Server
8
+ # Call our Rack app with our request ENV.
9
+ def self.call(app, request)
10
+ app.call(request.to_env)
11
+ end
12
+
13
+ # If scheduler is enabled
14
+ # Each request is wrapped in a Fiber.
15
+ def self.schedule(app, request)
16
+ Fiber.schedule do
17
+ call(app, request)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module ItsiServer
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+ require "itsi/server"
5
+ require "minitest/autorun"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class TestItsiServer < Minitest::Test
6
+ def test_that_it_has_a_version_number
7
+ refute_nil ::Itsi::Server::VERSION
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Itsi
2
+ VERSION = "0.1.0"
3
+ end
data/lib/itsi.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative 'itsi/version'
2
+ require 'itsi/scheduler'
3
+ require 'itsi/server'
4
+
5
+ module Itsi
6
+ end