itsi 0.1.11 → 0.1.12

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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1535 -45
  3. data/{sandbox/itsi_itsi_file/Itsi.rb → Itsi.rb} +19 -13
  4. data/Rakefile +8 -7
  5. data/crates/itsi_error/src/lib.rs +9 -0
  6. data/crates/itsi_rb_helpers/Cargo.toml +1 -0
  7. data/crates/itsi_rb_helpers/src/heap_value.rs +18 -0
  8. data/crates/itsi_rb_helpers/src/lib.rs +34 -7
  9. data/crates/itsi_server/Cargo.toml +69 -30
  10. data/crates/itsi_server/src/lib.rs +79 -147
  11. data/crates/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  12. data/crates/itsi_server/src/{body_proxy/itsi_body_proxy.rs → ruby_types/itsi_body_proxy/mod.rs} +22 -3
  13. data/crates/itsi_server/src/ruby_types/itsi_grpc_request.rs +147 -0
  14. data/crates/itsi_server/src/ruby_types/itsi_grpc_response.rs +19 -0
  15. data/crates/itsi_server/src/ruby_types/itsi_grpc_stream/mod.rs +216 -0
  16. data/{gems/server/ext/itsi_server/src/request/itsi_request.rs → crates/itsi_server/src/ruby_types/itsi_http_request.rs} +101 -117
  17. data/crates/itsi_server/src/{response/itsi_response.rs → ruby_types/itsi_http_response.rs} +72 -41
  18. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +225 -0
  19. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +355 -0
  20. data/crates/itsi_server/src/ruby_types/itsi_server.rs +82 -0
  21. data/crates/itsi_server/src/ruby_types/mod.rs +55 -0
  22. data/crates/itsi_server/src/server/bind.rs +13 -5
  23. data/crates/itsi_server/src/server/byte_frame.rs +32 -0
  24. data/crates/itsi_server/src/server/cache_store.rs +74 -0
  25. data/crates/itsi_server/src/server/itsi_service.rs +172 -0
  26. data/crates/itsi_server/src/server/lifecycle_event.rs +3 -0
  27. data/crates/itsi_server/src/server/listener.rs +102 -2
  28. data/crates/itsi_server/src/server/middleware_stack/middleware.rs +153 -0
  29. data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +47 -0
  30. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +58 -0
  31. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +82 -0
  32. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +321 -0
  33. data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +139 -0
  34. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +300 -0
  35. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +287 -0
  36. data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +48 -0
  37. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +127 -0
  38. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +191 -0
  39. data/crates/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +72 -0
  40. data/crates/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +85 -0
  41. data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +195 -0
  42. data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +82 -0
  43. data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +82 -0
  44. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +216 -0
  45. data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +124 -0
  46. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +76 -0
  47. data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +43 -0
  48. data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +34 -0
  49. data/crates/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +93 -0
  50. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +162 -0
  51. data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +158 -0
  52. data/crates/itsi_server/src/server/middleware_stack/middlewares/token_source.rs +12 -0
  53. data/crates/itsi_server/src/server/middleware_stack/mod.rs +315 -0
  54. data/crates/itsi_server/src/server/mod.rs +8 -1
  55. data/crates/itsi_server/src/server/process_worker.rs +38 -12
  56. data/crates/itsi_server/src/server/rate_limiter.rs +565 -0
  57. data/crates/itsi_server/src/server/request_job.rs +11 -0
  58. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +119 -42
  59. data/crates/itsi_server/src/server/serve_strategy/mod.rs +9 -6
  60. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +256 -111
  61. data/crates/itsi_server/src/server/signal.rs +19 -0
  62. data/crates/itsi_server/src/server/static_file_server.rs +984 -0
  63. data/crates/itsi_server/src/server/thread_worker.rs +139 -94
  64. data/crates/itsi_server/src/server/types.rs +43 -0
  65. data/crates/itsi_server/test.md +14 -0
  66. data/crates/itsi_tracing/Cargo.toml +1 -0
  67. data/crates/itsi_tracing/src/lib.rs +216 -45
  68. data/docs/.gitignore +7 -0
  69. data/docs/.gitpod.yml +15 -0
  70. data/docs/Itsi.rb +17 -0
  71. data/docs/content/_index.md +17 -0
  72. data/docs/content/about.md +6 -0
  73. data/docs/content/docs/_index.md +18 -0
  74. data/docs/content/docs/first-page.md +9 -0
  75. data/docs/content/docs/folder/_index.md +10 -0
  76. data/docs/content/docs/folder/leaf.md +7 -0
  77. data/docs/go.mod +5 -0
  78. data/docs/go.sum +2 -0
  79. data/docs/hugo.yaml +77 -0
  80. data/examples/static_assets_example.rb +83 -0
  81. data/gems/_index.md +18 -0
  82. data/gems/scheduler/CODE_OF_CONDUCT.md +7 -0
  83. data/gems/scheduler/Cargo.lock +75 -14
  84. data/gems/scheduler/README.md +5 -0
  85. data/gems/scheduler/_index.md +7 -0
  86. data/gems/scheduler/itsi-scheduler.gemspec +4 -1
  87. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  88. data/gems/scheduler/lib/itsi/scheduler.rb +2 -2
  89. data/gems/scheduler/test/test_file_io.rb +0 -1
  90. data/gems/scheduler/test/test_itsi_scheduler.rb +1 -1
  91. data/gems/server/CHANGELOG.md +5 -0
  92. data/gems/server/CODE_OF_CONDUCT.md +7 -0
  93. data/gems/server/Cargo.lock +1536 -45
  94. data/gems/server/README.md +4 -0
  95. data/gems/server/_index.md +6 -0
  96. data/gems/server/exe/itsi +33 -74
  97. data/gems/server/itsi-server.gemspec +3 -2
  98. data/gems/server/lib/itsi/{request.rb → http_request.rb} +29 -5
  99. data/gems/server/lib/itsi/http_response.rb +39 -0
  100. data/gems/server/lib/itsi/server/Itsi.rb +11 -19
  101. data/gems/server/lib/itsi/server/config/dsl.rb +506 -0
  102. data/gems/server/lib/itsi/server/config.rb +103 -8
  103. data/gems/server/lib/itsi/server/default_app/default_app.rb +38 -0
  104. data/gems/server/lib/itsi/server/grpc_interface.rb +213 -0
  105. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +8 -17
  106. data/gems/server/lib/itsi/server/rack_interface.rb +23 -4
  107. data/gems/server/lib/itsi/server/scheduler_interface.rb +1 -1
  108. data/gems/server/lib/itsi/server/scheduler_mode.rb +4 -0
  109. data/gems/server/lib/itsi/server/signal_trap.rb +7 -1
  110. data/gems/server/lib/itsi/server/version.rb +1 -1
  111. data/gems/server/lib/itsi/server.rb +74 -63
  112. data/gems/server/lib/itsi/standard_headers.rb +86 -0
  113. data/gems/server/test/helpers/test_helper.rb +12 -12
  114. data/gems/server/test/test_itsi_server.rb +2 -2
  115. data/lib/itsi/version.rb +1 -1
  116. data/sandbox/itsi_file/Gemfile +11 -0
  117. data/sandbox/itsi_file/Gemfile.lock +69 -0
  118. data/sandbox/itsi_file/Itsi.rb +276 -0
  119. data/sandbox/itsi_file/error.html +2 -0
  120. data/sandbox/itsi_file/organisations_controller.rb +20 -0
  121. data/sandbox/itsi_file/public/assets/image.png +0 -0
  122. data/sandbox/itsi_file/public/assets/index.html +1 -0
  123. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +2 -2
  124. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  125. data/sandbox/itsi_sandbox_rack/config.ru +2 -15
  126. data/sandbox/itsi_sandbox_rails/.dockerignore +2 -5
  127. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +1 -1
  128. data/sandbox/itsi_sandbox_rails/.gitignore +2 -1
  129. data/sandbox/itsi_sandbox_rails/Dockerfile +6 -9
  130. data/sandbox/itsi_sandbox_rails/Gemfile +16 -22
  131. data/sandbox/itsi_sandbox_rails/Gemfile.lock +100 -225
  132. data/sandbox/itsi_sandbox_rails/app/assets/config/manifest.js +4 -0
  133. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +11 -6
  134. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/channel.rb +4 -0
  135. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/connection.rb +4 -0
  136. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +7 -8
  137. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +0 -3
  138. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +2 -7
  139. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +3 -4
  140. data/sandbox/itsi_sandbox_rails/bin/setup +8 -5
  141. data/sandbox/itsi_sandbox_rails/config/application.rb +1 -35
  142. data/sandbox/itsi_sandbox_rails/config/cable.yml +3 -10
  143. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -1
  144. data/sandbox/itsi_sandbox_rails/config/database.yml +9 -19
  145. data/sandbox/itsi_sandbox_rails/config/environment.rb +1 -1
  146. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +21 -12
  147. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +49 -34
  148. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +19 -5
  149. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +5 -0
  150. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +1 -1
  151. data/sandbox/itsi_sandbox_rails/config/initializers/permissions_policy.rb +13 -0
  152. data/sandbox/itsi_sandbox_rails/config/puma.rb +2 -9
  153. data/sandbox/itsi_sandbox_rails/config.ru +0 -1
  154. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +1 -1
  155. data/sandbox/itsi_sandbox_rails/db/schema.rb +2 -2
  156. data/sandbox/itsi_sandbox_rails/lib/assets/.keep +0 -0
  157. data/sandbox/itsi_sandbox_rails/public/404.html +66 -113
  158. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +65 -113
  159. data/sandbox/itsi_sandbox_rails/public/422.html +66 -113
  160. data/sandbox/itsi_sandbox_rails/public/500.html +65 -113
  161. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  162. data/sandbox/itsi_sandbox_rails/public/icon.svg +2 -2
  163. data/sandbox/itsi_sandbox_rails/test/channels/application_cable/connection_test.rb +13 -0
  164. data/sandbox/itsi_sandbox_roda/Gemfile.lock +3 -10
  165. data/tasks.txt +72 -35
  166. metadata +89 -139
  167. data/crates/itsi_server/src/body_proxy/mod.rs +0 -2
  168. data/crates/itsi_server/src/request/itsi_request.rs +0 -298
  169. data/crates/itsi_server/src/request/mod.rs +0 -1
  170. data/crates/itsi_server/src/response/mod.rs +0 -1
  171. data/crates/itsi_server/src/server/itsi_server.rs +0 -288
  172. data/gems/scheduler/ext/itsi_error/Cargo.lock +0 -368
  173. data/gems/scheduler/ext/itsi_error/Cargo.toml +0 -11
  174. data/gems/scheduler/ext/itsi_error/src/from.rs +0 -68
  175. data/gems/scheduler/ext/itsi_error/src/lib.rs +0 -24
  176. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +0 -15
  177. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +0 -31
  178. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +0 -355
  179. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +0 -10
  180. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  181. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +0 -201
  182. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +0 -24
  183. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +0 -6
  184. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  185. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  186. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  187. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  188. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +0 -38
  189. data/gems/scheduler/ext/itsi_server/Cargo.lock +0 -2956
  190. data/gems/scheduler/ext/itsi_server/Cargo.toml +0 -50
  191. data/gems/scheduler/ext/itsi_server/extconf.rb +0 -6
  192. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  193. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  194. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  195. data/gems/scheduler/ext/itsi_server/src/env.rs +0 -43
  196. data/gems/scheduler/ext/itsi_server/src/lib.rs +0 -180
  197. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +0 -298
  198. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +0 -1
  199. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +0 -357
  200. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +0 -1
  201. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +0 -174
  202. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  203. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +0 -104
  204. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +0 -288
  205. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  206. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +0 -318
  207. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +0 -11
  208. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +0 -203
  209. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -260
  210. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  211. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -276
  212. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +0 -74
  213. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +0 -399
  214. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  215. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +0 -265
  216. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +0 -274
  217. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +0 -16
  218. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +0 -58
  219. data/gems/server/ext/itsi_error/Cargo.lock +0 -368
  220. data/gems/server/ext/itsi_error/Cargo.toml +0 -11
  221. data/gems/server/ext/itsi_error/src/from.rs +0 -68
  222. data/gems/server/ext/itsi_error/src/lib.rs +0 -24
  223. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +0 -15
  224. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +0 -31
  225. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +0 -355
  226. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +0 -10
  227. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  228. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +0 -201
  229. data/gems/server/ext/itsi_scheduler/Cargo.toml +0 -24
  230. data/gems/server/ext/itsi_scheduler/extconf.rb +0 -6
  231. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  232. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  233. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  234. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  235. data/gems/server/ext/itsi_scheduler/src/lib.rs +0 -38
  236. data/gems/server/ext/itsi_server/Cargo.lock +0 -2956
  237. data/gems/server/ext/itsi_server/Cargo.toml +0 -50
  238. data/gems/server/ext/itsi_server/extconf.rb +0 -6
  239. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  240. data/gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  241. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  242. data/gems/server/ext/itsi_server/src/env.rs +0 -43
  243. data/gems/server/ext/itsi_server/src/lib.rs +0 -180
  244. data/gems/server/ext/itsi_server/src/request/mod.rs +0 -1
  245. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +0 -357
  246. data/gems/server/ext/itsi_server/src/response/mod.rs +0 -1
  247. data/gems/server/ext/itsi_server/src/server/bind.rs +0 -174
  248. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  249. data/gems/server/ext/itsi_server/src/server/io_stream.rs +0 -104
  250. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +0 -288
  251. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  252. data/gems/server/ext/itsi_server/src/server/listener.rs +0 -318
  253. data/gems/server/ext/itsi_server/src/server/mod.rs +0 -11
  254. data/gems/server/ext/itsi_server/src/server/process_worker.rs +0 -203
  255. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -260
  256. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  257. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -276
  258. data/gems/server/ext/itsi_server/src/server/signal.rs +0 -74
  259. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +0 -399
  260. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  261. data/gems/server/ext/itsi_server/src/server/tls.rs +0 -265
  262. data/gems/server/ext/itsi_tracing/Cargo.lock +0 -274
  263. data/gems/server/ext/itsi_tracing/Cargo.toml +0 -16
  264. data/gems/server/ext/itsi_tracing/src/lib.rs +0 -58
  265. data/gems/server/lib/itsi/server/options_dsl.rb +0 -401
  266. data/gems/server/lib/itsi/stream_io.rb +0 -38
  267. data/location_dsl.rb +0 -381
  268. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +0 -3
  269. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +0 -3
  270. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +0 -14
  271. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +0 -3
  272. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +0 -3
  273. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +0 -51
  274. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +0 -47
  275. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +0 -109
  276. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  277. data/sandbox/itsi_sandbox_rails/.kamal/secrets +0 -17
  278. data/sandbox/itsi_sandbox_rails/bin/dev +0 -2
  279. data/sandbox/itsi_sandbox_rails/bin/jobs +0 -6
  280. data/sandbox/itsi_sandbox_rails/bin/kamal +0 -27
  281. data/sandbox/itsi_sandbox_rails/bin/thrust +0 -5
  282. data/sandbox/itsi_sandbox_rails/config/cache.yml +0 -16
  283. data/sandbox/itsi_sandbox_rails/config/deploy.yml +0 -116
  284. data/sandbox/itsi_sandbox_rails/config/queue.yml +0 -18
  285. data/sandbox/itsi_sandbox_rails/config/recurring.yml +0 -10
  286. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +0 -11
  287. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +0 -14
  288. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +0 -129
  289. data/sandbox/itsi_sandbox_rails/public/400.html +0 -114
  290. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +0 -9
  291. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +0 -7
  292. /data/{sandbox/itsi_sandbox_rails/script/.keep → crates/_index.md} +0 -0
  293. /data/gems/server/lib/itsi/{index.html → server/default_app/index.html} +0 -0
