Skip to content

Commit

Permalink
x/sdk/js: Add process.env
Browse files Browse the repository at this point in the history
Reflects contents of `environ` at transform init

Signed-off-by: Oren Leiman <[email protected]>
  • Loading branch information
oleiman committed Jul 13, 2024
1 parent 7685b6d commit 76993e6
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/transform-sdk/js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To use this SDK manually here are the steps:

```shell
# Compile the C++
docker run -v `pwd`/..:/src -w /src/js ghcr.io/webassembly/wasi-sdk \
docker run -v `pwd`/..:/src -w /src/js ghcr.io/webassembly/wasi-sdk:wasi-sdk-21 \
/bin/bash -c 'apt update && apt install -y git && cmake --preset release-static && cmake --build --preset release-static -- redpanda_js_transform -j32'
# Convert the JavaScript file into a WebAssembly text file
cat user_code.js | ./generate_js_provider.py > js_user_code.wat
Expand Down
64 changes: 63 additions & 1 deletion src/transform-sdk/js/js_vm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <expected>
#include <format>
#include <print>
#include <unistd.h>
#include <unordered_map>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -394,6 +396,50 @@ class console {
FILE* _info_stream;
FILE* _err_stream;
};

class process {
using map_t = std::unordered_map<std::string, std::string>;

public:
process() = default;

static std::expected<qjs::value, qjs::exception> env(JSContext* ctx) {
auto native_env = map_from_environ();
auto js_env = value::object(ctx);
for (const auto& [k, v] : native_env) {
auto val = value::string(ctx, v);
if (!val.has_value()) {
return std::unexpected(val.error());
}
if (auto res = js_env.set_property(k, val.value());
!res.has_value()) {
return std::unexpected(res.error());
}
}
return js_env;
}

private:
static map_t map_from_environ() {
map_t env{};
for (char** envp = environ; *envp != nullptr;
std::advance(envp, std::ptrdiff_t{1})) {
// environ entries are expected to be null terminated
const std::string entry{*envp};
if (entry.empty()) {
continue;
}
auto delim = entry.find_first_of('=');
if (delim == std::string_view::npos) {
continue;
}
auto key = entry.substr(0, delim);
auto val = delim + 1 < entry.size() ? entry.substr(delim + 1) : "";
env.emplace(std::move(key), std::move(val));
}
return env;
}
};
} // namespace

std::expected<std::monostate, exception> runtime::create_builtins() {
Expand All @@ -406,10 +452,26 @@ std::expected<std::monostate, exception> runtime::create_builtins() {
console_builder.method<&console::warn>("error");
auto factory = console_builder.build();
auto global_this = value::global(_ctx.get());
return global_this.set_property(
auto result = global_this.set_property(
"console",
factory.create(std::make_unique<console>(
console::config{.info = stdout, .warn = stderr})));

if (!result.has_value()) {
return result;
}

auto process_builder = class_builder<process>(_ctx.get(), "Process");
if (auto env_v = process::env(_ctx.get()); env_v.has_value()) {
auto factory = process_builder.build();
auto process_class = factory.create(std::make_unique<process>());
result = process_class.set_property("env", env_v.value());
result = global_this.set_property("process", process_class);
} else {
result = std::unexpected(env_v.error());
}

return result;
}

std::expected<compiled_bytecode, exception>
Expand Down

0 comments on commit 76993e6

Please sign in to comment.