Skip to content

Commit

Permalink
Load Pyodide runtime from external capnproto file
Browse files Browse the repository at this point in the history
These changes are needed to load the Pyodide runtime from an external capnproto
file. In workerd, we'll keep loading Pyodide in the same way, but we moved this
to WorkerdAPI. In our internal codebase, we now download the bundle and call
`setPyodideBundleData` when we load the first Python worker. Then when setting
up the module registry, we add the bundle from `pyodideBundleGlobal`.

TODO in followups:
1. Make workerd load the bundle in the same way
2. Add support for multiple versions of the bundle
  • Loading branch information
hoodmane committed Jul 24, 2024
1 parent 2c8bc74 commit 9a69cc8
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 27 deletions.
9 changes: 3 additions & 6 deletions src/workerd/api/modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ namespace workerd::api {
template <class Registry>
void registerModules(Registry& registry, auto featureFlags) {
node::registerNodeJsCompatModules(registry, featureFlags);
pyodide::registerPyodideModules(registry, featureFlags);
if (featureFlags.getPythonWorkers()) {
pyodide::registerPyodideModules(registry, featureFlags);
}
registerUnsafeModules(registry, featureFlags);
if (featureFlags.getRttiApi()) {
registerRTTIModule(registry);
Expand All @@ -45,11 +47,6 @@ void registerBuiltinModules(jsg::modules::ModuleRegistry::Builder& builder, auto
builder.add(getExternalUnsafeModuleBundle<TypeWrapper>(featureFlags));
}

if (featureFlags.getPythonWorkers()) {
builder.add(pyodide::getExternalPyodideModuleBundle(featureFlags));
builder.add(pyodide::getInternalPyodideModuleBundle(featureFlags));
}

if (featureFlags.getRttiApi()) {
builder.add(getExternalRttiModuleBundle<TypeWrapper>(featureFlags));
}
Expand Down
11 changes: 11 additions & 0 deletions src/workerd/api/pyodide/pyodide.c++
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

namespace workerd::api::pyodide {

kj::Maybe<kj::Array<unsigned char>> pyodideBundleDataGlobal = kj::none;
kj::Maybe<kj::Own<capnp::FlatArrayMessageReader>> pyodideBundleReaderGlobal = kj::none;
kj::Maybe<jsg::Bundle::Reader> pyodideBundleGlobal = kj::none;

void setPyodideBundleData(kj::Array<unsigned char> data) {
pyodideBundleReaderGlobal = kj::heap<capnp::FlatArrayMessageReader>(kj::arrayPtr(
reinterpret_cast<const capnp::word*>(data.begin()), data.size() / sizeof(capnp::word)));
pyodideBundleGlobal = KJ_REQUIRE_NONNULL(pyodideBundleReaderGlobal)->getRoot<jsg::Bundle>();
pyodideBundleDataGlobal = kj::mv(data);
}

static int readToTarget(kj::ArrayPtr<const kj::byte> source, int offset, kj::ArrayPtr<kj::byte> buf) {
int size = source.size();
if (offset >= size || offset < 0) {
Expand Down
30 changes: 9 additions & 21 deletions src/workerd/api/pyodide/pyodide.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@
#include <workerd/jsg/url.h>
#include <workerd/server/workerd.capnp.h>
#include <workerd/io/io-context.h>
#include "capnp/serialize.h"

namespace workerd::api::pyodide {

// singleton that owns bundle
extern kj::Maybe<jsg::Bundle::Reader> pyodideBundleGlobal;

void setPyodideBundleData(kj::Array<unsigned char> data);


struct PythonConfig {
kj::Maybe<kj::Own<const kj::Directory>> diskCacheRoot;
bool createSnapshot;
Expand Down Expand Up @@ -344,26 +351,7 @@ bool hasPythonModules(capnp::List<server::config::Worker::Module>::Reader module
api::pyodide::SimplePythonLimiter

template <class Registry> void registerPyodideModules(Registry& registry, auto featureFlags) {
if (featureFlags.getPythonWorkers()) {
// We add `pyodide:` packages here including python-entrypoint-helper.js.
registry.addBuiltinBundle(PYODIDE_BUNDLE, kj::none);
registry.template addBuiltinModule<PackagesTarReader>(
"pyodide-internal:packages_tar_reader", workerd::jsg::ModuleRegistry::Type::INTERNAL);
}
registry.template addBuiltinModule<PackagesTarReader>(
"pyodide-internal:packages_tar_reader", workerd::jsg::ModuleRegistry::Type::INTERNAL);
}

kj::Own<jsg::modules::ModuleBundle> getInternalPyodideModuleBundle(auto featureFlags) {
jsg::modules::ModuleBundle::BuiltinBuilder builder(
jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY);
jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(builder, PYODIDE_BUNDLE);
return builder.finish();
}

kj::Own<jsg::modules::ModuleBundle> getExternalPyodideModuleBundle(auto featureFlags) {
jsg::modules::ModuleBundle::BuiltinBuilder builder(
jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN);
jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(builder, PYODIDE_BUNDLE);
return builder.finish();
}

} // namespace workerd::api::pyodide
1 change: 1 addition & 0 deletions src/workerd/server/workerd-api.c++
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ void WorkerdApi::compileModules(
if (hasPythonModules(confModules)) {
KJ_REQUIRE(featureFlags.getPythonWorkers(),
"The python_workers compatibility flag is required to use Python.");
registry.addBuiltinBundle(PYODIDE_BUNDLE, kj::none);
// Inject pyodide bootstrap module.
{
auto mainModule = confModules.begin();
Expand Down

0 comments on commit 9a69cc8

Please # to comment.