itsi 0.2.16 → 0.2.17

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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/Cargo.lock +4 -2
  4. data/crates/itsi_acme/Cargo.toml +1 -1
  5. data/crates/itsi_scheduler/Cargo.toml +1 -1
  6. data/crates/itsi_server/Cargo.toml +3 -1
  7. data/crates/itsi_server/src/lib.rs +6 -1
  8. data/crates/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +2 -0
  9. data/crates/itsi_server/src/ruby_types/itsi_grpc_call.rs +4 -4
  10. data/crates/itsi_server/src/ruby_types/itsi_grpc_response_stream/mod.rs +14 -13
  11. data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +64 -33
  12. data/crates/itsi_server/src/ruby_types/itsi_http_response.rs +151 -152
  13. data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +6 -15
  14. data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +26 -5
  15. data/crates/itsi_server/src/ruby_types/itsi_server.rs +1 -1
  16. data/crates/itsi_server/src/server/binds/listener.rs +45 -7
  17. data/crates/itsi_server/src/server/frame_stream.rs +142 -0
  18. data/crates/itsi_server/src/server/http_message_types.rs +142 -9
  19. data/crates/itsi_server/src/server/io_stream.rs +28 -5
  20. data/crates/itsi_server/src/server/lifecycle_event.rs +1 -1
  21. data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +2 -3
  22. data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +8 -10
  23. data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +2 -3
  24. data/crates/itsi_server/src/server/middleware_stack/middlewares/csp.rs +3 -3
  25. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +54 -56
  26. data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +5 -7
  27. data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +5 -5
  28. data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +7 -10
  29. data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +2 -3
  30. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +1 -2
  31. data/crates/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +4 -6
  32. data/crates/itsi_server/src/server/mod.rs +1 -0
  33. data/crates/itsi_server/src/server/process_worker.rs +3 -4
  34. data/crates/itsi_server/src/server/serve_strategy/acceptor.rs +16 -12
  35. data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +87 -31
  36. data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +158 -142
  37. data/crates/itsi_server/src/server/signal.rs +37 -9
  38. data/crates/itsi_server/src/server/thread_worker.rs +84 -69
  39. data/crates/itsi_server/src/services/itsi_http_service.rs +43 -43
  40. data/crates/itsi_server/src/services/static_file_server.rs +28 -47
  41. data/docs/benchmark-dashboard/.gitignore +27 -0
  42. data/docs/benchmark-dashboard/app/api/benchmarks/route.ts +22 -0
  43. data/docs/benchmark-dashboard/app/globals.css +94 -0
  44. data/docs/benchmark-dashboard/app/layout.tsx +20 -0
  45. data/docs/benchmark-dashboard/app/page.tsx +252 -0
  46. data/docs/benchmark-dashboard/components/benchmark-dashboard.tsx +1663 -0
  47. data/docs/benchmark-dashboard/components/theme-provider.tsx +11 -0
  48. data/docs/benchmark-dashboard/components/ui/accordion.tsx +58 -0
  49. data/docs/benchmark-dashboard/components/ui/alert-dialog.tsx +141 -0
  50. data/docs/benchmark-dashboard/components/ui/alert.tsx +59 -0
  51. data/docs/benchmark-dashboard/components/ui/aspect-ratio.tsx +7 -0
  52. data/docs/benchmark-dashboard/components/ui/avatar.tsx +50 -0
  53. data/docs/benchmark-dashboard/components/ui/badge.tsx +36 -0
  54. data/docs/benchmark-dashboard/components/ui/breadcrumb.tsx +115 -0
  55. data/docs/benchmark-dashboard/components/ui/button.tsx +56 -0
  56. data/docs/benchmark-dashboard/components/ui/calendar.tsx +66 -0
  57. data/docs/benchmark-dashboard/components/ui/card.tsx +79 -0
  58. data/docs/benchmark-dashboard/components/ui/carousel.tsx +262 -0
  59. data/docs/benchmark-dashboard/components/ui/chart.tsx +365 -0
  60. data/docs/benchmark-dashboard/components/ui/checkbox.tsx +30 -0
  61. data/docs/benchmark-dashboard/components/ui/collapsible.tsx +11 -0
  62. data/docs/benchmark-dashboard/components/ui/command.tsx +153 -0
  63. data/docs/benchmark-dashboard/components/ui/context-menu.tsx +200 -0
  64. data/docs/benchmark-dashboard/components/ui/dialog.tsx +122 -0
  65. data/docs/benchmark-dashboard/components/ui/drawer.tsx +118 -0
  66. data/docs/benchmark-dashboard/components/ui/dropdown-menu.tsx +200 -0
  67. data/docs/benchmark-dashboard/components/ui/form.tsx +178 -0
  68. data/docs/benchmark-dashboard/components/ui/hover-card.tsx +29 -0
  69. data/docs/benchmark-dashboard/components/ui/input-otp.tsx +71 -0
  70. data/docs/benchmark-dashboard/components/ui/input.tsx +22 -0
  71. data/docs/benchmark-dashboard/components/ui/label.tsx +26 -0
  72. data/docs/benchmark-dashboard/components/ui/loading-spinner.tsx +12 -0
  73. data/docs/benchmark-dashboard/components/ui/menubar.tsx +236 -0
  74. data/docs/benchmark-dashboard/components/ui/navigation-menu.tsx +128 -0
  75. data/docs/benchmark-dashboard/components/ui/pagination.tsx +117 -0
  76. data/docs/benchmark-dashboard/components/ui/popover.tsx +31 -0
  77. data/docs/benchmark-dashboard/components/ui/progress.tsx +28 -0
  78. data/docs/benchmark-dashboard/components/ui/radio-group.tsx +44 -0
  79. data/docs/benchmark-dashboard/components/ui/resizable.tsx +45 -0
  80. data/docs/benchmark-dashboard/components/ui/scroll-area.tsx +48 -0
  81. data/docs/benchmark-dashboard/components/ui/select.tsx +160 -0
  82. data/docs/benchmark-dashboard/components/ui/separator.tsx +31 -0
  83. data/docs/benchmark-dashboard/components/ui/sheet.tsx +140 -0
  84. data/docs/benchmark-dashboard/components/ui/sidebar.tsx +763 -0
  85. data/docs/benchmark-dashboard/components/ui/skeleton.tsx +15 -0
  86. data/docs/benchmark-dashboard/components/ui/slider.tsx +28 -0
  87. data/docs/benchmark-dashboard/components/ui/sonner.tsx +31 -0
  88. data/docs/benchmark-dashboard/components/ui/switch.tsx +29 -0
  89. data/docs/benchmark-dashboard/components/ui/table.tsx +117 -0
  90. data/docs/benchmark-dashboard/components/ui/tabs.tsx +55 -0
  91. data/docs/benchmark-dashboard/components/ui/textarea.tsx +22 -0
  92. data/docs/benchmark-dashboard/components/ui/toast.tsx +129 -0
  93. data/docs/benchmark-dashboard/components/ui/toaster.tsx +35 -0
  94. data/docs/benchmark-dashboard/components/ui/toggle-group.tsx +61 -0
  95. data/docs/benchmark-dashboard/components/ui/toggle.tsx +45 -0
  96. data/docs/benchmark-dashboard/components/ui/tooltip.tsx +30 -0
  97. data/docs/benchmark-dashboard/components/ui/use-mobile.tsx +19 -0
  98. data/docs/benchmark-dashboard/components/ui/use-toast.ts +194 -0
  99. data/docs/benchmark-dashboard/components.json +21 -0
  100. data/docs/benchmark-dashboard/dist/benchmark-dashboard.css +1 -0
  101. data/docs/benchmark-dashboard/dist/benchmark-dashboard.iife.js +211 -0
  102. data/docs/benchmark-dashboard/dist/placeholder-logo.png +0 -0
  103. data/docs/benchmark-dashboard/dist/placeholder-logo.svg +1 -0
  104. data/docs/benchmark-dashboard/dist/placeholder-user.jpg +0 -0
  105. data/docs/benchmark-dashboard/dist/placeholder.jpg +0 -0
  106. data/docs/benchmark-dashboard/dist/placeholder.svg +1 -0
  107. data/docs/benchmark-dashboard/embed.tsx +13 -0
  108. data/docs/benchmark-dashboard/hooks/use-mobile.tsx +19 -0
  109. data/docs/benchmark-dashboard/hooks/use-toast.ts +194 -0
  110. data/docs/benchmark-dashboard/lib/benchmark-utils.ts +54 -0
  111. data/docs/benchmark-dashboard/lib/utils.ts +6 -0
  112. data/docs/benchmark-dashboard/next.config.mjs +14 -0
  113. data/docs/benchmark-dashboard/package-lock.json +5859 -0
  114. data/docs/benchmark-dashboard/package.json +72 -0
  115. data/docs/benchmark-dashboard/pnpm-lock.yaml +5 -0
  116. data/docs/benchmark-dashboard/postcss.config.mjs +8 -0
  117. data/docs/benchmark-dashboard/styles/globals.css +94 -0
  118. data/docs/benchmark-dashboard/tailwind.config.ts +96 -0
  119. data/docs/benchmark-dashboard/tsconfig.json +27 -0
  120. data/docs/benchmark-dashboard/vite.config.ts +24 -0
  121. data/docs/build.rb +52 -0
  122. data/docs/content/benchmarks/index.md +96 -0
  123. data/docs/content/getting_started/_index.md +76 -46
  124. data/docs/hugo.yaml +3 -0
  125. data/docs/static/results.json +1 -0
  126. data/docs/static/scripts/benchmark-dashboard.iife.js +211 -0
  127. data/docs/static/styles/benchmark-dashboard.css +1 -0
  128. data/gems/scheduler/Cargo.lock +1 -1
  129. data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
  130. data/gems/server/Cargo.lock +3 -1
  131. data/gems/server/exe/itsi +6 -1
  132. data/gems/server/lib/itsi/http_request.rb +31 -39
  133. data/gems/server/lib/itsi/http_response.rb +5 -0
  134. data/gems/server/lib/itsi/rack_env_pool.rb +59 -0
  135. data/gems/server/lib/itsi/server/config/dsl.rb +5 -4
  136. data/gems/server/lib/itsi/server/config/middleware/proxy.rb +1 -1
  137. data/gems/server/lib/itsi/server/config/middleware/rackup_file.rb +2 -2
  138. data/gems/server/lib/itsi/server/config/options/auto_reload_config.rb +6 -2
  139. data/gems/server/lib/itsi/server/config/options/include.rb +5 -2
  140. data/gems/server/lib/itsi/server/config/options/pipeline_flush.md +16 -0
  141. data/gems/server/lib/itsi/server/config/options/pipeline_flush.rb +19 -0
  142. data/gems/server/lib/itsi/server/config/options/writev.md +25 -0
  143. data/gems/server/lib/itsi/server/config/options/writev.rb +19 -0
  144. data/gems/server/lib/itsi/server/config.rb +21 -8
  145. data/gems/server/lib/itsi/server/default_config/Itsi.rb +1 -4
  146. data/gems/server/lib/itsi/server/grpc/grpc_call.rb +2 -0
  147. data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +2 -2
  148. data/gems/server/lib/itsi/server/rack/handler/itsi.rb +3 -1
  149. data/gems/server/lib/itsi/server/rack_interface.rb +17 -12
  150. data/gems/server/lib/itsi/server/scheduler_interface.rb +2 -0
  151. data/gems/server/lib/itsi/server/version.rb +1 -1
  152. data/gems/server/lib/itsi/server.rb +1 -0
  153. data/gems/server/lib/ruby_lsp/itsi/addon.rb +12 -13
  154. data/gems/server/test/helpers/test_helper.rb +12 -13
  155. data/gems/server/test/middleware/grpc/grpc.rb +13 -14
  156. data/gems/server/test/middleware/grpc/test_service_impl.rb +3 -3
  157. data/gems/server/test/middleware/proxy.rb +262 -268
  158. data/lib/itsi/version.rb +1 -1
  159. metadata +96 -6
  160. data/tasks.txt +0 -28
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import { BenchmarkDashboard } from "@/components/benchmark-dashboard";
4
+ import "@/styles/globals.css";
5
+
6
+ const root = document.getElementById("root");
7
+ if (root) {
8
+ fetch("/results.json")
9
+ .then((res) => res.json())
10
+ .then((data) => {
11
+ ReactDOM.createRoot(root).render(<BenchmarkDashboard data={data} />);
12
+ });
13
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener("change", onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener("change", onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
@@ -0,0 +1,194 @@
1
+ "use client"
2
+
3
+ // Inspired by react-hot-toast library
4
+ import * as React from "react"
5
+
6
+ import type {
7
+ ToastActionElement,
8
+ ToastProps,
9
+ } from "@/components/ui/toast"
10
+
11
+ const TOAST_LIMIT = 1
12
+ const TOAST_REMOVE_DELAY = 1000000
13
+
14
+ type ToasterToast = ToastProps & {
15
+ id: string
16
+ title?: React.ReactNode
17
+ description?: React.ReactNode
18
+ action?: ToastActionElement
19
+ }
20
+
21
+ const actionTypes = {
22
+ ADD_TOAST: "ADD_TOAST",
23
+ UPDATE_TOAST: "UPDATE_TOAST",
24
+ DISMISS_TOAST: "DISMISS_TOAST",
25
+ REMOVE_TOAST: "REMOVE_TOAST",
26
+ } as const
27
+
28
+ let count = 0
29
+
30
+ function genId() {
31
+ count = (count + 1) % Number.MAX_SAFE_INTEGER
32
+ return count.toString()
33
+ }
34
+
35
+ type ActionType = typeof actionTypes
36
+
37
+ type Action =
38
+ | {
39
+ type: ActionType["ADD_TOAST"]
40
+ toast: ToasterToast
41
+ }
42
+ | {
43
+ type: ActionType["UPDATE_TOAST"]
44
+ toast: Partial<ToasterToast>
45
+ }
46
+ | {
47
+ type: ActionType["DISMISS_TOAST"]
48
+ toastId?: ToasterToast["id"]
49
+ }
50
+ | {
51
+ type: ActionType["REMOVE_TOAST"]
52
+ toastId?: ToasterToast["id"]
53
+ }
54
+
55
+ interface State {
56
+ toasts: ToasterToast[]
57
+ }
58
+
59
+ const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
60
+
61
+ const addToRemoveQueue = (toastId: string) => {
62
+ if (toastTimeouts.has(toastId)) {
63
+ return
64
+ }
65
+
66
+ const timeout = setTimeout(() => {
67
+ toastTimeouts.delete(toastId)
68
+ dispatch({
69
+ type: "REMOVE_TOAST",
70
+ toastId: toastId,
71
+ })
72
+ }, TOAST_REMOVE_DELAY)
73
+
74
+ toastTimeouts.set(toastId, timeout)
75
+ }
76
+
77
+ export const reducer = (state: State, action: Action): State => {
78
+ switch (action.type) {
79
+ case "ADD_TOAST":
80
+ return {
81
+ ...state,
82
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
83
+ }
84
+
85
+ case "UPDATE_TOAST":
86
+ return {
87
+ ...state,
88
+ toasts: state.toasts.map((t) =>
89
+ t.id === action.toast.id ? { ...t, ...action.toast } : t
90
+ ),
91
+ }
92
+
93
+ case "DISMISS_TOAST": {
94
+ const { toastId } = action
95
+
96
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
97
+ // but I'll keep it here for simplicity
98
+ if (toastId) {
99
+ addToRemoveQueue(toastId)
100
+ } else {
101
+ state.toasts.forEach((toast) => {
102
+ addToRemoveQueue(toast.id)
103
+ })
104
+ }
105
+
106
+ return {
107
+ ...state,
108
+ toasts: state.toasts.map((t) =>
109
+ t.id === toastId || toastId === undefined
110
+ ? {
111
+ ...t,
112
+ open: false,
113
+ }
114
+ : t
115
+ ),
116
+ }
117
+ }
118
+ case "REMOVE_TOAST":
119
+ if (action.toastId === undefined) {
120
+ return {
121
+ ...state,
122
+ toasts: [],
123
+ }
124
+ }
125
+ return {
126
+ ...state,
127
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
128
+ }
129
+ }
130
+ }
131
+
132
+ const listeners: Array<(state: State) => void> = []
133
+
134
+ let memoryState: State = { toasts: [] }
135
+
136
+ function dispatch(action: Action) {
137
+ memoryState = reducer(memoryState, action)
138
+ listeners.forEach((listener) => {
139
+ listener(memoryState)
140
+ })
141
+ }
142
+
143
+ type Toast = Omit<ToasterToast, "id">
144
+
145
+ function toast({ ...props }: Toast) {
146
+ const id = genId()
147
+
148
+ const update = (props: ToasterToast) =>
149
+ dispatch({
150
+ type: "UPDATE_TOAST",
151
+ toast: { ...props, id },
152
+ })
153
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
154
+
155
+ dispatch({
156
+ type: "ADD_TOAST",
157
+ toast: {
158
+ ...props,
159
+ id,
160
+ open: true,
161
+ onOpenChange: (open) => {
162
+ if (!open) dismiss()
163
+ },
164
+ },
165
+ })
166
+
167
+ return {
168
+ id: id,
169
+ dismiss,
170
+ update,
171
+ }
172
+ }
173
+
174
+ function useToast() {
175
+ const [state, setState] = React.useState<State>(memoryState)
176
+
177
+ React.useEffect(() => {
178
+ listeners.push(setState)
179
+ return () => {
180
+ const index = listeners.indexOf(setState)
181
+ if (index > -1) {
182
+ listeners.splice(index, 1)
183
+ }
184
+ }
185
+ }, [state])
186
+
187
+ return {
188
+ ...state,
189
+ toast,
190
+ dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
191
+ }
192
+ }
193
+
194
+ export { useToast, toast }
@@ -0,0 +1,54 @@
1
+ // This file would contain utility functions for processing benchmark data
2
+ // For example, parsing JSON files, aggregating results, etc.
3
+
4
+ export type BenchmarkResult = {
5
+ server: string
6
+ test_case: string
7
+ threads: number
8
+ workers: number
9
+ http2: boolean
10
+ concurrency: number
11
+ rss_mb?: number
12
+ results: {
13
+ successRate: number
14
+ total: number
15
+ slowest: number
16
+ fastest: number
17
+ average: number
18
+ requestsPerSec: number
19
+ totalData: number
20
+ sizePerRequest: number
21
+ sizePerSec: number
22
+ errorDistribution: Record<string, number>
23
+ p95_latency: number
24
+ }
25
+ timestamp?: string
26
+ }
27
+
28
+ /**
29
+ * In a real implementation, this function would:
30
+ * 1. Scan the directory structure
31
+ * 2. Read and parse the JSON files
32
+ * 3. Return the aggregated data
33
+ */
34
+ export async function loadBenchmarkData(): Promise<BenchmarkResult[]> {
35
+ // This is a placeholder for the actual implementation
36
+ return []
37
+ }
38
+
39
+ /**
40
+ * Calculate summary statistics for benchmark results
41
+ */
42
+ export function calculateStats(data: BenchmarkResult[], metric: keyof BenchmarkResult["results"]) {
43
+ if (data.length === 0) return null
44
+
45
+ const values = data.map((item) => item.results[metric] as number)
46
+
47
+ return {
48
+ count: values.length,
49
+ min: Math.min(...values),
50
+ max: Math.max(...values),
51
+ avg: values.reduce((sum, val) => sum + val, 0) / values.length,
52
+ median: values.sort((a, b) => a - b)[Math.floor(values.length / 2)],
53
+ }
54
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,14 @@
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ eslint: {
4
+ ignoreDuringBuilds: true,
5
+ },
6
+ typescript: {
7
+ ignoreBuildErrors: true,
8
+ },
9
+ images: {
10
+ unoptimized: true,
11
+ },
12
+ }
13
+
14
+ export default nextConfig