Skip to content

Commit 069a25d

Browse files
committed
Added RPC support to Durable Objects.
1 parent f21e19e commit 069a25d

17 files changed

+211
-5
lines changed

worker-build/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ flate2 = "1.1"
1818
tar = "0.4"
1919
ureq = { version = "3.0", features = ["gzip"] }
2020
clap = { version = "4.5", features = ['derive'] }
21+
toml = "0.8"
22+
serde = { version = "1.0", features = ["derive"] }
2123
worker-codegen = { path = "../worker-codegen", version = "0.1.0" }
2224
wasm-pack = "0.13"
2325

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use crate::wrangler_config::{get_wrangler_config, WranglerConfig};
2+
use anyhow::Result;
3+
4+
pub fn get_durable_object_class_names() -> Result<Vec<String>> {
5+
let config: WranglerConfig = get_wrangler_config()?;
6+
7+
let mut names = Vec::new();
8+
9+
if let Some(do_config) = config.durable_objects {
10+
for binding in do_config.bindings {
11+
if !binding.class_name.is_empty() {
12+
if !names.contains(&binding.class_name) {
13+
names.push(binding.class_name);
14+
}
15+
}
16+
}
17+
}
18+
19+
if !names.is_empty() {
20+
println!(
21+
"[worker-build] Found DO class names in wrangler.toml: {:?}",
22+
names
23+
);
24+
} else {
25+
println!("[worker-build] No Durable Object class names found in wrangler.toml [durable_objects].bindings");
26+
}
27+
28+
Ok(names)
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use anyhow::Result;
2+
3+
pub fn get_durable_object_class_names_declaration(names: &Vec<String>) -> Result<String> {
4+
Ok(format!(
5+
"const __WORKER_BUILD_DO_NAMES__ = [{}];",
6+
names
7+
.into_iter()
8+
.map(|n| format!("\"{}\"", n))
9+
.collect::<Vec<_>>()
10+
.join(", ")
11+
))
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pub fn get_durable_object_class_names_exports(names: Vec<String>) -> String {
2+
let mut exports = String::new();
3+
4+
let prefix = "__DO_WRAPPED_";
5+
6+
for name in names {
7+
exports.push_str(&format!(
8+
"\nexport const {} = globalThis.{}{};",
9+
name, prefix, name
10+
));
11+
}
12+
13+
exports
14+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use super::{
2+
get_durable_object_class_names, get_durable_object_class_names_declaration,
3+
get_durable_object_class_names_exports,
4+
};
5+
use anyhow::Result;
6+
7+
const SHIM_TEMPLATE: &str = include_str!("../js/durable_objects_shim.js");
8+
9+
pub fn get_durable_objects_shim() -> Result<String> {
10+
let names = get_durable_object_class_names()?;
11+
12+
if names.is_empty() {
13+
return Ok("const successfullyWrappedDONames = [];".to_string());
14+
}
15+
16+
let mut shim = get_durable_object_class_names_declaration(&names)?;
17+
18+
shim.push_str(SHIM_TEMPLATE);
19+
20+
shim.push_str(&get_durable_object_class_names_exports(names));
21+
22+
Ok(shim)
23+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use super::get_durable_objects_shim;
2+
use anyhow::Result;
3+
4+
pub fn inject_durable_objects_shim(shim: String) -> Result<String> {
5+
Ok(shim.replace(
6+
"$DURABLE_OBJECTS_INJECTION_POINT",
7+
&get_durable_objects_shim()?,
8+
))
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mod get_durable_object_class_names;
2+
mod get_durable_object_class_names_declaration;
3+
mod get_durable_object_class_names_exports;
4+
mod get_durable_objects_shim;
5+
mod inject_durable_objects_shim;
6+
7+
pub use get_durable_object_class_names::get_durable_object_class_names;
8+
pub use get_durable_object_class_names_declaration::get_durable_object_class_names_declaration;
9+
pub use get_durable_object_class_names_exports::get_durable_object_class_names_exports;
10+
pub use get_durable_objects_shim::get_durable_objects_shim;
11+
pub use inject_durable_objects_shim::inject_durable_objects_shim;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { DurableObject } from "cloudflare:workers";
2+
3+
const successfullyWrappedDONames = [];
4+
const globalStorePrefix = "__DO_WRAPPED_"; // For globalThis storage
5+
6+
if (typeof __WORKER_BUILD_DO_NAMES__ !== 'undefined' && Array.isArray(__WORKER_BUILD_DO_NAMES__)) {
7+
__WORKER_BUILD_DO_NAMES__.forEach(className => {
8+
const OriginalClass = imports[className];
9+
if (typeof OriginalClass === 'function' && OriginalClass.prototype && typeof OriginalClass.prototype.fetch === 'function') {
10+
console.log(`[shim.js] Wrapping DO (identified by worker-build): ${className}`);
11+
successfullyWrappedDONames.push(className);
12+
const WrappedClass = class extends DurableObject {
13+
constructor(state, env) { super(state, env); this._inner = new OriginalClass(state, env); }
14+
async fetch(request) { return this._inner.fetch(request); }
15+
};
16+
Object.getOwnPropertyNames(OriginalClass.prototype).forEach(methodName => {
17+
if (methodName !== 'constructor' && methodName !== 'fetch') {
18+
if (typeof OriginalClass.prototype[methodName] === 'function') {
19+
WrappedClass.prototype[methodName] = function(...args) { return this._inner[methodName](...args); };
20+
}
21+
}
22+
});
23+
globalThis[`${globalStorePrefix}${className}`] = WrappedClass;
24+
} else {
25+
console.warn(`[shim.js] DO '${className}' (from __WORKER_BUILD_DO_NAMES__) not found/invalid in wasm imports.`);
26+
}
27+
});
28+
}

worker-build/src/js/shim.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as imports from "./index_bg.js";
2-
export * from "./index_bg.js";
32
import wasmModule from "./index.wasm";
43
import { WorkerEntrypoint } from "cloudflare:workers";
54

@@ -12,7 +11,7 @@ imports.__wbg_set_wasm(instance.exports);
1211
// Run the worker's initialization function.
1312
instance.exports.__wbindgen_start?.();
1413

15-
export { wasmModule };
14+
$DURABLE_OBJECTS_INJECTION_POINT
1615

1716
class Entrypoint extends WorkerEntrypoint {
1817
async fetch(request) {
@@ -31,6 +30,7 @@ class Entrypoint extends WorkerEntrypoint {
3130
}
3231

3332
const EXCLUDE_EXPORT = [
33+
...successfullyWrappedDONames,
3434
"IntoUnderlyingByteSource",
3535
"IntoUnderlyingSink",
3636
"IntoUnderlyingSource",
@@ -44,10 +44,11 @@ const EXCLUDE_EXPORT = [
4444
"getMemory",
4545
];
4646

47-
Object.keys(imports).map((k) => {
47+
Object.keys(imports).forEach((k) => {
4848
if (!(EXCLUDE_EXPORT.includes(k) | k.startsWith("__"))) {
4949
Entrypoint.prototype[k] = imports[k];
5050
}
5151
});
5252

5353
export default Entrypoint;
54+
export { wasmModule };

worker-build/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{
1111
use anyhow::Result;
1212

1313
use clap::Parser;
14+
use durable_object::inject_durable_objects_shim;
1415
use wasm_pack::command::build::{Build, BuildOptions};
1516

1617
const OUT_DIR: &str = "build";
@@ -19,7 +20,9 @@ const WORKER_SUBDIR: &str = "worker";
1920

2021
const SHIM_TEMPLATE: &str = include_str!("./js/shim.js");
2122

23+
mod durable_object;
2224
mod install;
25+
mod wrangler_config;
2326

2427
pub fn main() -> Result<()> {
2528
// Our tests build the bundle ourselves.
@@ -54,6 +57,8 @@ pub fn main() -> Result<()> {
5457
shim_template.replace("$WAIT_UNTIL_RESPONSE", "")
5558
};
5659

60+
let shim = inject_durable_objects_shim(shim)?;
61+
5762
write_string_to_file(worker_path("shim.js"), shim)?;
5863

5964
bundle(&esbuild_path)?;

0 commit comments

Comments
 (0)