itsi-scheduler 0.1.5 → 0.2.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.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +120 -52
  3. data/README.md +57 -24
  4. data/Rakefile +0 -4
  5. data/ext/itsi_acme/Cargo.toml +86 -0
  6. data/ext/itsi_acme/examples/high_level.rs +63 -0
  7. data/ext/itsi_acme/examples/high_level_warp.rs +52 -0
  8. data/ext/itsi_acme/examples/low_level.rs +87 -0
  9. data/ext/itsi_acme/examples/low_level_axum.rs +66 -0
  10. data/ext/itsi_acme/src/acceptor.rs +81 -0
  11. data/ext/itsi_acme/src/acme.rs +354 -0
  12. data/ext/itsi_acme/src/axum.rs +86 -0
  13. data/ext/itsi_acme/src/cache.rs +39 -0
  14. data/ext/itsi_acme/src/caches/boxed.rs +80 -0
  15. data/ext/itsi_acme/src/caches/composite.rs +69 -0
  16. data/ext/itsi_acme/src/caches/dir.rs +106 -0
  17. data/ext/itsi_acme/src/caches/mod.rs +11 -0
  18. data/ext/itsi_acme/src/caches/no.rs +78 -0
  19. data/ext/itsi_acme/src/caches/test.rs +136 -0
  20. data/ext/itsi_acme/src/config.rs +172 -0
  21. data/ext/itsi_acme/src/https_helper.rs +69 -0
  22. data/ext/itsi_acme/src/incoming.rs +142 -0
  23. data/ext/itsi_acme/src/jose.rs +161 -0
  24. data/ext/itsi_acme/src/lib.rs +142 -0
  25. data/ext/itsi_acme/src/resolver.rs +59 -0
  26. data/ext/itsi_acme/src/state.rs +424 -0
  27. data/ext/itsi_error/Cargo.toml +1 -0
  28. data/ext/itsi_error/src/lib.rs +106 -7
  29. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  30. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  31. data/ext/itsi_error/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  32. data/ext/itsi_error/target/debug/build/rb-sys-49f554618693db24/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  33. data/ext/itsi_error/target/debug/incremental/itsi_error-1mmt5sux7jb0i/s-h510z7m8v9-0bxu7yd.lock +0 -0
  34. data/ext/itsi_error/target/debug/incremental/itsi_error-2vn3jey74oiw0/s-h5113n0e7e-1v5qzs6.lock +0 -0
  35. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510ykifhe-0tbnep2.lock +0 -0
  36. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510yyocpj-0tz7ug7.lock +0 -0
  37. data/ext/itsi_error/target/debug/incremental/itsi_error-37uv9dicz7awp/s-h510z0xc8g-14ol18k.lock +0 -0
  38. data/ext/itsi_error/target/debug/incremental/itsi_error-3g5qf4y7d54uj/s-h5113n0e7d-1trk8on.lock +0 -0
  39. data/ext/itsi_error/target/debug/incremental/itsi_error-3lpfftm45d3e2/s-h510z7m8r3-1pxp20o.lock +0 -0
  40. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510ykifek-1uxasnk.lock +0 -0
  41. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510yyocki-11u37qm.lock +0 -0
  42. data/ext/itsi_error/target/debug/incremental/itsi_error-3o4qownhl3d7n/s-h510z0xc93-0pmy0zm.lock +0 -0
  43. data/ext/itsi_rb_helpers/Cargo.toml +1 -0
  44. data/ext/itsi_rb_helpers/src/heap_value.rs +18 -0
  45. data/ext/itsi_rb_helpers/src/lib.rs +63 -12
  46. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/common.rs +355 -0
  47. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/dynamic.rs +276 -0
  48. data/ext/itsi_rb_helpers/target/debug/build/clang-sys-da71b0344e568175/out/macros.rs +49 -0
  49. data/ext/itsi_rb_helpers/target/debug/build/rb-sys-eb9ed4ff3a60f995/out/bindings-0.9.110-mri-arm64-darwin23-3.4.2.rs +8865 -0
  50. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-040pxg6yhb3g3/s-h5113n7a1b-03bwlt4.lock +0 -0
  51. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h51113xnh3-1eik1ip.lock +0 -0
  52. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-131g1u4dzkt1a/s-h5111704jj-0g4rj8x.lock +0 -0
  53. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-1q2d3drtxrzs5/s-h5113n79yl-0bxcqc5.lock +0 -0
  54. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h51113xoox-10de2hp.lock +0 -0
  55. data/ext/itsi_rb_helpers/target/debug/incremental/itsi_rb_helpers-374a9h7ovycj0/s-h5111704w7-0vdq7gq.lock +0 -0
  56. data/ext/itsi_scheduler/Cargo.toml +1 -1
  57. data/ext/itsi_scheduler/src/itsi_scheduler.rs +9 -3
  58. data/ext/itsi_scheduler/src/lib.rs +1 -0
  59. data/ext/itsi_server/Cargo.lock +2956 -0
  60. data/ext/itsi_server/Cargo.toml +73 -29
  61. data/ext/itsi_server/src/default_responses/mod.rs +11 -0
  62. data/ext/itsi_server/src/env.rs +43 -0
  63. data/ext/itsi_server/src/lib.rs +114 -75
  64. data/ext/itsi_server/src/prelude.rs +2 -0
  65. data/ext/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  66. data/ext/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +29 -8
  67. data/ext/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
  68. data/ext/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +264 -0
  69. data/ext/itsi_server/src/ruby_types/itsi_http_request.rs +362 -0
  70. data/ext/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +84 -40
  71. data/ext/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +233 -0
  72. data/ext/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +565 -0
  73. data/ext/itsi_server/src/ruby_types/itsi_server.rs +86 -0
  74. data/ext/itsi_server/src/ruby_types/mod.rs +48 -0
  75. data/ext/itsi_server/src/server/{bind.rs → binds/bind.rs} +59 -24
  76. data/ext/itsi_server/src/server/binds/listener.rs +444 -0
  77. data/ext/itsi_server/src/server/binds/mod.rs +4 -0
  78. data/ext/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +57 -19
  79. data/ext/itsi_server/src/server/{tls.rs → binds/tls.rs} +120 -31
  80. data/ext/itsi_server/src/server/byte_frame.rs +32 -0
  81. data/ext/itsi_server/src/server/http_message_types.rs +97 -0
  82. data/ext/itsi_server/src/server/io_stream.rs +2 -1
  83. data/ext/itsi_server/src/server/lifecycle_event.rs +3 -0
  84. data/ext/itsi_server/src/server/middleware_stack/middleware.rs +170 -0
  85. data/ext/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +63 -0
  86. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +94 -0
  87. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +94 -0
  88. data/ext/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +343 -0
  89. data/ext/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +151 -0
  90. data/ext/itsi_server/src/server/middleware_stack/middlewares/compression.rs +316 -0
  91. data/ext/itsi_server/src/server/middleware_stack/middlewares/cors.rs +301 -0
  92. data/ext/itsi_server/src/server/middleware_stack/middlewares/csp.rs +193 -0
  93. data/ext/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +64 -0
  94. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +192 -0
  95. data/ext/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +171 -0
  96. data/ext/itsi_server/src/server/middleware_stack/middlewares/etag.rs +198 -0
  97. data/ext/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +82 -0
  98. data/ext/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +209 -0
  99. data/ext/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  100. data/ext/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
  101. data/ext/itsi_server/src/server/middleware_stack/middlewares/mod.rs +116 -0
  102. data/ext/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +411 -0
  103. data/ext/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +142 -0
  104. data/ext/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +55 -0
  105. data/ext/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +54 -0
  106. data/ext/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +51 -0
  107. data/ext/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +126 -0
  108. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +187 -0
  109. data/ext/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
  110. data/ext/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +173 -0
  111. data/ext/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +31 -0
  112. data/ext/itsi_server/src/server/middleware_stack/mod.rs +381 -0
  113. data/ext/itsi_server/src/server/mod.rs +7 -5
  114. data/ext/itsi_server/src/server/process_worker.rs +65 -14
  115. data/ext/itsi_server/src/server/redirect_type.rs +26 -0
  116. data/ext/itsi_server/src/server/request_job.rs +11 -0
  117. data/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +150 -50
  118. data/ext/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  119. data/ext/itsi_server/src/server/serve_strategy/single_mode.rs +399 -165
  120. data/ext/itsi_server/src/server/signal.rs +33 -26
  121. data/ext/itsi_server/src/server/size_limited_incoming.rs +107 -0
  122. data/ext/itsi_server/src/server/thread_worker.rs +218 -107
  123. data/ext/itsi_server/src/services/cache_store.rs +74 -0
  124. data/ext/itsi_server/src/services/itsi_http_service.rs +257 -0
  125. data/ext/itsi_server/src/services/mime_types.rs +1416 -0
  126. data/ext/itsi_server/src/services/mod.rs +6 -0
  127. data/ext/itsi_server/src/services/password_hasher.rs +83 -0
  128. data/ext/itsi_server/src/services/rate_limiter.rs +580 -0
  129. data/ext/itsi_server/src/services/static_file_server.rs +1340 -0
  130. data/ext/itsi_tracing/Cargo.toml +1 -0
  131. data/ext/itsi_tracing/src/lib.rs +362 -33
  132. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0994n8rpvvt9m/s-h510hfz1f6-1kbycmq.lock +0 -0
  133. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-0bob7bf4yq34i/s-h5113125h5-0lh4rag.lock +0 -0
  134. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2fcodulrxbbxo/s-h510h2infk-0hp5kjw.lock +0 -0
  135. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2iak63r1woi1l/s-h510h2in4q-0kxfzw1.lock +0 -0
  136. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2kk4qj9gn5dg2/s-h5113124kv-0enwon2.lock +0 -0
  137. data/ext/itsi_tracing/target/debug/incremental/itsi_tracing-2mwo0yas7dtw4/s-h510hfz1ha-1udgpei.lock +0 -0
  138. data/itsi-scheduler-100.png +0 -0
  139. data/lib/itsi/scheduler/version.rb +1 -1
  140. data/lib/itsi/scheduler.rb +11 -6
  141. metadata +117 -24
  142. data/CHANGELOG.md +0 -5
  143. data/CODE_OF_CONDUCT.md +0 -132
  144. data/LICENSE.txt +0 -21
  145. data/ext/itsi_error/src/from.rs +0 -71
  146. data/ext/itsi_server/extconf.rb +0 -6
  147. data/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  148. data/ext/itsi_server/src/request/itsi_request.rs +0 -277
  149. data/ext/itsi_server/src/request/mod.rs +0 -1
  150. data/ext/itsi_server/src/response/mod.rs +0 -1
  151. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +0 -13
  152. data/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +0 -5
  153. data/ext/itsi_server/src/server/itsi_server.rs +0 -244
  154. data/ext/itsi_server/src/server/listener.rs +0 -327
  155. /data/ext/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
