From cd1d989e138d9051ea76a6a6a53b01d96155d14a Mon Sep 17 00:00:00 2001 From: Sergey Melnychuk Date: Fri, 14 Oct 2022 21:53:51 +0200 Subject: [PATCH 1/2] Add Service Bindings support CloudFlare Workers Service Bindings: https://developers.cloudflare.com/workers/platform/bindings/about-service-bindings/ Inspiration: https://github.com/cloudflare/workers-rs/pull/183 --- worker/src/env.rs | 9 +++++++-- worker/src/fetcher.rs | 34 ++++++++++++++++++++++++++++++++-- worker/src/router.rs | 8 +++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/worker/src/env.rs b/worker/src/env.rs index f3710815..c9579332 100644 --- a/worker/src/env.rs +++ b/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}; @@ -51,6 +50,12 @@ impl Env { pub fn dynamic_dispatcher(&self, binding: &str) -> Result { 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 { + self.get_binding(binding) + } } pub trait EnvBinding: Sized + JsCast { diff --git a/worker/src/fetcher.rs b/worker/src/fetcher.rs index 3572590d..a27c05d7 100644 --- a/worker/src/fetcher.rs +++ b/worker/src/fetcher.rs @@ -1,8 +1,8 @@ -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::{Request, RequestInit, Response, Result, env::EnvBinding}; /// A struct for invoking fetch events to other Workers. pub struct Fetcher(FetcherSys); @@ -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::() + } + + 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 for JsValue { + fn from(service: Fetcher) -> Self { + JsValue::from(service.0) + } +} + +impl AsRef for Fetcher { + fn as_ref(&self) -> &wasm_bindgen::JsValue { + &self.0 + } +} + impl From for Fetcher { fn from(inner: FetcherSys) -> Self { Self(inner) diff --git a/worker/src/router.rs b/worker/src/router.rs index 89e6a193..a38a8322 100644 --- a/worker/src/router.rs +++ b/worker/src/router.rs @@ -10,7 +10,7 @@ use crate::{ http::Method, request::Request, response::Response, - Result, + Result, Fetcher, }; type HandlerFn = fn(Request, RouteContext) -> Result; @@ -94,6 +94,12 @@ impl RouteContext { 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 { + self.env.service(binding) + } } impl<'a> Router<'a, ()> { From c999534d8f069f6e73c3ad4087b1cb494aa3cbd1 Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Thu, 17 Nov 2022 10:17:20 -0500 Subject: [PATCH 2/2] chore: add integration testing for service bindings Adds integration testing for service bindings by creating a new worker in the worker-sandbox directory and mounting it with Miniflare. --- worker-build/src/install.rs | 2 +- worker-build/src/main.rs | 8 ++++---- worker-sandbox/remote-service/package.json | 3 +++ worker-sandbox/remote-service/service.js | 3 +++ worker-sandbox/remote-service/wrangler.toml | 2 ++ worker-sandbox/src/lib.rs | 11 +++++++++++ worker-sandbox/tests/requests.rs | 9 +++++++++ worker-sandbox/wrangler.toml | 7 +++++++ worker/src/fetcher.rs | 8 ++++---- worker/src/router.rs | 2 +- 10 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 worker-sandbox/remote-service/package.json create mode 100644 worker-sandbox/remote-service/service.js create mode 100644 worker-sandbox/remote-service/wrangler.toml diff --git a/worker-build/src/install.rs b/worker-build/src/install.rs index 50448968..89cd0893 100644 --- a/worker-build/src/install.rs +++ b/worker-build/src/install.rs @@ -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()?; diff --git a/worker-build/src/main.rs b/worker-build/src/main.rs index 219a56f8..3dccf8a5 100644 --- a/worker-build/src/main.rs +++ b/worker-build/src/main.rs @@ -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()?; @@ -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", diff --git a/worker-sandbox/remote-service/package.json b/worker-sandbox/remote-service/package.json new file mode 100644 index 00000000..8f5067aa --- /dev/null +++ b/worker-sandbox/remote-service/package.json @@ -0,0 +1,3 @@ +{ + "main": "./service.js" +} diff --git a/worker-sandbox/remote-service/service.js b/worker-sandbox/remote-service/service.js new file mode 100644 index 00000000..27d56bf8 --- /dev/null +++ b/worker-sandbox/remote-service/service.js @@ -0,0 +1,3 @@ +addEventListener('fetch', event => { + event.respondWith(new Response('hello world')) +}) diff --git a/worker-sandbox/remote-service/wrangler.toml b/worker-sandbox/remote-service/wrangler.toml new file mode 100644 index 00000000..19e9f373 --- /dev/null +++ b/worker-sandbox/remote-service/wrangler.toml @@ -0,0 +1,2 @@ +name = "remote-service" +type = "javascript" diff --git a/worker-sandbox/src/lib.rs b/worker-sandbox/src/lib.rs index 4781d04e..2d57b69b 100644 --- a/worker-sandbox/src/lib.rs +++ b/worker-sandbox/src/lib.rs @@ -646,6 +646,17 @@ pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result, + url: impl Into, init: Option, ) -> Result { - 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), diff --git a/worker/src/router.rs b/worker/src/router.rs index a38a8322..8eca726d 100644 --- a/worker/src/router.rs +++ b/worker/src/router.rs @@ -10,7 +10,7 @@ use crate::{ http::Method, request::Request, response::Response, - Result, Fetcher, + Fetcher, Result, }; type HandlerFn = fn(Request, RouteContext) -> Result;