diff --git a/frameworks/Funxy/funxy-stdlib/README.md b/frameworks/Funxy/funxy-stdlib/README.md new file mode 100644 index 00000000000..88ea860b1f5 --- /dev/null +++ b/frameworks/Funxy/funxy-stdlib/README.md @@ -0,0 +1,16 @@ +# Funxy (stdlib) + +[Funxy](https://github.com/funvibe/funxy) is a general-purpose scripting language with static typing and type inference. + +- Homepage: https://github.com/funvibe/funxy +- Documentation: https://github.com/funvibe/funxy/tree/main/docs + +This implementation targets the following TechEmpower tests: + +- Plaintext (`/plaintext`) +- JSON Serialization (`/json`) + +Implementation files in this directory: + +- `supervisor.lang` +- `worker.lang` diff --git a/frameworks/Funxy/funxy-stdlib/benchmark_config.json b/frameworks/Funxy/funxy-stdlib/benchmark_config.json new file mode 100644 index 00000000000..a64d86b6cad --- /dev/null +++ b/frameworks/Funxy/funxy-stdlib/benchmark_config.json @@ -0,0 +1,22 @@ +{ + "framework": "funxy", + "maintainers": ["oakulikov", "funvibe"], + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "framework": "funxy", + "language": "Funxy", + "webserver": "None", + "os": "Linux", + "display_name": "funxy_stdlib", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Funxy/funxy-stdlib/funxy.dockerfile b/frameworks/Funxy/funxy-stdlib/funxy.dockerfile new file mode 100644 index 00000000000..0e462bb9515 --- /dev/null +++ b/frameworks/Funxy/funxy-stdlib/funxy.dockerfile @@ -0,0 +1,23 @@ +FROM ubuntu:22.04 + +RUN apt-get update && \ + apt-get install -y curl ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# Install Funxy binary directly (non-interactive, Docker-friendly) +RUN set -eux; \ + arch="$(dpkg --print-architecture)"; \ + case "$arch" in \ + amd64) funxy_arch="amd64" ;; \ + arm64) funxy_arch="arm64" ;; \ + *) echo "Unsupported architecture: $arch" >&2; exit 1 ;; \ + esac; \ + curl -fsSL -o /usr/local/bin/funxy "https://github.com/funvibe/funxy/releases/latest/download/funxy-linux-${funxy_arch}"; \ + chmod +x /usr/local/bin/funxy + +WORKDIR /app +COPY supervisor.lang worker.lang ./ + +EXPOSE 8080 + +CMD ["funxy", "vmm", "supervisor.lang"] \ No newline at end of file diff --git a/frameworks/Funxy/funxy-stdlib/supervisor.lang b/frameworks/Funxy/funxy-stdlib/supervisor.lang new file mode 100644 index 00000000000..92fa8fa53f9 --- /dev/null +++ b/frameworks/Funxy/funxy-stdlib/supervisor.lang @@ -0,0 +1,32 @@ +import "lib/vmm" (spawnVMGroup) +import "lib/time" (sleepMs) +import "lib/sys" (sysScriptDir, sysCPUCount) +import "lib/path" (pathJoin) +import "lib/flag" (flagSet, flagParse, flagGet) + +// Override with --workers N. +// If omitted or <= 0, use runtime CPU parallelism from sysCPUCount(). +flagSet("workers", 0, "number of worker VMs (<=0 means auto-detect)") +flagParse() +workersFlag = flagGet("workers") +logicalCPU = sysCPUCount() +cores = if workersFlag > 0 { workersFlag } else { logicalCPU } +if cores <= 0 { + panic("invalid worker count: " ++ show(cores)) +} + +worker_path = pathJoin([sysScriptDir(), "worker.lang"]) +print("Starting TFB cluster with workers=" ++ show(cores) ++ " (runtime_cpu=" ++ show(logicalCPU) ++ ")") + +match spawnVMGroup(worker_path, { + group: "tfb_web", + capabilities: ["lib/http", "lib/json"] +}, cores) { + Ok(ids) -> print("Started Funxy TFB cluster. Workers: " ++ show(ids)) + Fail(e) -> panic("Failed to start cluster: " ++ e) +} + +// Block the supervisor from exiting so the VMM stays alive +while true { + sleepMs(1000) +} diff --git a/frameworks/Funxy/funxy-stdlib/worker.lang b/frameworks/Funxy/funxy-stdlib/worker.lang new file mode 100644 index 00000000000..d871373a23c --- /dev/null +++ b/frameworks/Funxy/funxy-stdlib/worker.lang @@ -0,0 +1,24 @@ +import "lib/http" (httpServe) +import "lib/json" (jsonEncodeBytes) + +// Pre-allocate response structures to avoid allocation overhead during the hot path +headers_plain = [("Server", "Funxy"), ("Content-Type", "text/plain")] +msg_plain = "Hello, World!" + +// TechEmpower requires the Date header, but lib/http automatically adds and caches +// an accurate Date header for us, so we don't need to generate it manually. +httpServe(8080, fun(req) { + match req.path { + "/plaintext" -> { + status: 200, + headers: headers_plain, + body: msg_plain + } + "/json" -> { + status: 200, + headers: [("Server", "Funxy"), ("Content-Type", "application/json")], + body: jsonEncodeBytes({ message: "Hello, World!" }) + } + _ -> { status: 404, body: "" } + } +})