Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add service binding support #243

Merged
merged 2 commits into from Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion worker-build/src/install.rs
Expand Up @@ -35,7 +35,7 @@ pub fn ensure_wasm_pack() -> Result<()> {
if is_installed("wasm-pack")?.is_none() {
println!("Installing wasm-pack...");
let exit_status = Command::new("cargo")
.args(&["install", "wasm-pack"])
.args(["install", "wasm-pack"])
.spawn()?
.wait()?;

Expand Down
8 changes: 4 additions & 4 deletions worker-build/src/main.rs
Expand Up @@ -49,9 +49,9 @@ where
let exit_status = Command::new("wasm-pack")
.arg("build")
.arg("--no-typescript")
.args(&["--target", "bundler"])
.args(&["--out-dir", OUT_DIR])
.args(&["--out-name", OUT_NAME])
.args(["--target", "bundler"])
.args(["--out-dir", OUT_DIR])
.args(["--out-name", OUT_NAME])
.args(args)
.spawn()?
.wait()?;
Expand Down Expand Up @@ -122,7 +122,7 @@ fn bundle(esbuild_path: &Path) -> Result<()> {
let path = PathBuf::from(OUT_DIR).join(WORKER_SUBDIR).canonicalize()?;
let esbuild_path = esbuild_path.canonicalize()?;
let mut command = Command::new(esbuild_path);
command.args(&[
command.args([
"--external:./index.wasm",
"--format=esm",
"--bundle",
Expand Down
3 changes: 3 additions & 0 deletions worker-sandbox/remote-service/package.json
@@ -0,0 +1,3 @@
{
"main": "./service.js"
}
3 changes: 3 additions & 0 deletions worker-sandbox/remote-service/service.js
@@ -0,0 +1,3 @@
addEventListener('fetch', event => {
event.respondWith(new Response('hello world'))
})
2 changes: 2 additions & 0 deletions worker-sandbox/remote-service/wrangler.toml
@@ -0,0 +1,2 @@
name = "remote-service"
type = "javascript"
11 changes: 11 additions & 0 deletions worker-sandbox/src/lib.rs
Expand Up @@ -646,6 +646,17 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result<Respo
Ok(resp)
}
})
.get_async("/remote-by-request", |req, ctx| async move {
let fetcher = ctx.service("remote")?;
fetcher.fetch_request(req).await
})
.get_async("/remote-by-path", |req, ctx| async move {
let fetcher = ctx.service("remote")?;
let mut init = RequestInit::new();
init.with_method(Method::Post);

fetcher.fetch(req.url()?.to_string(), Some(init)).await
})
.or_else_any_method_async("/*catchall", |_, ctx| async move {
console_log!(
"[or_else_any_method_async] caught: {}",
Expand Down
9 changes: 9 additions & 0 deletions worker-sandbox/tests/requests.rs
Expand Up @@ -469,3 +469,12 @@ fn cache_api() {
let body: serde_json::Value = post(delete_endpoint.as_str(), |r| r).json().unwrap();
assert_eq!("ResponseNotFound", body);
}

#[test]
fn test_service_binding() {
let body: String = get("remote-by-request", |r| r).text().unwrap();
assert_eq!(body, "hello world");

let body: String = get("remote-by-path", |r| r).text().unwrap();
assert_eq!(body, "hello world");
}
7 changes: 7 additions & 0 deletions worker-sandbox/wrangler.toml
Expand Up @@ -11,6 +11,13 @@ kv_namespaces = [

vars = { SOME_VARIABLE = "some value" }

[[services]]
binding = "remote"
service = "remote-service"

[miniflare.mounts]
remote-service = "./remote-service"

[durable_objects]
bindings = [{ name = "COUNTER", class_name = "Counter" }, { name = "ALARM", class_name = "AlarmObject" }]

Expand Down
9 changes: 7 additions & 2 deletions worker/src/env.rs
@@ -1,6 +1,5 @@
use crate::error::Error;
use crate::Result;
use crate::{durable::ObjectNamespace, DynamicDispatcher};
use crate::{durable::ObjectNamespace, DynamicDispatcher, Fetcher, Result};

use js_sys::Object;
use wasm_bindgen::{prelude::*, JsCast, JsValue};
Expand Down Expand Up @@ -51,6 +50,12 @@ impl Env {
pub fn dynamic_dispatcher(&self, binding: &str) -> Result<DynamicDispatcher> {
self.get_binding(binding)
}

/// Get a [Service Binding](https://developers.cloudflare.com/workers/runtime-apis/service-bindings/)
/// for Worker-to-Worker communication.
pub fn service(&self, binding: &str) -> Result<Fetcher> {
self.get_binding(binding)
}
}

pub trait EnvBinding: Sized + JsCast {
Expand Down
40 changes: 35 additions & 5 deletions worker/src/fetcher.rs
@@ -1,20 +1,20 @@
use wasm_bindgen::JsCast;
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
use worker_sys::{Fetcher as FetcherSys, Response as ResponseSys};

use crate::{Request, RequestInit, Response, Result};
use crate::{env::EnvBinding, Request, RequestInit, Response, Result};

/// A struct for invoking fetch events to other Workers.
pub struct Fetcher(FetcherSys);

impl Fetcher {
/// Invoke a fetch event in a worker with a path and optionally a [RequestInit].
/// Invoke a fetch event in a worker with a url and optionally a [RequestInit].
pub async fn fetch(
&self,
path: impl Into<String>,
url: impl Into<String>,
init: Option<RequestInit>,
) -> Result<Response> {
let path = path.into();
let path = url.into();
let promise = match init {
Some(ref init) => self.0.fetch_with_str_and_init(&path, &init.into()),
None => self.0.fetch_with_str(&path),
Expand All @@ -32,6 +32,36 @@ impl Fetcher {
}
}

impl EnvBinding for Fetcher {
const TYPE_NAME: &'static str = "Fetcher";
}

impl JsCast for Fetcher {
fn instanceof(val: &wasm_bindgen::JsValue) -> bool {
val.is_instance_of::<Fetcher>()
}

fn unchecked_from_js(val: wasm_bindgen::JsValue) -> Self {
Self(val.into())
}

fn unchecked_from_js_ref(val: &wasm_bindgen::JsValue) -> &Self {
unsafe { &*(val as *const JsValue as *const Self) }
}
}

impl From<Fetcher> for JsValue {
fn from(service: Fetcher) -> Self {
JsValue::from(service.0)
}
}

impl AsRef<wasm_bindgen::JsValue> for Fetcher {
fn as_ref(&self) -> &wasm_bindgen::JsValue {
&self.0
}
}

impl From<FetcherSys> for Fetcher {
fn from(inner: FetcherSys) -> Self {
Self(inner)
Expand Down
8 changes: 7 additions & 1 deletion worker/src/router.rs
Expand Up @@ -10,7 +10,7 @@ use crate::{
http::Method,
request::Request,
response::Response,
Result,
Fetcher, Result,
};

type HandlerFn<D> = fn(Request, RouteContext<D>) -> Result<Response>;
Expand Down Expand Up @@ -94,6 +94,12 @@ impl<D> RouteContext<D> {
pub fn param(&self, key: &str) -> Option<&String> {
self.params.get(key)
}

/// Get a [Service Binding](https://developers.cloudflare.com/workers/runtime-apis/service-bindings/)
/// for Worker-to-Worker communication.
pub fn service(&self, binding: &str) -> Result<Fetcher> {
self.env.service(binding)
}
}

impl<'a> Router<'a, ()> {
Expand Down