Skip to content
File

Blob: src/workerd/server/workerd-api.h

cpp357 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include "workerd/api/pyodide/pyodide.h"
8 
9#include <workerd/io/worker-fs.h>
10#include <workerd/io/worker.h>
11#include <workerd/server/workerd.capnp.h>
12 
13namespace workerd {
14namespace api {
15namespace pyodide {
16struct PythonConfig;
17}
18} // namespace api
19} // namespace workerd
20namespace workerd {
21namespace jsg {
22class V8System;
23namespace modules {
24class ModuleRegistry;
25}
26} // namespace jsg
27} // namespace workerd
28 
29namespace workerd::api {
30class MemoryCacheProvider;
31}
32 
33namespace workerd::server {
34 
35using api::pyodide::PythonConfig;
36 
37// A Worker::Api implementation with support for all the APIs supported by the OSS runtime.
38class WorkerdApi final: public Worker::Api {
39 public:
40 WorkerdApi(jsg::V8System& v8System,
41 CompatibilityFlags::Reader features,
42 capnp::List<config::Extension>::Reader extensions,
43 v8::Isolate::CreateParams createParams,
44 v8::IsolateGroup group,
45 kj::Own<JsgIsolateObserver> observer,
46 api::MemoryCacheProvider& memoryCacheProvider,
47 const PythonConfig& pythonConfig);
48 ~WorkerdApi() noexcept(false);
49 
50 static const WorkerdApi& from(const Worker::Api&);
51 
52 kj::Own<jsg::Lock> lock(jsg::V8StackScope& stackScope) const override;
53 CompatibilityFlags::Reader getFeatureFlags() const override;
54 jsg::JsContext<api::ServiceWorkerGlobalScope> newContext(
55 jsg::Lock& lock, Worker::Api::NewContextOptions options = {}) const override;
56 jsg::Dict<NamedExport> unwrapExports(
57 jsg::Lock& lock, v8::Local<v8::Value> moduleNamespace) const override;
58 NamedExport unwrapExport(jsg::Lock& lock, v8::Local<v8::Value> exportVal) const override;
59 EntrypointClasses getEntrypointClasses(jsg::Lock& lock) const override;
60 const jsg::TypeHandler<ErrorInterface>& getErrorInterfaceTypeHandler(
61 jsg::Lock& lock) const override;
62 const jsg::TypeHandler<api::QueueExportedHandler>& getQueueTypeHandler(
63 jsg::Lock& lock) const override;
64 jsg::JsObject wrapExecutionContext(
65 jsg::Lock& lock, jsg::Ref<api::ExecutionContext> ref) const override;
66 const jsg::IsolateObserver& getObserver() const override;
67 void setIsolateObserver(IsolateObserver&) override;
68 
69 static Worker::Script::Source extractSource(kj::StringPtr name,
70 config::Worker::Reader conf,
71 CompatibilityFlags::Reader featureFlags,
72 Worker::ValidationErrorReporter& errorReporter);
73 
74 void compileModules(jsg::Lock& lock,
75 const Worker::Script::ModulesSource& source,
76 const Worker::Isolate& isolate,
77 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts,
78 SpanParent parentSpan) const override;
79 
80 kj::Array<Worker::Script::CompiledGlobal> compileServiceWorkerGlobals(jsg::Lock& lock,
81 const Worker::Script::ScriptSource& source,
82 const Worker::Isolate& isolate) const override;
83 
84 // A pipeline-level binding.
85 struct Global {
86 // TODO(cleanup): Get rid of this and just load from config.Worker.bindings capnp structure
87 // directly.
88 
89 struct Json {
90 kj::String text;
91 
92 Json clone() const {
93 return Json{.text = kj::str(text)};
94 }
95 };
96 struct Fetcher {
97 uint channel;
98 bool requiresHost;
99 bool isInHouse;
100 
101 Fetcher clone() const {
102 return *this;
103 }
104 };
105 struct LoopbackServiceStub {
106 uint channel;
107 
108 LoopbackServiceStub clone() const {
109 return *this;
110 }
111 };
112 struct KvNamespace {
113 uint subrequestChannel;
114 kj::String bindingName;
115 
116 KvNamespace clone() const {
117 return KvNamespace{
118 .subrequestChannel = subrequestChannel, .bindingName = kj::str(bindingName)};
119 }
120 };
121 struct R2Bucket {
122 uint subrequestChannel;
123 kj::String bucket;
124 kj::String bindingName;
125 
126 R2Bucket clone() const {
127 return R2Bucket{
128 .subrequestChannel = subrequestChannel,
129 .bucket = kj::str(bucket),
130 .bindingName = kj::str(bindingName),
131 };
132 }
133 };
134 struct QueueBinding {
135 uint subrequestChannel;
136 
137 QueueBinding clone() const {
138 return *this;
139 }
140 };
141 struct CryptoKey {
142 kj::String format;
143 kj::OneOf<kj::Array<byte>, Json> keyData;
144 Json algorithm;
145 bool extractable;
146 kj::Array<kj::String> usages;
147 
148 CryptoKey clone() const {
149 decltype(keyData) clonedKeyData;
150 KJ_SWITCH_ONEOF(keyData) {
151 KJ_CASE_ONEOF(bytes, kj::Array<byte>) {
152 clonedKeyData = kj::heapArray(bytes.asPtr());
153 }
154 KJ_CASE_ONEOF(json, Json) {
155 clonedKeyData = json.clone();
156 }
157 }
158 return CryptoKey{
159 .format = kj::str(format),
160 .keyData = kj::mv(clonedKeyData),
161 .algorithm = algorithm.clone(),
162 .extractable = extractable,
163 .usages = KJ_MAP(s, usages) { return kj::str(s); },
164 };
165 }
166 };
167 
168 struct MemoryCache {
169 kj::Maybe<kj::String> cacheId = kj::none;
170 uint32_t maxKeys;
171 uint32_t maxValueSize;
172 uint64_t maxTotalValueSize;
173 
174 MemoryCache clone() const {
175 return MemoryCache{
176 .cacheId = cacheId.map([](auto& id) { return kj::str(id); }),
177 .maxKeys = maxKeys,
178 .maxValueSize = maxValueSize,
179 .maxTotalValueSize = maxTotalValueSize,
180 };
181 }
182 };
183 
184 struct EphemeralActorNamespace {
185 uint actorChannel;
186 
187 EphemeralActorNamespace clone() const {
188 return *this;
189 }
190 };
191 struct LoopbackEphemeralActorNamespace {
192 uint actorChannel;
193 uint classChannel;
194 
195 LoopbackEphemeralActorNamespace clone() const {
196 return *this;
197 }
198 };
199 struct DurableActorNamespace {
200 uint actorChannel;
201 kj::StringPtr uniqueKey;
202 
203 DurableActorNamespace clone() const {
204 return *this;
205 }
206 };
207 struct LoopbackDurableActorNamespace {
208 uint actorChannel;
209 kj::StringPtr uniqueKey;
210 uint classChannel;
211 
212 LoopbackDurableActorNamespace clone() const {
213 return *this;
214 }
215 };
216 struct Wrapped {
217 // data carrier for configured WrappedBinding
218 kj::String moduleName;
219 kj::String entrypoint;
220 kj::Array<Global> innerBindings;
221 
222 Wrapped clone() const {
223 return Wrapped{.moduleName = kj::str(moduleName),
224 .entrypoint = kj::str(entrypoint),
225 .innerBindings = KJ_MAP(b, innerBindings) { return b.clone(); }};
226 }
227 };
228 struct AnalyticsEngine {
229 uint subrequestChannel;
230 kj::String dataset;
231 int64_t version;
232 AnalyticsEngine clone() const {
233 return AnalyticsEngine{
234 .subrequestChannel = subrequestChannel, .dataset = kj::str(dataset), .version = version};
235 }
236 };
237 struct Hyperdrive {
238 uint subrequestChannel;
239 kj::String database;
240 kj::String user;
241 kj::String password;
242 kj::String scheme;
243 
244 Hyperdrive clone() const {
245 return Hyperdrive{
246 .subrequestChannel = subrequestChannel,
247 .database = kj::str(database),
248 .user = kj::str(user),
249 .password = kj::str(password),
250 .scheme = kj::str(scheme),
251 };
252 }
253 };
254 struct UnsafeEval {};
255 
256 struct ActorClass {
257 uint channel;
258 
259 ActorClass clone() const {
260 return *this;
261 }
262 };
263 
264 struct LoopbackActorClass {
265 uint channel;
266 
267 LoopbackActorClass clone() const {
268 return *this;
269 }
270 };
271 
272 struct WorkerLoader {
273 uint channel;
274 
275 WorkerLoader clone() const {
276 return *this;
277 }
278 };
279 
280 struct WorkerdDebugPort {
281 WorkerdDebugPort clone() const {
282 return *this;
283 }
284 };
285 
286 kj::String name;
287 kj::OneOf<Json,
288 Fetcher,
289 LoopbackServiceStub,
290 KvNamespace,
291 R2Bucket,
292 CryptoKey,
293 EphemeralActorNamespace,
294 LoopbackEphemeralActorNamespace,
295 DurableActorNamespace,
296 LoopbackDurableActorNamespace,
297 QueueBinding,
298 kj::String,
299 kj::Array<byte>,
300 Wrapped,
301 AnalyticsEngine,
302 Hyperdrive,
303 UnsafeEval,
304 MemoryCache,
305 ActorClass,
306 LoopbackActorClass,
307 WorkerLoader,
308 WorkerdDebugPort>
309 value;
310 
311 Global clone() const;
312 };
313 
314 void compileGlobals(jsg::Lock& lock,
315 kj::ArrayPtr<const Global> globals,
316 v8::Local<v8::Object> target,
317 uint32_t ownerId) const;
318 
319 // Part of the original module registry API.
320 static kj::Maybe<jsg::ModuleRegistry::ModuleInfo> tryCompileModule(jsg::Lock& js,
321 config::Worker::Module::Reader conf,
322 const jsg::CompilationObserver& observer,
323 CompatibilityFlags::Reader featureFlags);
324 
325 // Convert a module definition from workerd config to a Worker::Script::Module (which may contain
326 // string pointers into the config).
327 static Worker::Script::Module readModuleConf(config::Worker::Module::Reader conf,
328 CompatibilityFlags::Reader featureFlags,
329 kj::Maybe<Worker::ValidationErrorReporter&> errorReporter = kj::none);
330 
331 using ModuleFallbackCallback = Worker::Api::ModuleFallbackCallback;
332 void setModuleFallbackCallback(kj::Function<ModuleFallbackCallback>&& callback) const override;
333 
334 // Create the ModuleRegistry instance for the worker.
335 static kj::Arc<jsg::modules::ModuleRegistry> newWorkerdModuleRegistry(
336 const jsg::ResolveObserver& resolveObserver,
337 kj::Maybe<const Worker::Script::ModulesSource&> source,
338 const CompatibilityFlags::Reader& featureFlags,
339 const PythonConfig& pythonConfig,
340 const jsg::Url& bundleBase,
341 capnp::List<config::Extension>::Reader extensions,
342 kj::Maybe<kj::String> fallbackService = kj::none,
343 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts = kj::none);
344 
345 private:
346 struct Impl;
347 kj::Own<Impl> impl;
348};
349 
350kj::Array<kj::String> getPythonRequirements(const Worker::Script::ModulesSource& source);
351 
352// An ActorStorage implementation which will always respond to reads as if the state is empty,
353// and will fail any writes. Defined here to be used by test-fixture and server.
354kj::Own<rpc::ActorStorage::Stage::Server> newEmptyReadOnlyActorStorage();
355 
356} // namespace workerd::server