itsi 0.1.9 → 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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1542 -43
  3. data/Itsi.rb +125 -0
  4. data/Rakefile +8 -4
  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 +59 -9
  9. data/crates/itsi_server/Cargo.toml +70 -28
  10. data/crates/itsi_server/src/lib.rs +80 -80
  11. data/crates/itsi_server/src/{body_proxy → ruby_types/itsi_body_proxy}/big_bytes.rs +10 -5
  12. data/{gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs → crates/itsi_server/src/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/crates/itsi_server/src/ruby_types/itsi_http_request.rs +282 -0
  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 +29 -17
  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 +111 -11
  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 +44 -11
  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 +129 -46
  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 +325 -167
  61. data/crates/itsi_server/src/server/signal.rs +20 -4
  62. data/crates/itsi_server/src/server/static_file_server.rs +984 -0
  63. data/crates/itsi_server/src/server/thread_worker.rs +165 -88
  64. data/crates/itsi_server/src/server/tls.rs +1 -1
  65. data/crates/itsi_server/src/server/types.rs +43 -0
  66. data/crates/itsi_server/test.md +14 -0
  67. data/crates/itsi_tracing/Cargo.toml +1 -0
  68. data/crates/itsi_tracing/src/lib.rs +216 -45
  69. data/docs/.gitignore +7 -0
  70. data/docs/.gitpod.yml +15 -0
  71. data/docs/Itsi.rb +17 -0
  72. data/docs/content/_index.md +17 -0
  73. data/docs/content/about.md +6 -0
  74. data/docs/content/docs/_index.md +18 -0
  75. data/docs/content/docs/first-page.md +9 -0
  76. data/docs/content/docs/folder/_index.md +10 -0
  77. data/docs/content/docs/folder/leaf.md +7 -0
  78. data/docs/go.mod +5 -0
  79. data/docs/go.sum +2 -0
  80. data/docs/hugo.yaml +77 -0
  81. data/examples/static_assets_example.rb +83 -0
  82. data/gems/_index.md +18 -0
  83. data/gems/scheduler/CODE_OF_CONDUCT.md +7 -0
  84. data/gems/scheduler/Cargo.lock +75 -14
  85. data/gems/scheduler/README.md +5 -0
  86. data/gems/scheduler/_index.md +7 -0
  87. data/gems/scheduler/itsi-scheduler.gemspec +4 -1
  88. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  89. data/gems/scheduler/lib/itsi/scheduler.rb +2 -2
  90. data/gems/scheduler/test/test_file_io.rb +0 -1
  91. data/gems/scheduler/test/test_itsi_scheduler.rb +1 -1
  92. data/gems/server/CHANGELOG.md +5 -0
  93. data/gems/server/CODE_OF_CONDUCT.md +7 -0
  94. data/gems/server/Cargo.lock +1543 -43
  95. data/gems/server/README.md +4 -0
  96. data/gems/server/_index.md +6 -0
  97. data/gems/server/exe/itsi +46 -57
  98. data/gems/server/itsi-server.gemspec +3 -2
  99. data/gems/server/lib/itsi/{request.rb → http_request.rb} +29 -5
  100. data/gems/server/lib/itsi/http_response.rb +39 -0
  101. data/gems/server/lib/itsi/server/Itsi.rb +119 -0
  102. data/gems/server/lib/itsi/server/config/dsl.rb +506 -0
  103. data/gems/server/lib/itsi/server/config.rb +131 -0
  104. data/gems/server/lib/itsi/server/default_app/default_app.rb +38 -0
  105. data/gems/server/lib/itsi/server/grpc_interface.rb +213 -0
  106. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +9 -6
  107. data/gems/server/lib/itsi/server/rack_interface.rb +24 -9
  108. data/gems/server/lib/itsi/server/scheduler_interface.rb +1 -1
  109. data/gems/server/lib/itsi/server/scheduler_mode.rb +4 -0
  110. data/gems/server/lib/itsi/server/signal_trap.rb +6 -1
  111. data/gems/server/lib/itsi/server/version.rb +1 -1
  112. data/gems/server/lib/itsi/server.rb +75 -60
  113. data/gems/server/lib/itsi/standard_headers.rb +86 -0
  114. data/gems/server/test/helpers/test_helper.rb +14 -12
  115. data/gems/server/test/test_itsi_server.rb +21 -2
  116. data/lib/itsi/version.rb +1 -1
  117. data/sandbox/itsi_file/Gemfile +11 -0
  118. data/sandbox/itsi_file/Gemfile.lock +69 -0
  119. data/sandbox/itsi_file/Itsi.rb +276 -0
  120. data/sandbox/itsi_file/error.html +2 -0
  121. data/sandbox/itsi_file/organisations_controller.rb +20 -0
  122. data/sandbox/itsi_file/public/assets/image.png +0 -0
  123. data/sandbox/itsi_file/public/assets/index.html +1 -0
  124. data/sandbox/itsi_sandbox_async/Gemfile +1 -1
  125. data/sandbox/itsi_sandbox_hanami/Gemfile.lock +2 -2
  126. data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
  127. data/sandbox/itsi_sandbox_rack/config.ru +2 -15
  128. data/sandbox/itsi_sandbox_rails/.dockerignore +2 -5
  129. data/sandbox/itsi_sandbox_rails/.github/workflows/ci.yml +1 -1
  130. data/sandbox/itsi_sandbox_rails/.gitignore +2 -1
  131. data/sandbox/itsi_sandbox_rails/Dockerfile +6 -9
  132. data/sandbox/itsi_sandbox_rails/Gemfile +16 -22
  133. data/sandbox/itsi_sandbox_rails/Gemfile.lock +100 -225
  134. data/sandbox/itsi_sandbox_rails/app/assets/config/manifest.js +4 -0
  135. data/sandbox/itsi_sandbox_rails/app/assets/stylesheets/application.css +11 -6
  136. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/channel.rb +4 -0
  137. data/sandbox/itsi_sandbox_rails/app/channels/application_cable/connection.rb +4 -0
  138. data/sandbox/itsi_sandbox_rails/app/controllers/live_controller.rb +7 -8
  139. data/sandbox/itsi_sandbox_rails/app/controllers/uploads_controller.rb +0 -3
  140. data/sandbox/itsi_sandbox_rails/app/views/layouts/application.html.erb +2 -7
  141. data/sandbox/itsi_sandbox_rails/bin/docker-entrypoint +3 -4
  142. data/sandbox/itsi_sandbox_rails/bin/setup +8 -5
  143. data/sandbox/itsi_sandbox_rails/config/application.rb +1 -35
  144. data/sandbox/itsi_sandbox_rails/config/cable.yml +3 -10
  145. data/sandbox/itsi_sandbox_rails/config/credentials.yml.enc +1 -1
  146. data/sandbox/itsi_sandbox_rails/config/database.yml +9 -19
  147. data/sandbox/itsi_sandbox_rails/config/environment.rb +1 -1
  148. data/sandbox/itsi_sandbox_rails/config/environments/development.rb +21 -12
  149. data/sandbox/itsi_sandbox_rails/config/environments/production.rb +49 -34
  150. data/sandbox/itsi_sandbox_rails/config/environments/test.rb +19 -5
  151. data/sandbox/itsi_sandbox_rails/config/initializers/assets.rb +5 -0
  152. data/sandbox/itsi_sandbox_rails/config/initializers/filter_parameter_logging.rb +1 -1
  153. data/sandbox/itsi_sandbox_rails/config/initializers/permissions_policy.rb +13 -0
  154. data/sandbox/itsi_sandbox_rails/config/puma.rb +2 -9
  155. data/sandbox/itsi_sandbox_rails/config.ru +0 -1
  156. data/sandbox/itsi_sandbox_rails/db/migrate/20250301041554_create_posts.rb +1 -1
  157. data/sandbox/itsi_sandbox_rails/db/schema.rb +2 -2
  158. data/sandbox/itsi_sandbox_rails/lib/assets/.keep +0 -0
  159. data/sandbox/itsi_sandbox_rails/public/404.html +66 -113
  160. data/sandbox/itsi_sandbox_rails/public/406-unsupported-browser.html +65 -113
  161. data/sandbox/itsi_sandbox_rails/public/422.html +66 -113
  162. data/sandbox/itsi_sandbox_rails/public/500.html +65 -113
  163. data/sandbox/itsi_sandbox_rails/public/icon.png +0 -0
  164. data/sandbox/itsi_sandbox_rails/public/icon.svg +2 -2
  165. data/sandbox/itsi_sandbox_rails/test/channels/application_cable/connection_test.rb +13 -0
  166. data/sandbox/itsi_sandbox_roda/Gemfile.lock +3 -10
  167. data/tasks.txt +72 -12
  168. metadata +94 -139
  169. data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  170. data/crates/itsi_server/src/body_proxy/mod.rs +0 -2
  171. data/crates/itsi_server/src/request/itsi_request.rs +0 -305
  172. data/crates/itsi_server/src/request/mod.rs +0 -1
  173. data/crates/itsi_server/src/response/mod.rs +0 -1
  174. data/crates/itsi_server/src/server/itsi_server.rs +0 -294
  175. data/gems/scheduler/ext/itsi_error/Cargo.lock +0 -368
  176. data/gems/scheduler/ext/itsi_error/Cargo.toml +0 -11
  177. data/gems/scheduler/ext/itsi_error/src/from.rs +0 -68
  178. data/gems/scheduler/ext/itsi_error/src/lib.rs +0 -24
  179. data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +0 -15
  180. data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +0 -31
  181. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.lock +0 -355
  182. data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +0 -10
  183. data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  184. data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +0 -178
  185. data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +0 -24
  186. data/gems/scheduler/ext/itsi_scheduler/extconf.rb +0 -6
  187. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  188. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  189. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  190. data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  191. data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +0 -38
  192. data/gems/scheduler/ext/itsi_server/Cargo.lock +0 -2956
  193. data/gems/scheduler/ext/itsi_server/Cargo.toml +0 -47
  194. data/gems/scheduler/ext/itsi_server/extconf.rb +0 -6
  195. data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  196. data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +0 -122
  197. data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  198. data/gems/scheduler/ext/itsi_server/src/env.rs +0 -43
  199. data/gems/scheduler/ext/itsi_server/src/lib.rs +0 -112
  200. data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +0 -305
  201. data/gems/scheduler/ext/itsi_server/src/request/mod.rs +0 -1
  202. data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +0 -357
  203. data/gems/scheduler/ext/itsi_server/src/response/mod.rs +0 -1
  204. data/gems/scheduler/ext/itsi_server/src/server/bind.rs +0 -170
  205. data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  206. data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +0 -104
  207. data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +0 -294
  208. data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  209. data/gems/scheduler/ext/itsi_server/src/server/listener.rs +0 -318
  210. data/gems/scheduler/ext/itsi_server/src/server/mod.rs +0 -11
  211. data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +0 -196
  212. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  213. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  214. data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  215. data/gems/scheduler/ext/itsi_server/src/server/signal.rs +0 -77
  216. data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +0 -367
  217. data/gems/scheduler/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  218. data/gems/scheduler/ext/itsi_server/src/server/tls.rs +0 -265
  219. data/gems/scheduler/ext/itsi_tracing/Cargo.lock +0 -274
  220. data/gems/scheduler/ext/itsi_tracing/Cargo.toml +0 -16
  221. data/gems/scheduler/ext/itsi_tracing/src/lib.rs +0 -58
  222. data/gems/server/ext/itsi_error/Cargo.lock +0 -368
  223. data/gems/server/ext/itsi_error/Cargo.toml +0 -11
  224. data/gems/server/ext/itsi_error/src/from.rs +0 -68
  225. data/gems/server/ext/itsi_error/src/lib.rs +0 -24
  226. data/gems/server/ext/itsi_instrument_entry/Cargo.toml +0 -15
  227. data/gems/server/ext/itsi_instrument_entry/src/lib.rs +0 -31
  228. data/gems/server/ext/itsi_rb_helpers/Cargo.lock +0 -355
  229. data/gems/server/ext/itsi_rb_helpers/Cargo.toml +0 -10
  230. data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +0 -121
  231. data/gems/server/ext/itsi_rb_helpers/src/lib.rs +0 -178
  232. data/gems/server/ext/itsi_scheduler/Cargo.toml +0 -24
  233. data/gems/server/ext/itsi_scheduler/extconf.rb +0 -6
  234. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +0 -56
  235. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +0 -44
  236. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +0 -44
  237. data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +0 -308
  238. data/gems/server/ext/itsi_scheduler/src/lib.rs +0 -38
  239. data/gems/server/ext/itsi_server/Cargo.lock +0 -2956
  240. data/gems/server/ext/itsi_server/Cargo.toml +0 -47
  241. data/gems/server/ext/itsi_server/extconf.rb +0 -6
  242. data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +0 -104
  243. data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +0 -2
  244. data/gems/server/ext/itsi_server/src/env.rs +0 -43
  245. data/gems/server/ext/itsi_server/src/lib.rs +0 -112
  246. data/gems/server/ext/itsi_server/src/request/itsi_request.rs +0 -305
  247. data/gems/server/ext/itsi_server/src/request/mod.rs +0 -1
  248. data/gems/server/ext/itsi_server/src/response/itsi_response.rs +0 -357
  249. data/gems/server/ext/itsi_server/src/response/mod.rs +0 -1
  250. data/gems/server/ext/itsi_server/src/server/bind.rs +0 -170
  251. data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +0 -37
  252. data/gems/server/ext/itsi_server/src/server/io_stream.rs +0 -104
  253. data/gems/server/ext/itsi_server/src/server/itsi_server.rs +0 -294
  254. data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +0 -9
  255. data/gems/server/ext/itsi_server/src/server/listener.rs +0 -318
  256. data/gems/server/ext/itsi_server/src/server/mod.rs +0 -11
  257. data/gems/server/ext/itsi_server/src/server/process_worker.rs +0 -196
  258. data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +0 -254
  259. data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +0 -27
  260. data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +0 -263
  261. data/gems/server/ext/itsi_server/src/server/signal.rs +0 -77
  262. data/gems/server/ext/itsi_server/src/server/thread_worker.rs +0 -367
  263. data/gems/server/ext/itsi_server/src/server/tls/locked_dir_cache.rs +0 -132
  264. data/gems/server/ext/itsi_server/src/server/tls.rs +0 -265
  265. data/gems/server/ext/itsi_tracing/Cargo.lock +0 -274
  266. data/gems/server/ext/itsi_tracing/Cargo.toml +0 -16
  267. data/gems/server/ext/itsi_tracing/src/lib.rs +0 -58
  268. data/gems/server/lib/itsi/stream_io.rb +0 -38
  269. data/sandbox/itsi_sandbox_rails/.kamal/hooks/docker-setup.sample +0 -3
  270. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-app-boot.sample +0 -3
  271. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-deploy.sample +0 -14
  272. data/sandbox/itsi_sandbox_rails/.kamal/hooks/post-proxy-reboot.sample +0 -3
  273. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-app-boot.sample +0 -3
  274. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-build.sample +0 -51
  275. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-connect.sample +0 -47
  276. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-deploy.sample +0 -109
  277. data/sandbox/itsi_sandbox_rails/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  278. data/sandbox/itsi_sandbox_rails/.kamal/secrets +0 -17
  279. data/sandbox/itsi_sandbox_rails/bin/dev +0 -2
  280. data/sandbox/itsi_sandbox_rails/bin/jobs +0 -6
  281. data/sandbox/itsi_sandbox_rails/bin/kamal +0 -27
  282. data/sandbox/itsi_sandbox_rails/bin/thrust +0 -5
  283. data/sandbox/itsi_sandbox_rails/config/cache.yml +0 -16
  284. data/sandbox/itsi_sandbox_rails/config/deploy.yml +0 -116
  285. data/sandbox/itsi_sandbox_rails/config/queue.yml +0 -18
  286. data/sandbox/itsi_sandbox_rails/config/recurring.yml +0 -10
  287. data/sandbox/itsi_sandbox_rails/db/cable_schema.rb +0 -11
  288. data/sandbox/itsi_sandbox_rails/db/cache_schema.rb +0 -14
  289. data/sandbox/itsi_sandbox_rails/db/queue_schema.rb +0 -129
  290. data/sandbox/itsi_sandbox_rails/public/400.html +0 -114
  291. data/sandbox/itsi_sandbox_rails/test/fixtures/posts.yml +0 -9
  292. data/sandbox/itsi_sandbox_rails/test/models/post_test.rb +0 -7
  293. /data/{sandbox/itsi_sandbox_rails/script/.keep → crates/_index.md} +0 -0
  294. /data/gems/server/lib/itsi/{index.html → server/default_app/index.html} +0 -0
@@ -0,0 +1,506 @@
1
+ module Itsi
2
+ class Server
3
+ module Config
4
+ class DSL
5
+ attr_reader :parent, :children, :middleware, :controller_class, :routes, :methods, :protocols,
6
+ :hosts, :ports, :extensions, :content_types, :accepts, :options
7
+
8
+ def self.evaluate(config = Itsi::Server::Config.config_file_path)
9
+ new do
10
+ if config.is_a?(Proc)
11
+ instance_exec(&config)
12
+ else
13
+ code = IO.read(config)
14
+ instance_eval(code, config.to_s, 1)
15
+ end
16
+ end.options
17
+ end
18
+
19
+ def initialize(
20
+ parent = nil,
21
+ routes: [],
22
+ methods: [],
23
+ protocols: [],
24
+ hosts: [],
25
+ ports: [],
26
+ extensions: [],
27
+ content_types: [],
28
+ accepts: [],
29
+ controller: self,
30
+ &block
31
+ )
32
+ @parent = parent
33
+ @children = []
34
+ @middleware = {}
35
+ @controller_class = nil
36
+
37
+ @controller = controller
38
+ # We'll store our array of route specs (strings or a single Regexp).
39
+ @routes = Array(routes).flatten
40
+ @methods = methods.map { |s| s.is_a?(Regexp) ? s : s.to_s }
41
+ @protocols = protocols.map { |s| s.is_a?(Regexp) ? s : s.to_s }
42
+ @hosts = hosts.map { |s| s.is_a?(Regexp) ? s : s.to_s }
43
+ @ports = ports.map { |s| s.is_a?(Regexp) ? s : s.to_s }
44
+ @extensions = extensions.map { |s| s.is_a?(Regexp) ? s : s.to_s }
45
+ @content_types = content_types.map { |s| s.is_a?(Regexp) ? s : s.to_s }
46
+ @accepts = accepts.map { |s| s.is_a?(Regexp) ? s : s.to_s }
47
+
48
+ @options = {
49
+ middleware_loaders: [],
50
+ middleware_loader: lambda do
51
+ @options[:middleware_loaders].each(&:call)
52
+ flatten_routes
53
+ end
54
+ }
55
+
56
+ instance_exec(&block)
57
+ end
58
+
59
+
60
+ def workers(workers)
61
+ raise "Workers must be set at the root" unless @parent.nil?
62
+
63
+ @options[:workers] = [workers.to_i, 1].max
64
+ end
65
+
66
+ def threads(threads)
67
+ raise "Threads must be set at the root" unless @parent.nil?
68
+
69
+ @options[:threads] = [threads.to_i, 1].max
70
+ end
71
+
72
+ def oob_gc_responses_threshold(threshold)
73
+ raise "OOB GC responses threshold must be set at the root" unless @parent.nil?
74
+
75
+ @options[:oob_gc_responses_threshold] = threshold.to_i
76
+ end
77
+
78
+ def log_level(level)
79
+ raise "Log level must be set at the root" unless @parent.nil?
80
+
81
+ @options[:log_level] = level.to_s
82
+ end
83
+
84
+ def log_format(format)
85
+ raise "Log format must be set at the root" unless @parent.nil?
86
+
87
+ case format.to_s
88
+ when "auto" then nil
89
+ when "ansi" then ENV["ITSI_LOG_ANSI"] = "true"
90
+ when "json", "plain" then ENV["ITSI_LOG_PLAIN"] = "true"
91
+ else raise "Invalid log format '#{format}'"
92
+ end
93
+ end
94
+
95
+ def get(route, app_proc = nil, &blk)
96
+ endpoint(route, :get, app_proc, &blk)
97
+ end
98
+
99
+ def post(route, app_proc = nil, &blk)
100
+ endpoint(route, :post, app_proc, &blk)
101
+ end
102
+
103
+ def put(route, app_proc = nil, &blk)
104
+ endpoint(route, :put, app_proc, &blk)
105
+ end
106
+
107
+ def delete(route, app_proc = nil, &blk)
108
+ endpoint(route, :delete, app_proc, &blk)
109
+ end
110
+
111
+ def patch(route, app_proc = nil, &blk)
112
+ endpoint(route, :patch, app_proc, &blk)
113
+ end
114
+
115
+ def endpoint(route, method, app_proc = nil, &blk)
116
+ raise "You can't use both a block and an explicit handler in the same endpoint" if blk && app_proc
117
+ raise "You must provide either a block or an explicit handler for the endpoint" if app_proc.nil? && blk.nil?
118
+
119
+ app_proc = @controller.method(app_proc).to_proc if app_proc.is_a?(Symbol)
120
+
121
+ app_proc ||= blk
122
+
123
+ location(route, methods: [method]) do
124
+ @middleware[:app] = { app_proc: app_proc }
125
+ end
126
+ end
127
+
128
+ def grpc(handler, **)
129
+ if @middleware[:app] && @middleware[:app][:request_type].to_s != "grpc"
130
+ raise "App has already been set. You can use only one of `run` and `rackup_file` or `grpc` per location"
131
+ end
132
+
133
+ @middleware[:app] ||= {
134
+ request_type: "grpc",
135
+ impls: []
136
+ }
137
+ @middleware[:app][:impls] << handler
138
+ @middleware[:app][:app_proc] = Itsi::Server::GrpcInterface.for(@middleware[:app][:impls])
139
+ end
140
+
141
+ def run(app, sendfile: true)
142
+ if @options[:app_loader]
143
+ raise "App has already been set. You can use only one of `run` and `rackup_file` per location"
144
+ end
145
+
146
+ if @parent.nil?
147
+ @options[:app_loader] = -> { { "app_proc" => Itsi::Server::RackInterface.for(app) } }
148
+ else
149
+ @middleware[:app] = { app_proc: Itsi::Server::RackInterface.for(app), sendfile: sendfile }
150
+ end
151
+ end
152
+
153
+ def rackup_file(rackup_file)
154
+ if @options[:app_loader]
155
+ raise "App has already been set. You can use only one of `run` and `rackup_file` per location"
156
+ end
157
+
158
+ raise "Rackup file #{rackup_file} doesn't exist" unless File.exist?(rackup_file)
159
+
160
+ if @parent.nil?
161
+ @options[:app_loader] = -> { { "app_proc" => Itsi::Server::RackInterface.for(rackup_file) } }
162
+ else
163
+ @middleware[:app] = { app_proc: Itsi::Server::RackInterface.for(rackup_file) }
164
+ end
165
+ end
166
+
167
+ def include(path)
168
+ code = IO.read("#{path}.rb")
169
+ instance_eval(code, "#{path}.rb", 1)
170
+ end
171
+
172
+ def bind(bind_str)
173
+ raise "Bind must be set at the root" unless @parent.nil?
174
+
175
+ @options[:binds] ||= []
176
+ @options[:binds] << bind_str.to_s
177
+ end
178
+
179
+ def after_fork(&block)
180
+ raise "After fork must be set at the root" unless @parent.nil?
181
+
182
+ @options[:hooks] ||= {}
183
+ @options[:hooks][:after_fork] = block
184
+ end
185
+
186
+ def before_fork(&block)
187
+ raise "Before fork must be set at the root" unless @parent.nil?
188
+
189
+ @options[:hooks] ||= {}
190
+ @options[:hooks][:before_fork] = block
191
+ end
192
+
193
+ def after_memory_threshold_reached(&block)
194
+ raise "Before fork must be set at the root" unless @parent.nil?
195
+
196
+ @options[:hooks] ||= {}
197
+ @options[:hooks][:after_memory_threshold_reached] = block
198
+ end
199
+
200
+ def worker_memory_limit(memory_limit)
201
+ raise "Worker memory limit must be set at the root" unless @parent.nil?
202
+
203
+ @options[:worker_memory_limit] = memory_limit
204
+ end
205
+
206
+ def multithreaded_reactor(multithreaded)
207
+ raise "Multithreaded reactor must be set at the root" unless @parent.nil?
208
+
209
+ @options[:multithreaded_reactor] = !!multithreaded
210
+ end
211
+
212
+ def watch(path, commands)
213
+ raise "Watch be set at the root" unless @parent.nil?
214
+
215
+ @options[:notify_watchers] ||= []
216
+ @options[:notify_watchers] << [path, commands]
217
+ end
218
+
219
+ def fiber_scheduler(klass_name = true)
220
+ raise "Fiber scheduler must be set at the root" unless @parent.nil?
221
+
222
+ klass_name = "Itsi::Scheduler" if klass_name == true
223
+ @options[:scheduler_class] = klass_name if klass_name
224
+ end
225
+
226
+ def preload(preload)
227
+ raise "Preload must be set at the root" unless @parent.nil?
228
+
229
+ @options[:preload] = preload
230
+ end
231
+
232
+ def shutdown_timeout(shutdown_timeout)
233
+ raise "Shutdown timeout must be set at the root" unless @parent.nil?
234
+
235
+ @options[:shutdown_timeout] = shutdown_timeout.to_f
236
+ end
237
+
238
+ def script_name(script_name)
239
+ raise "Script name must be set at the root" unless @parent.nil?
240
+
241
+ @options[:script_name] = script_name.to_s
242
+ end
243
+
244
+ def stream_body(stream_body)
245
+ raise "Stream body must be set at the root" unless @parent.nil?
246
+
247
+ @options[:stream_body] = !!stream_body
248
+ end
249
+
250
+ def location(*routes, methods: [], protocols: [], hosts: [], ports: [], extensions: [], content_types: [],
251
+ accepts: [], &block)
252
+ build_child = lambda {
253
+ @children << DSL.new(
254
+ self,
255
+ routes: routes,
256
+ methods: Array(methods) | self.methods,
257
+ protocols: Array(protocols) | self.protocols,
258
+ hosts: Array(hosts) | self.hosts,
259
+ ports: Array(ports) | self.ports,
260
+ extensions: Array(extensions) | self.extensions,
261
+ content_types: Array(content_types) | self.content_types,
262
+ accepts: Array(accepts) | self.accepts,
263
+ controller: @controller,
264
+ &block
265
+ )
266
+ }
267
+ if @parent.nil?
268
+ @options[:middleware_loaders] << build_child
269
+ else
270
+ build_child[]
271
+ end
272
+ end
273
+
274
+ def log_requests(**args)
275
+ @middleware[:log_requests] = args
276
+ end
277
+
278
+ def allow_list(**args)
279
+ args[:allowed_patterns] = Array(args[:allowed_patterns]).map do |pattern|
280
+ if pattern.is_a?(Regexp)
281
+ pattern.source
282
+ else
283
+ pattern
284
+ end
285
+ end
286
+ @middleware[:allow_list] = args
287
+ end
288
+
289
+ def deny_list(**args)
290
+ args[:denied_patterns] = Array(args[:denied_patterns]).map do |pattern|
291
+ if pattern.is_a?(Regexp)
292
+ pattern.source
293
+ else
294
+ pattern
295
+ end
296
+ end
297
+ @middleware[:deny_list] = args
298
+ end
299
+
300
+ def controller(controller)
301
+ raise "`controller` must be set inside a location block" if @parent.nil?
302
+
303
+ @controller = controller
304
+ end
305
+
306
+ def auth_basic(**args)
307
+ raise "`auth_basic` must be set inside a location block" if @parent.nil?
308
+
309
+ @middleware[:auth_basic] = args
310
+ end
311
+
312
+ def redirect(**args)
313
+ raise "`redirect` must be set inside a location block" if @parent.nil?
314
+
315
+ @middleware[:redirect] = args
316
+ end
317
+
318
+ def proxy(**args)
319
+ raise "`proxy` must be set inside a location block" if @parent.nil?
320
+
321
+ @middleware[:proxy] = args
322
+ end
323
+
324
+ def auth_jwt(**args)
325
+ raise "`auth_jwt` must be set inside a location block" if @parent.nil?
326
+
327
+ @middleware[:auth_jwt] = args
328
+ end
329
+
330
+ def auth_api_key(**args)
331
+ raise "`auth_api_key` must be set inside a location block" if @parent.nil?
332
+
333
+ @middleware[:auth_api_key] = args
334
+ end
335
+
336
+ def compress(**args)
337
+ raise "`compress` must be set inside a location block" if @parent.nil?
338
+
339
+ @middleware[:compression] = args
340
+ end
341
+
342
+ def request_headers(**args)
343
+ raise "`request_headers` must be set inside a location block" if @parent.nil?
344
+
345
+ @middleware[:request_headers] = args
346
+ end
347
+
348
+ def response_headers(**args)
349
+ raise "`response_headers` must be set inside a location block" if @parent.nil?
350
+
351
+ @middleware[:response_headers] = args
352
+ end
353
+
354
+ def rate_limit(**args)
355
+ raise "`rate_limit` must be set inside a location block" if @parent.nil?
356
+
357
+ @middleware[:rate_limit] = args
358
+ end
359
+
360
+ def cache_control(**args)
361
+ raise "`cache_control` must be set inside a location block" if @parent.nil?
362
+
363
+ @middleware[:cache_control] = args
364
+ end
365
+
366
+ def etag(**args)
367
+ raise "`etag` must be set inside a location block" if @parent.nil?
368
+
369
+ @middleware[:etag] = args
370
+ end
371
+
372
+ def intrusion_protection(**args)
373
+ raise "`intrusion_protection` must be set inside a location block" if @parent.nil?
374
+
375
+ args[:banned_url_patterns] = Array(args[:banned_url_patterns]).map do |pattern|
376
+ if pattern.is_a?(Regexp)
377
+ pattern.source
378
+ else
379
+ pattern
380
+ end
381
+ end
382
+ @middleware[:intrusion_protection] = args
383
+ end
384
+
385
+ def cors(**args)
386
+ raise "`cors` must be set inside a location block" if @parent.nil?
387
+
388
+ @middleware[:cors] = args
389
+ end
390
+
391
+ def static_assets(**args)
392
+ raise "`static_assets` must be set inside a location block" if @parent.nil?
393
+
394
+ root_dir = args[:root_dir] || "."
395
+
396
+ if !File.exist?(root_dir)
397
+ warn "Warning: static_assets root_dir '#{root_dir}' does not exist!"
398
+ elsif !File.directory?(root_dir)
399
+ warn "Warning: static_assets root_dir '#{root_dir}' is not a directory!"
400
+ end
401
+
402
+ args[:relative_path] = true unless args.key?(:relative_path)
403
+
404
+ location(/(?<path_suffix>.*)/, extensions: args[:allowed_extensions] || []) do
405
+ @middleware[:static_assets] = args
406
+ end
407
+ end
408
+
409
+ def file_server(**args)
410
+ raise "`file_server` must be set inside a location block" if @parent.nil?
411
+
412
+ # Forward to static_assets for implementation
413
+ puts "Note: file_server is an alias for static_assets"
414
+ static_assets(**args)
415
+ end
416
+
417
+ def flatten_routes
418
+ result = []
419
+ result.concat(@children.flat_map(&:flatten_routes))
420
+ route_options = paths_from_parent
421
+ if route_options
422
+ result << deep_stringify_keys(
423
+ {
424
+ route: Regexp.new("^#{route_options}$"),
425
+ methods: @methods.any? ? @methods : nil,
426
+ protocols: @protocols.any? ? @protocols : nil,
427
+ hosts: @hosts.any? ? @hosts : nil,
428
+ ports: @ports.any? ? @ports : nil,
429
+ extensions: @extensions.any? ? @extensions : nil,
430
+ content_types: @content_types.any? ? @content_types : nil,
431
+ accepts: @accepts.any? ? @accepts : nil,
432
+ middleware: effective_middleware
433
+ }
434
+ )
435
+ end
436
+ result
437
+ end
438
+
439
+ def paths_from_parent
440
+ return nil unless @routes.any?
441
+
442
+ route_or_str = @routes.map do |seg|
443
+ case seg
444
+ when Regexp
445
+ seg.source
446
+ when /^:([A-Za-z_]\w*)(?:\(([^)]*)\))?$/
447
+ param_name = Regexp.last_match(1)
448
+ custom = Regexp.last_match(2)
449
+ if custom && !custom.empty?
450
+ "(?<#{param_name}>#{custom})"
451
+ else
452
+ "(?<#{param_name}>[^/]+)"
453
+ end
454
+ when /\*/
455
+ seg.gsub(/\*/, ".*")
456
+ else
457
+ Regexp.escape(seg).gsub(%r{/$}, ".*")
458
+ end
459
+ end.join("|")
460
+
461
+ if parent.paths_from_parent && parent.paths_from_parent != "(?:/.*)"
462
+ "#{parent.paths_from_parent}#{route_or_str != "" ? "(?:#{route_or_str})" : ""}"
463
+ else
464
+ route_or_str = "/#{route_or_str}" unless route_or_str.start_with?("/")
465
+ "(?:#{route_or_str})"
466
+ end
467
+ end
468
+
469
+ def effective_middleware
470
+ merged = merge_ancestor_middleware
471
+ merged.map { |k, v| { type: k.to_s, parameters: v } }
472
+ end
473
+
474
+ def merge_ancestor_middleware
475
+ chain = []
476
+ node = self
477
+ while node
478
+ chain << node
479
+ node = node.parent
480
+ end
481
+ chain.reverse!
482
+
483
+ merged = {}
484
+ chain.each do |n|
485
+ n.middleware.each do |k, v|
486
+ merged[k] = v
487
+ end
488
+ end
489
+ merged
490
+ end
491
+
492
+ def deep_stringify_keys(obj)
493
+ case obj
494
+ when Hash
495
+ obj.transform_keys!(&:to_s)
496
+ obj.transform_values! { |v| deep_stringify_keys(v) }
497
+ when Array
498
+ obj.map { |v| deep_stringify_keys(v) }
499
+ else
500
+ obj
501
+ end
502
+ end
503
+ end
504
+ end
505
+ end
506
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Itsi
4
+ class Server
5
+ module Config
6
+ require_relative "config/dsl"
7
+ require_relative "default_app/default_app"
8
+ require "debug"
9
+
10
+ ITSI_DEFAULT_CONFIG_FILE = "Itsi.rb"
11
+
12
+ def self.save_argv!
13
+ @argv ||= ARGV[0...ARGV.index("--listeners")]
14
+ end
15
+
16
+ # The configuration used when launching the Itsi server are evaluated in the following precedence:
17
+ # 1. CLI Args.
18
+ # 2. Itsi.rb file.
19
+ # 3. Default values.
20
+ def self.build_config(args, config_file_path, builder_proc)
21
+ itsifile_config = \
22
+ if builder_proc
23
+ DSL.evaluate(builder_proc)
24
+ elsif File.exist?(config_file_path.to_s)
25
+ DSL.evaluate(config_file_path)
26
+ else
27
+ {}
28
+ end
29
+ args.transform_keys!(&:to_sym)
30
+ itsifile_config.transform_keys!(&:to_sym)
31
+
32
+ # We'll preload while we load config, if enabled.
33
+ middleware_loader = itsifile_config.fetch(:middleware_loader, -> {})
34
+ default_app_loader = itsifile_config.fetch(:app_loader) do
35
+ rackup_file_path = args.fetch(:rackup_file, "./config.ru")
36
+ if File.exist?(rackup_file_path)
37
+ lambda {
38
+ { "app_proc" => Itsi::Server::RackInterface.for(rackup_file_path) }
39
+ }
40
+ else
41
+ DEFAULT_APP
42
+ end
43
+ end
44
+ preload = args.fetch(:preload) { itsifile_config.fetch(:preload, false) }
45
+
46
+ case preload
47
+ # If we preload everything, then we'll load middleware and default rack app ahead of time
48
+ when true
49
+ preloaded_middleware = middleware_loader.call
50
+ preloaded_app = default_app_loader.call
51
+ middleware_loader = -> { preloaded_middleware }
52
+ default_app_loader = -> { preloaded_app }
53
+ # If we're just preloading a specific gem group, we'll do that here too
54
+ when Symbol
55
+ Bundler.require(preload)
56
+ end
57
+
58
+ {
59
+ workers: args.fetch(:workers) { itsifile_config.fetch(:workers, Etc.nprocessors) },
60
+ worker_memory_limit: args.fetch(:worker_memory_limit) { itsifile_config.fetch(:worker_memory_limit, nil) },
61
+ silence: args.fetch(:silence) { itsifile_config.fetch(:silence, false) },
62
+ shutdown_timeout: args.fetch(:shutdown_timeout) { itsifile_config.fetch(:shutdown_timeout, 5) },
63
+ hooks: itsifile_config.fetch(:hooks, nil),
64
+ preload: !!preload,
65
+ notify_watchers: itsifile_config.fetch(:notify_watchers, nil),
66
+ threads: args.fetch(:threads) { itsifile_config.fetch(:threads, 1) },
67
+ script_name: args.fetch(:script_name) { itsifile_config.fetch(:script_name, "") },
68
+ streamable_body: args.fetch(:streamable_body) { itsifile_config.fetch(:streamable_body, false) },
69
+ multithreaded_reactor: args.fetch(:multithreaded_reactor) do
70
+ itsifile_config.fetch(:multithreaded_reactor, true)
71
+ end,
72
+ scheduler_class: args.fetch(:scheduler_class) { itsifile_config.fetch(:scheduler_class, nil) },
73
+ oob_gc_responses_threshold: args.fetch(:oob_gc_responses_threshold) do
74
+ itsifile_config.fetch(:oob_gc_responses_threshold, nil)
75
+ end,
76
+ log_level: args.fetch(:log_level) { itsifile_config.fetch(:log_level, nil) },
77
+ binds: args.fetch(:binds) { itsifile_config.fetch(:binds, ["http://0.0.0.0:3000"]) },
78
+ middleware_loader: middleware_loader,
79
+ default_app_loader: default_app_loader,
80
+ listeners: args.fetch(:listeners) { nil }
81
+ }.transform_keys(&:to_s)
82
+ end
83
+
84
+ # Reloads the entire process
85
+ # using exec, passing in any active file descriptors
86
+ # and previous invocation arguments
87
+ def self.reload_exec(listener_info)
88
+ if ENV["BUNDLE_BIN_PATH"]
89
+ exec "bundle", "exec", $PROGRAM_NAME, *@argv, "--listeners", listener_info
90
+ else
91
+ exec $PROGRAM_NAME, *@argv, "--listeners", listener_info
92
+ end
93
+ end
94
+
95
+ # Find config file path, if it exists.
96
+ def self.config_file_path(config_file_path = nil)
97
+ config_file_path ||= \
98
+ if File.exist?(ITSI_DEFAULT_CONFIG_FILE)
99
+ ITSI_DEFAULT_CONFIG_FILE
100
+ elsif File.exist?("config/#{ITSI_DEFAULT_CONFIG_FILE}")
101
+ "config/#{ITSI_DEFAULT_CONFIG_FILE}"
102
+ end
103
+ # Options simply pass through unless we've specified a config file
104
+ return unless File.exist?(config_file_path.to_s)
105
+
106
+ config_file_path
107
+ end
108
+
109
+ def self.pid_file_path
110
+ if Dir.exist?("tmp")
111
+ File.join("tmp", "itsi.pid")
112
+ else
113
+ ".itsi.pid"
114
+ end
115
+ end
116
+
117
+ # Write a default config file, if one doesn't exist.
118
+ def self.write_default
119
+ if File.exist?(ITSI_DEFAULT_CONFIG_FILE)
120
+ puts "#{ITSI_DEFAULT_CONFIG_FILE} already exists."
121
+ return
122
+ end
123
+
124
+ puts "Writing default configuration..."
125
+ File.open(ITSI_DEFAULT_CONFIG_FILE, "w") do |file|
126
+ file.write(IO.read("#{__dir__}/Itsi.rb"))
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,38 @@
1
+ # When you Run Itsi without a Rack app,
2
+ # we start a tiny little echo server, just so you can see it in action.
3
+ DEFAULT_INDEX = IO.read("#{__dir__}/index.html").freeze
4
+ DEFAULT_BINDS = ["http://0.0.0.0:3000"].freeze
5
+ DEFAULT_APP = lambda {
6
+ require "json"
7
+ require "itsi/scheduler"
8
+ Itsi.log_warn "No config.ru or Itsi.rb app detected. Running default app."
9
+ {
10
+ "app_proc" => Itsi::Server::RackInterface.for(lambda do |env|
11
+ headers, body = \
12
+ if env["itsi.response"].json?
13
+ [
14
+ { "Content-Type" => "application/json" },
15
+ [{ "message" => "You're running on Itsi!", "rack_env" => env,
16
+ "version" => Itsi::Server::VERSION }.to_json]
17
+ ]
18
+ else
19
+ [
20
+ { "Content-Type" => "text/html" },
21
+ [
22
+ format(
23
+ DEFAULT_INDEX,
24
+ REQUEST_METHOD: env["REQUEST_METHOD"],
25
+ PATH_INFO: env["PATH_INFO"],
26
+ SERVER_NAME: env["SERVER_NAME"],
27
+ SERVER_PORT: env["SERVER_PORT"],
28
+ REMOTE_ADDR: env["REMOTE_ADDR"],
29
+ HTTP_USER_AGENT: env["HTTP_USER_AGENT"]
30
+ )
31
+ ]
32
+ ]
33
+ end
34
+ [200, headers, body]
35
+ end)
36
+ }
37
+
38
+ }