@@ -1,4 +1,5 @@
1
- use super::big_bytes::BigBytes;
1
+ pub mod big_bytes;
2
+ use big_bytes::BigBytes;
2
3
  use bytes::Bytes;
3
4
  use futures::executor::block_on;
4
5
  use http_body_util::{BodyDataStream, BodyExt};
@@ -25,10 +26,10 @@ pub enum ItsiBody {
25
26
  }
26
27
 
27
28
  impl ItsiBody {
28
- pub fn into_value(&self) -> Value {
29
+ pub fn into_value(&self) -> Option<Value> {
29
30
  match self {
30
31
  ItsiBody::Buffered(bytes) => bytes.as_value(),
31
- ItsiBody::Stream(proxy) => proxy.clone().into_value(),
32
+ ItsiBody::Stream(proxy) => Some(proxy.clone().into_value()),
32
33
  }
33
34
  }
34
35
  }
@@ -98,6 +99,24 @@ impl ItsiBodyProxy {
98
99
  Ok(Some(output_string))
99
100
  }
100
101
 
102
+ pub fn to_bytes(&self) -> MagnusResult<Vec<u8>> {
103
+ self.verify_open()?;
104
+ let mut stream = self.incoming.lock();
105
+ let mut buf = self.buf.lock();
106
+
107
+ while let Some(chunk) = block_on(stream.next()) {
108
+ let chunk = chunk.map_err(|err| {
109
+ magnus::Error::new(
110
+ magnus::exception::exception(),
111
+ format!("Error reading body {:?}", err),
112
+ )
113
+ })?;
114
+ buf.extend_from_slice(&chunk);
115
+ }
116
+
117
+ Ok(buf.clone())
118
+ }
119
+
101
120
  /// Equivalent to calling gets and yielding it, until we reach EOF
102
121
  pub fn each(ruby: &Ruby, rbself: &Self) -> MagnusResult<()> {
103
122
  let proc = ruby.block_proc()?;
@@ -0,0 +1,147 @@
1
+ use derive_more::Debug;
2
+ use http::{request::Parts, Response, StatusCode};
3
+ use http_body_util::{combinators::BoxBody, BodyExt, Empty};
4
+ use itsi_error::from::CLIENT_CONNECTION_CLOSED;
5
+ use itsi_rb_helpers::{print_rb_backtrace, HeapValue};
6
+ use itsi_tracing::debug;
7
+ use magnus::{
8
+ block::Proc,
9
+ error::{ErrorType, Result as MagnusResult},
10
+ Error,
11
+ };
12
+ use magnus::{
13
+ value::{LazyId, ReprValue},
14
+ Ruby, Value,
15
+ };
16
+ use std::{sync::Arc, time::Instant};
17
+ use tokio::sync::mpsc::{self};
18
+ use tracing::error;
19
+
20
+ use super::itsi_grpc_stream::ItsiGrpcStream;
21
+ use crate::server::{
22
+ byte_frame::ByteFrame,
23
+ itsi_service::RequestContext,
24
+ request_job::RequestJob,
25
+ types::{HttpRequest, HttpResponse},
26
+ };
27
+
28
+ static ID_MESSAGE: LazyId = LazyId::new("message");
29
+
30
+ #[derive(Debug)]
31
+ #[magnus::wrap(class = "Itsi::GrpcRequest", free_immediately, size)]
32
+ pub struct ItsiGrpcRequest {
33
+ pub parts: Parts,
34
+ pub start: Instant,
35
+ #[debug(skip)]
36
+ pub context: RequestContext,
37
+ #[debug(skip)]
38
+ pub stream: ItsiGrpcStream,
39
+ }
40
+
41
+ impl ItsiGrpcRequest {
42
+ pub fn service_name(&self) -> MagnusResult<String> {
43
+ let path = self.parts.uri.path();
44
+ Ok(path.split('/').nth_back(1).unwrap().to_string())
45
+ }
46
+
47
+ pub fn method_name(&self) -> MagnusResult<String> {
48
+ let path = self.parts.uri.path();
49
+ Ok(path.split('/').nth_back(0).unwrap().to_string())
50
+ }
51
+
52
+ pub fn stream(&self) -> MagnusResult<ItsiGrpcStream> {
53
+ Ok(self.stream.clone())
54
+ }
55
+
56
+ pub fn content_type_str(&self) -> &str {
57
+ self.parts
58
+ .headers
59
+ .get("Content-Type")
60
+ .and_then(|hv| hv.to_str().ok())
61
+ .unwrap_or("application/x-www-form-urlencoded")
62
+ }
63
+
64
+ pub fn is_json(&self) -> bool {
65
+ self.content_type_str() == "application/json"
66
+ }
67
+
68
+ pub fn process(self, ruby: &Ruby, app_proc: Arc<HeapValue<Proc>>) -> magnus::error::Result<()> {
69
+ let response = self.stream.clone();
70
+ let result = app_proc.call::<_, Value>((self,));
71
+ if let Err(err) = result {
72
+ Self::internal_error(ruby, response, err);
73
+ }
74
+ Ok(())
75
+ }
76
+
77
+ pub fn internal_error(_ruby: &Ruby, stream: ItsiGrpcStream, err: Error) {
78
+ if let Some(rb_err) = err.value() {
79
+ print_rb_backtrace(rb_err);
80
+ stream.internal_server_error(err.to_string());
81
+ } else {
82
+ stream.internal_server_error(err.to_string());
83
+ }
84
+ }
85
+
86
+ pub(crate) async fn process_request(
87
+ app: Arc<HeapValue<Proc>>,
88
+ hyper_request: HttpRequest,
89
+ context: &RequestContext,
90
+ ) -> itsi_error::Result<HttpResponse> {
91
+ let (request, mut receiver) = ItsiGrpcRequest::new(hyper_request, context).await;
92
+ let shutdown_channel = context.service.shutdown_channel.clone();
93
+ let response_stream = request.stream.clone();
94
+ match context
95
+ .sender
96
+ .send(RequestJob::ProcessGrpcRequest(request, app))
97
+ .await
98
+ {
99
+ Err(err) => {
100
+ error!("Error occurred: {}", err);
101
+ let mut response = Response::new(BoxBody::new(Empty::new()));
102
+ *response.status_mut() = StatusCode::BAD_REQUEST;
103
+ Ok(response)
104
+ }
105
+ _ => match receiver.recv().await {
106
+ Some(first_frame) => Ok(response_stream
107
+ .build_response(first_frame, receiver, shutdown_channel)
108
+ .await),
109
+ None => Ok(Response::new(BoxBody::new(Empty::new()))),
110
+ },
111
+ }
112
+ }
113
+ pub fn is_connection_closed_err(ruby: &Ruby, err: &Error) -> bool {
114
+ match err.error_type() {
115
+ ErrorType::Jump(_) => false,
116
+ ErrorType::Error(_, _) => false,
117
+ ErrorType::Exception(exception) => {
118
+ exception.is_kind_of(ruby.exception_eof_error())
119
+ && err
120
+ .value()
121
+ .map(|v| {
122
+ v.funcall::<_, _, String>(*ID_MESSAGE, ())
123
+ .unwrap_or("".to_string())
124
+ .eq(CLIENT_CONNECTION_CLOSED)
125
+ })
126
+ .unwrap_or(false)
127
+ }
128
+ }
129
+ }
130
+
131
+ pub(crate) async fn new(
132
+ request: HttpRequest,
133
+ context: &RequestContext,
134
+ ) -> (ItsiGrpcRequest, mpsc::Receiver<ByteFrame>) {
135
+ let (parts, body) = request.into_parts();
136
+ let response_channel = mpsc::channel::<ByteFrame>(100);
137
+ (
138
+ Self {
139
+ context: context.clone(),
140
+ start: Instant::now(),
141
+ parts,
142
+ stream: ItsiGrpcStream::new(response_channel.0, body.into_data_stream()),
143
+ },
144
+ response_channel.1,
145
+ )
146
+ }
147
+ }
@@ -0,0 +1,19 @@
1
+ use derive_more::Debug;
2
+ use http::request::Parts;
3
+ use tokio::sync::mpsc::Sender;
4
+
5
+ use crate::server::byte_frame::ByteFrame;
6
+
7
+ #[derive(Debug, Clone)]
8
+ #[magnus::wrap(class = "Itsi::GrpcResponse", free_immediately, size)]
9
+ pub struct ItsiGrpcResponse {
10
+ pub parts: Parts,
11
+ #[debug(skip)]
12
+ pub sender: Sender<ByteFrame>,
13
+ }
14
+
15
+ impl ItsiGrpcResponse {
16
+ pub fn new(parts: Parts, sender: Sender<ByteFrame>) -> Self {
17
+ Self { parts, sender }
18
+ }
19
+ }
@@ -0,0 +1,216 @@
1
+ use std::{collections::HashMap, sync::Arc};
2
+
3
+ use crate::server::{
4
+ byte_frame::ByteFrame, serve_strategy::single_mode::RunningPhase, types::HttpResponse,
5
+ };
6
+ use bytes::Bytes;
7
+ use derive_more::Debug;
8
+ use futures::{executor::block_on, stream::unfold};
9
+ use http::{
10
+ header::{HeaderName, HeaderValue, CONTENT_TYPE},
11
+ HeaderMap, Response,
12
+ };
13
+ use http_body_util::{combinators::BoxBody, BodyDataStream, BodyExt, Empty, Full, StreamBody};
14
+ use hyper::body::{Frame, Incoming};
15
+ use magnus::error::Result as MagnusResult;
16
+ use parking_lot::Mutex;
17
+ use tokio::sync::{
18
+ mpsc::{Receiver, Sender},
19
+ oneshot, watch,
20
+ };
21
+ use tokio_stream::{wrappers::ReceiverStream, StreamExt};
22
+ use tracing::{error, info, warn};
23
+
24
+ #[derive(Debug, Clone)]
25
+ #[magnus::wrap(class = "Itsi::GrpcStream", free_immediately, size)]
26
+ pub struct ItsiGrpcStream {
27
+ pub inner: Arc<Mutex<ItsiGrpcStreamInner>>,
28
+ }
29
+
30
+ #[derive(Debug)]
31
+ pub struct ItsiGrpcStreamInner {
32
+ pub body: BodyDataStream<Incoming>,
33
+ pub buf: Vec<u8>,
34
+ pub response_sender: Sender<ByteFrame>,
35
+ pub response: Option<HttpResponse>,
36
+ trailer_tx: oneshot::Sender<HeaderMap>,
37
+ trailer_rx: Option<oneshot::Receiver<HeaderMap>>,
38
+ }
39
+
40
+ impl ItsiGrpcStreamInner {
41
+ pub fn read(&mut self, bytes: usize) -> MagnusResult<Bytes> {
42
+ let stream = &mut self.body;
43
+ let buf = &mut self.buf;
44
+ let mut result = Vec::with_capacity(bytes);
45
+
46
+ info!("Entering read with {:?}. Current buf is {:?}", bytes, buf);
47
+
48
+ // First, use any data already in the buffer
49
+ if !buf.is_empty() {
50
+ let remaining = bytes.min(buf.len());
51
+ result.extend_from_slice(&buf[..remaining]);
52
+ buf.drain(..remaining);
53
+ }
54
+
55
+ while result.len() < bytes {
56
+ if let Some(chunk) = block_on(stream.next()) {
57
+ let chunk = chunk.map_err(|err| {
58
+ magnus::Error::new(
59
+ magnus::exception::exception(),
60
+ format!("Error reading body {:?}", err),
61
+ )
62
+ })?;
63
+ let remaining = bytes - result.len();
64
+ if chunk.len() > remaining {
65
+ result.extend_from_slice(&chunk[..remaining]);
66
+ buf.extend_from_slice(&chunk[remaining..]);
67
+ } else {
68
+ result.extend_from_slice(&chunk);
69
+ }
70
+ } else {
71
+ break;
72
+ }
73
+ }
74
+
75
+ Ok(result.into())
76
+ }
77
+
78
+ pub fn write(&mut self, bytes: Bytes) -> MagnusResult<()> {
79
+ self.response_sender
80
+ .blocking_send(ByteFrame::Data(bytes))
81
+ .map_err(|err| {
82
+ magnus::Error::new(
83
+ magnus::exception::exception(),
84
+ format!("Error writing body {:?}", err),
85
+ )
86
+ })?;
87
+ Ok(())
88
+ }
89
+
90
+ pub fn flush(&mut self) -> MagnusResult<()> {
91
+ Ok(())
92
+ }
93
+
94
+ pub fn send_trailers(&mut self, trailers: HashMap<String, String>) -> MagnusResult<()> {
95
+ let mut header_map = HeaderMap::new();
96
+ for (key, value) in trailers {
97
+ if let (Ok(hn), Ok(hv)) = (key.parse::<HeaderName>(), value.parse::<HeaderValue>()) {
98
+ header_map.insert(hn, hv);
99
+ }
100
+ }
101
+ let trailer_tx = std::mem::replace(&mut self.trailer_tx, oneshot::channel().0);
102
+ trailer_tx.send(header_map).map_err(|err| {
103
+ magnus::Error::new(
104
+ magnus::exception::exception(),
105
+ format!("Error sending trailers {:?}", err),
106
+ )
107
+ })?;
108
+ self.response_sender
109
+ .blocking_send(ByteFrame::Empty)
110
+ .map_err(|err| {
111
+ magnus::Error::new(
112
+ magnus::exception::exception(),
113
+ format!("Error flushing {:?}", err),
114
+ )
115
+ })?;
116
+ Ok(())
117
+ }
118
+ }
119
+
120
+ impl ItsiGrpcStream {
121
+ pub fn new(response_sender: Sender<ByteFrame>, body: BodyDataStream<Incoming>) -> Self {
122
+ let (trailer_tx, trailer_rx) = oneshot::channel::<HeaderMap>();
123
+ ItsiGrpcStream {
124
+ inner: Arc::new(Mutex::new(ItsiGrpcStreamInner {
125
+ body,
126
+ buf: Vec::new(),
127
+ response_sender,
128
+ response: Some(Response::new(BoxBody::new(Empty::new()))),
129
+ trailer_tx,
130
+ trailer_rx: Some(trailer_rx),
131
+ })),
132
+ }
133
+ }
134
+
135
+ pub fn read(&self, bytes: usize) -> MagnusResult<Bytes> {
136
+ self.inner.lock().read(bytes)
137
+ }
138
+
139
+ pub fn write(&self, bytes: Bytes) -> MagnusResult<()> {
140
+ self.inner.lock().write(bytes)
141
+ }
142
+
143
+ pub fn flush(&self) -> MagnusResult<()> {
144
+ self.inner.lock().flush()
145
+ }
146
+
147
+ pub fn send_trailers(&self, trailers: HashMap<String, String>) -> MagnusResult<()> {
148
+ self.inner.lock().send_trailers(trailers)
149
+ }
150
+
151
+ pub async fn build_response(
152
+ &self,
153
+ first_frame: ByteFrame,
154
+ receiver: Receiver<ByteFrame>,
155
+ shutdown_rx: watch::Receiver<RunningPhase>,
156
+ ) -> HttpResponse {
157
+ let mut response = self.inner.lock().response.take().unwrap();
158
+ let rx = self.inner.lock().trailer_rx.take().unwrap();
159
+ response
160
+ .headers_mut()
161
+ .append(CONTENT_TYPE, "application/grpc".parse().unwrap());
162
+ *response.body_mut() = if matches!(first_frame, ByteFrame::Empty) {
163
+ BoxBody::new(Empty::new())
164
+ } else if matches!(first_frame, ByteFrame::End(_)) {
165
+ BoxBody::new(Full::new(first_frame.into()))
166
+ } else {
167
+ let initial_frame = tokio_stream::once(Ok(Frame::data(Bytes::from(first_frame))));
168
+ let frame_stream = unfold(
169
+ (ReceiverStream::new(receiver), shutdown_rx),
170
+ |(mut receiver, mut shutdown_rx)| async move {
171
+ if let RunningPhase::ShutdownPending = *shutdown_rx.borrow() {
172
+ return None;
173
+ }
174
+ loop {
175
+ tokio::select! {
176
+ maybe_bytes = receiver.next() => {
177
+ match maybe_bytes {
178
+ Some(ByteFrame::Data(bytes)) | Some(ByteFrame::End(bytes)) => {
179
+ return Some((Ok(Frame::data(bytes)), (receiver, shutdown_rx)));
180
+ }
181
+ _ => {
182
+ return None;
183
+ }
184
+ }
185
+ },
186
+ _ = shutdown_rx.changed() => {
187
+ match *shutdown_rx.borrow() {
188
+ RunningPhase::ShutdownPending => {
189
+ warn!("Disconnecting streaming client.");
190
+ return None;
191
+ },
192
+ _ => continue,
193
+ }
194
+ }
195
+ }
196
+ }
197
+ },
198
+ );
199
+
200
+ let combined_stream = initial_frame.chain(frame_stream);
201
+ BoxBody::new(StreamBody::new(combined_stream))
202
+ }
203
+ .with_trailers(async move {
204
+ match rx.await {
205
+ Ok(trailers) => Some(Ok(trailers)),
206
+ Err(_err) => None,
207
+ }
208
+ })
209
+ .boxed();
210
+ response
211
+ }
212
+
213
+ pub fn internal_server_error(&self, message: String) {
214
+ error!(message);
215
+ }
216
+ }