diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/app/Actions/Specs/LaravelSpecs.php b/app/Actions/Specs/LaravelSpecs.php new file mode 100644 index 0000000..0961d7c --- /dev/null +++ b/app/Actions/Specs/LaravelSpecs.php @@ -0,0 +1,14 @@ + $this->getPhpServerApi(), + 'memory_limit' => $this->getMemoryLimit(), + 'op_cache' => $this->getOpCache(), + ]; + } + + public function getPhpServerApi() + { + return php_sapi_name(); + } + + public function getMemoryLimit() + { + return ini_get('memory_limit'); + } + + public function getOpCache() + { + return ini_get('opcache.enable'); + } +} \ No newline at end of file diff --git a/app/Actions/Specs/ServerSpecs.php b/app/Actions/Specs/ServerSpecs.php new file mode 100644 index 0000000..f4cea49 --- /dev/null +++ b/app/Actions/Specs/ServerSpecs.php @@ -0,0 +1,67 @@ + $this->getCpuModel(), + 'cpu_cores' => $this->getCpuCores(), + 'cpu_frequency' => $this->getCpuFrequency(), + 'os' => $this->getOs(), + 'ram' => $this->getRam(), + ]; + } + + public function getCpuModel() + { + // Run multi-line command and capture output + $command = <<<'CMD' + if cpu_info=$(grep -m1 "model name" /proc/cpuinfo 2>/dev/null); then + echo "$cpu_info" | cut -d':' -f2- | sed 's/^ *//' + elif [[ "$OSTYPE" == "darwin"* ]]; then + sysctl -n machdep.cpu.brand_string 2>/dev/null + else + echo "Unknown Processor Model" + fi + CMD; + + return trim(shell_exec($command)); + } + + public function getCpuCores() + { + $command = <<<'CMD' + [ -f /proc/cpuinfo ] && grep -c "^processor" /proc/cpuinfo || sysctl -n hw.ncpu 2>/dev/null + CMD; + + return trim(shell_exec($command)); + } + + public function getCpuFrequency() + { + $command = <<<'CMD' + if cpu_info=$(grep -m1 "cpu MHz" /proc/cpuinfo 2>/dev/null); then + echo "$cpu_info" | cut -d':' -f2- | sed 's/^ *//' + else + echo "Unknown CPU Frequency" + fi + CMD; + + return trim(shell_exec($command)); + } + + public function getOs() + { + return trim(shell_exec('grep "^PRETTY_NAME=" /etc/os-release | cut -d\'"\' -f2')); + } + + public function getRam() + { + $ram = (int) trim(shell_exec('awk \'/MemTotal/ {print $2}\' /proc/meminfo')); + return round($ram / 1024, 3) . ' MB'; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php deleted file mode 100644 index e19d9a4..0000000 --- a/app/Http/Controllers/AppController.php +++ /dev/null @@ -1,17 +0,0 @@ - Inertia::defer(fn () => ( new ServerSpecs() )->execute()), + 'php' => Inertia::defer(fn () => ( new PhpSpecs() )->execute()), + 'laravel' => Inertia::defer(fn () => ( new LaravelSpecs() )->execute()), + ]); + } + + public function store( Request $request ) + { + + } +} \ No newline at end of file diff --git a/app/Http/Controllers/EventController.php b/app/Http/Controllers/EventController.php new file mode 100644 index 0000000..cbde9c6 --- /dev/null +++ b/app/Http/Controllers/EventController.php @@ -0,0 +1,64 @@ +stream(function () { + while (ob_get_level()) { + ob_end_flush(); + } + @ini_set('output_buffering', 'off'); + @ini_set('zlib.output_compression', '0'); + set_time_limit(0); + + $bin = base_path('vendor/bin/yabs'); + $results = base_path('yabs-results.json'); + + $command = sprintf( + 'script -q /dev/null -c %s', + escapeshellarg(sprintf('%s -i -6 -w %s', $bin, $results)) + ); + + $process = Process::fromShellCommandline($command, base_path(), null, null, null); + + + echo "retry: 2000\n\n"; // keep connection healthy + @ob_flush(); flush(); + + $process->run(function ($type, $buffer) { + $buffer = trim($buffer); + if ($buffer !== '') { + echo "data: " . json_encode([ + 'timestamp' => date('Y-m-d H:i:s'), + 'type' => $type, // 'out' or 'err' + 'output' => $buffer, + ]) . "\n\n"; + @ob_flush(); flush(); + } + }); + + $status = $process->isSuccessful() ? 'completed' : 'error'; + $error = $process->isSuccessful() ? null : $process->getExitCodeText(); + + echo "data: " . json_encode([ + 'timestamp' => date('Y-m-d H:i:s'), + 'status' => $status, + 'error' => $error, + ]) . "\n\n"; + @ob_flush(); flush(); + + }, 200, [ + 'Content-Type' => 'text/event-stream', + 'Cache-Control' => 'no-cache', + 'Connection' => 'keep-alive', + 'X-Accel-Buffering' => 'no', + 'Access-Control-Allow-Origin' => '*', + ]); + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4d16bff..a4d4ea0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "vite": "^7.0.4" }, "dependencies": { + "@headlessui/vue": "^1.7.23", + "@heroicons/vue": "^2.2.0", "@inertiajs/vue3": "^2.1.7", + "@tailwindcss/forms": "^0.5.10", "@vitejs/plugin-vue": "^6.0.1", "@vueuse/core": "^13.9.0", "vue": "^3.5.21" diff --git a/public/images/icons/square-settings.svg b/public/images/icons/square-settings.svg new file mode 100644 index 0000000..51e21be --- /dev/null +++ b/public/images/icons/square-settings.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logos/benchkit-wide.svg b/public/images/logos/benchkit-wide.svg new file mode 100644 index 0000000..e8b5868 --- /dev/null +++ b/public/images/logos/benchkit-wide.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logos/discord-icon.svg b/public/images/logos/discord-icon.svg new file mode 100644 index 0000000..132c44d --- /dev/null +++ b/public/images/logos/discord-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/public/images/logos/github-icon.svg b/public/images/logos/github-icon.svg new file mode 100644 index 0000000..6097a4f --- /dev/null +++ b/public/images/logos/github-icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/images/logos/spin-pro.svg b/public/images/logos/spin-pro.svg new file mode 100644 index 0000000..649a4dd --- /dev/null +++ b/public/images/logos/spin-pro.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/ui/lightning.svg b/public/images/ui/lightning.svg new file mode 100644 index 0000000..e697713 --- /dev/null +++ b/public/images/ui/lightning.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/images/ui/window-controls.svg b/public/images/ui/window-controls.svg new file mode 100644 index 0000000..921e733 --- /dev/null +++ b/public/images/ui/window-controls.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/ui/your-environment.svg b/public/images/ui/your-environment.svg new file mode 100644 index 0000000..419f4e1 --- /dev/null +++ b/public/images/ui/your-environment.svg @@ -0,0 +1,630 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/css/app.css b/resources/css/app.css index 78ccf04..fe2801f 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,7 +1,14 @@ +@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap'); @import 'tailwindcss'; +@plugin "@tailwindcss/forms"; + @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @source '../../storage/framework/views/*.php'; @source '../**/*.blade.php'; @source '../**/*.js'; -@source '../**/*.vue'; \ No newline at end of file +@source '../**/*.vue'; + +@theme { + --font-mono: 'JetBrains Mono', monospace; +} \ No newline at end of file diff --git a/resources/js/Components/AppHeader.vue b/resources/js/Components/AppHeader.vue new file mode 100644 index 0000000..e922423 --- /dev/null +++ b/resources/js/Components/AppHeader.vue @@ -0,0 +1,48 @@ + + + \ No newline at end of file diff --git a/resources/js/Components/Background.vue b/resources/js/Components/Background.vue new file mode 100644 index 0000000..996fa25 --- /dev/null +++ b/resources/js/Components/Background.vue @@ -0,0 +1,85 @@ + + + \ No newline at end of file diff --git a/resources/js/Components/SettingsDrawer.vue b/resources/js/Components/SettingsDrawer.vue new file mode 100644 index 0000000..6607b8c --- /dev/null +++ b/resources/js/Components/SettingsDrawer.vue @@ -0,0 +1,198 @@ + + + \ No newline at end of file diff --git a/resources/js/Composables/useSettings.js b/resources/js/Composables/useSettings.js new file mode 100644 index 0000000..8677719 --- /dev/null +++ b/resources/js/Composables/useSettings.js @@ -0,0 +1,30 @@ +import { useForm } from '@inertiajs/vue3' + +const form = useForm({ + hardware: true, + disk: true, + geekbench: true, + geekbench_version: 6, + iperf: false, + network: true, + network_test_type: 'ipv4', + php_database: true, + database: { + create: 1000, + read: 1000, + update: 500, + delete: 500, + }, +}) + +export const useSettings = () => { + + const runBenchmark = () => { + form.post('/settings/benchmark'); + } + + return { + form, + runBenchmark, + } +} \ No newline at end of file diff --git a/resources/js/Composables/useStream.js b/resources/js/Composables/useStream.js new file mode 100644 index 0000000..19e1328 --- /dev/null +++ b/resources/js/Composables/useStream.js @@ -0,0 +1,39 @@ +import { ref } from 'vue'; + +const eventSource = ref(null); + +export const useStream = () => { + + const startStream = () => { + if (eventSource.value) { + eventSource.value.close(); + } + + eventSource.value = new EventSource('https://benchkit.dev.test/events'); + + eventSource.value.onmessage = (event) => { + console.log(event.data); + } + + eventSource.value.onerror = (event) => { + console.error(event); + } + + eventSource.value.onopen = (event) => { + console.log(event); + } + } + + const stopStream = () => { + if (eventSource.value) { + eventSource.value.close(); + eventSource.value = null; + } + } + + return { + eventSource, + startStream, + stopStream, + } +} \ No newline at end of file diff --git a/resources/js/Layouts/App.vue b/resources/js/Layouts/App.vue new file mode 100644 index 0000000..a354ada --- /dev/null +++ b/resources/js/Layouts/App.vue @@ -0,0 +1,28 @@ + + + \ No newline at end of file diff --git a/resources/js/Pages/Index.vue b/resources/js/Pages/Index.vue index ee26411..63b305b 100644 --- a/resources/js/Pages/Index.vue +++ b/resources/js/Pages/Index.vue @@ -1,9 +1,38 @@ \ No newline at end of file diff --git a/resources/js/Pages/Partials/Laravel.vue b/resources/js/Pages/Partials/Laravel.vue new file mode 100644 index 0000000..6fc2093 --- /dev/null +++ b/resources/js/Pages/Partials/Laravel.vue @@ -0,0 +1,254 @@ + + + \ No newline at end of file diff --git a/resources/js/Pages/Partials/Php.vue b/resources/js/Pages/Partials/Php.vue new file mode 100644 index 0000000..c1a8bd2 --- /dev/null +++ b/resources/js/Pages/Partials/Php.vue @@ -0,0 +1,47 @@ + + + \ No newline at end of file diff --git a/resources/js/Pages/Partials/Server.vue b/resources/js/Pages/Partials/Server.vue new file mode 100644 index 0000000..5409d0c --- /dev/null +++ b/resources/js/Pages/Partials/Server.vue @@ -0,0 +1,65 @@ + + + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 4fe3399..66f0e63 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,13 @@ use Illuminate\Support\Facades\Route; -use App\Http\Controllers\AppController; +use App\Http\Controllers\BenchmarkController; +use App\Http\Controllers\EventController; + +Route::get('/', [BenchmarkController::class, 'index']); +Route::post('/benchmark', [BenchmarkController::class, 'store']); + +Route::get('/events', [EventController::class, 'index']); + + -Route::get('/', [AppController::class, 'index']); diff --git a/yarn.lock b/yarn.lock index c01cdbd..9f7fc0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -179,6 +179,18 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f" integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ== +"@headlessui/vue@^1.7.23": + version "1.7.23" + resolved "https://registry.yarnpkg.com/@headlessui/vue/-/vue-1.7.23.tgz#7fe19dbeca35de9e6270c82c78c4864e6a6f7391" + integrity sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg== + dependencies: + "@tanstack/vue-virtual" "^3.0.0-beta.60" + +"@heroicons/vue@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@heroicons/vue/-/vue-2.2.0.tgz#d81f14eed448eec9859849ed63facd3f29bca2b3" + integrity sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw== + "@inertiajs/core@2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@inertiajs/core/-/core-2.1.7.tgz#1fd748c1fd06ce342249c5ca4a2a4d14706806ee" @@ -358,6 +370,13 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz#d81efe6a12060c7feddf9805e2a94c3ab0679f48" integrity sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg== +"@tailwindcss/forms@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.10.tgz#0a1cd67b6933402f1985a04595bd24f9785aa302" + integrity sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw== + dependencies: + mini-svg-data-uri "^1.2.3" + "@tailwindcss/node@4.1.12": version "4.1.12" resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.12.tgz#9099c7c9a6b719b2cae265fecbb37e08ed3fd2a2" @@ -468,6 +487,18 @@ "@tailwindcss/oxide" "4.1.12" tailwindcss "4.1.12" +"@tanstack/virtual-core@3.13.12": + version "3.13.12" + resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz#1dff176df9cc8f93c78c5e46bcea11079b397578" + integrity sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA== + +"@tanstack/vue-virtual@^3.0.0-beta.60": + version "3.13.12" + resolved "https://registry.yarnpkg.com/@tanstack/vue-virtual/-/vue-virtual-3.13.12.tgz#a66daac9e6822ce4bcba76a3954937440697c264" + integrity sha512-vhF7kEU9EXWXh+HdAwKJ2m3xaOnTTmgcdXcF2pim8g4GvI7eRrk2YRuV5nUlZnd/NbCIX4/Ja2OZu5EjJL06Ww== + dependencies: + "@tanstack/virtual-core" "3.13.12" + "@tybys/wasm-util@^0.10.0": version "0.10.0" resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" @@ -1034,6 +1065,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mini-svg-data-uri@^1.2.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" + integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== + minipass@^7.0.4, minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"