@@ -0,0 +1,233 @@
1
+ use derive_more::Debug;
2
+ use globset::{Glob, GlobSet, GlobSetBuilder};
3
+ use magnus::error::Result;
4
+ use nix::unistd::{close, fork, pipe, read};
5
+ use notify::event::ModifyKind;
6
+ use notify::{Event, RecursiveMode, Watcher};
7
+ use notify::{EventKind, RecommendedWatcher};
8
+ use std::path::Path;
9
+ use std::sync::mpsc::Sender;
10
+ use std::time::{Duration, Instant};
11
+ use std::{collections::HashSet, fs};
12
+ use std::{
13
+ os::fd::{AsRawFd, IntoRawFd, OwnedFd},
14
+ path::PathBuf,
15
+ process::Command,
16
+ sync::mpsc,
17
+ thread::{self},
18
+ };
19
+ use tracing::debug;
20
+
21
+ /// Represents a set of patterns and commands.
22
+ #[derive(Debug, Clone)]
23
+ struct PatternGroup {
24
+ base_dir: PathBuf,
25
+ glob_set: GlobSet,
26
+ pattern: String,
27
+ commands: Vec<Vec<String>>,
28
+ last_triggered: Option<Instant>,
29
+ }
30
+
31
+ /// Extracts the base directory from a wildcard pattern by taking the portion up to the first
32
+ /// component that contains a wildcard character.
33
+ fn extract_and_canonicalize_base_dir(pattern: &str) -> PathBuf {
34
+ if !(pattern.contains("*") || pattern.contains("?") || pattern.contains('[')) {
35
+ if let Ok(metadata) = fs::metadata(pattern) {
36
+ if metadata.is_dir() {
37
+ return fs::canonicalize(pattern).unwrap();
38
+ }
39
+ if metadata.is_file() {
40
+ return fs::canonicalize(pattern)
41
+ .unwrap()
42
+ .parent()
43
+ .unwrap()
44
+ .to_path_buf();
45
+ }
46
+ }
47
+ }
48
+
49
+ let path = Path::new(pattern);
50
+ let mut base = PathBuf::new();
51
+ for comp in path.components() {
52
+ let comp_str = comp.as_os_str().to_string_lossy();
53
+ if comp_str.contains('*') || comp_str.contains('?') || comp_str.contains('[') {
54
+ break;
55
+ } else {
56
+ base.push(comp);
57
+ }
58
+ }
59
+ // If no base was built, default to "."
60
+ let base = if base.as_os_str().is_empty() || !base.exists() {
61
+ PathBuf::from(".")
62
+ } else {
63
+ base
64
+ };
65
+
66
+ // Canonicalize to get the absolute path.
67
+ fs::canonicalize(&base).unwrap_or(base)
68
+ }
69
+
70
+ /// Minimum time between triggering the same pattern group (debounce time)
71
+ const DEBOUNCE_DURATION: Duration = Duration::from_millis(500);
72
+
73
+ pub fn watch_groups(pattern_groups: Vec<(String, Vec<Vec<String>>)>) -> Result<Option<OwnedFd>> {
74
+ let (r_fd, w_fd): (OwnedFd, OwnedFd) = pipe().map_err(|e| {
75
+ magnus::Error::new(
76
+ magnus::exception::standard_error(),
77
+ format!("Failed to create watcher pipe: {}", e),
78
+ )
79
+ })?;
80
+
81
+ let fork_result = unsafe {
82
+ fork().map_err(|e| {
83
+ magnus::Error::new(
84
+ magnus::exception::standard_error(),
85
+ format!("Failed to fork file watcher: {}", e),
86
+ )
87
+ })
88
+ }?;
89
+
90
+ if fork_result.is_child() {
91
+ let _ = close(w_fd.into_raw_fd());
92
+ thread::spawn(move || {
93
+ let mut buf = [0u8; 1];
94
+ loop {
95
+ match read(r_fd.as_raw_fd(), &mut buf) {
96
+ Ok(0) => {
97
+ std::process::exit(0);
98
+ }
99
+ Ok(_) => {}
100
+ Err(_) => {
101
+ std::process::exit(0);
102
+ }
103
+ }
104
+ }
105
+ });
106
+
107
+ let mut groups = Vec::new();
108
+ for (pattern, commands) in pattern_groups.into_iter() {
109
+ let base_dir = extract_and_canonicalize_base_dir(&pattern);
110
+ let glob = Glob::new(pattern.trim_start_matches("./")).map_err(|e| {
111
+ magnus::Error::new(
112
+ magnus::exception::standard_error(),
113
+ format!("Failed to create watch glob: {}", e),
114
+ )
115
+ })?;
116
+ let glob_set = GlobSetBuilder::new().add(glob).build().map_err(|e| {
117
+ magnus::Error::new(
118
+ magnus::exception::standard_error(),
119
+ format!("Failed to create watch glob set: {}", e),
120
+ )
121
+ })?;
122
+ groups.push(PatternGroup {
123
+ base_dir,
124
+ glob_set,
125
+ pattern,
126
+ commands,
127
+ last_triggered: None,
128
+ });
129
+ }
130
+
131
+ // Create a channel and a watcher.
132
+ let (tx, rx) = mpsc::channel::<notify::Result<Event>>();
133
+ let sender = tx.clone();
134
+ fn event_fn(sender: Sender<notify::Result<Event>>) -> impl Fn(notify::Result<Event>) {
135
+ move |res| match res {
136
+ Ok(event) => {
137
+ sender.send(Ok(event)).unwrap();
138
+ }
139
+ Err(e) => println!("watch error: {:?}", e),
140
+ }
141
+ }
142
+
143
+ let mut watched_dirs = HashSet::new();
144
+ let mut watcher: RecommendedWatcher =
145
+ notify::recommended_watcher(event_fn(sender)).expect("Failed to create watcher");
146
+ for group in &groups {
147
+ if watched_dirs.insert(group.base_dir.clone()) {
148
+ debug!("Watching {}{}", group.base_dir.display(), group.pattern);
149
+ watcher
150
+ .watch(&group.base_dir, RecursiveMode::Recursive)
151
+ .expect("Failed to add watch");
152
+ }
153
+ }
154
+
155
+ // Main event loop.
156
+ for res in rx {
157
+ match res {
158
+ Ok(event) => {
159
+ if !matches!(event.kind, EventKind::Modify(ModifyKind::Data(_))) {
160
+ continue;
161
+ }
162
+ let now = Instant::now();
163
+ for group in &mut groups {
164
+ for path in event.paths.iter() {
165
+ if let Ok(rel_path) = path.strip_prefix(&group.base_dir) {
166
+ if group.glob_set.is_match(rel_path)
167
+ || rel_path.to_str().is_some_and(|s| s == group.pattern)
168
+ {
169
+ debug!("Matched pattern: {:?}", group.pattern);
170
+ // Check if we should debounce this event
171
+ if let Some(last_triggered) = group.last_triggered {
172
+ if now.duration_since(last_triggered) < DEBOUNCE_DURATION {
173
+ // Skip this event as we've recently triggered for this pattern
174
+ continue;
175
+ }
176
+ }
177
+
178
+ // Update the last triggered time
179
+ group.last_triggered = Some(now);
180
+
181
+ // Execute the commands for this group.
182
+ for command in &group.commands {
183
+ if command.is_empty() {
184
+ continue;
185
+ }
186
+ let mut cmd = Command::new(&command[0]);
187
+ if command.len() > 1 {
188
+ cmd.args(&command[1..]);
189
+ }
190
+ debug!(
191
+ "Executing command: {:?} due to change in {:?}",
192
+ command, path
193
+ );
194
+ match cmd.spawn() {
195
+ Ok(mut child) => {
196
+ if let Err(e) = child.wait() {
197
+ eprintln!(
198
+ "Command {:?} failed: {:?}",
199
+ command, e
200
+ );
201
+ }
202
+ }
203
+ Err(e) => {
204
+ eprintln!(
205
+ "Failed to execute command {:?}: {:?}",
206
+ command, e
207
+ );
208
+ }
209
+ }
210
+ }
211
+ break;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ Err(e) => println!("Watch error: {:?}", e),
218
+ }
219
+ }
220
+
221
+ // Clean up the watches.
222
+ for group in &groups {
223
+ watcher
224
+ .unwatch(&group.base_dir)
225
+ .expect("Failed to remove watch");
226
+ }
227
+ drop(watcher);
228
+ std::process::exit(0);
229
+ } else {
230
+ let _ = close(r_fd.into_raw_fd());
231
+ Ok(Some(w_fd))
232
+ }
233
+ }