Skip to content

Commit 1464474

Browse files
Support for spin framework
1 parent c9adc7e commit 1464474

11 files changed

Lines changed: 138 additions & 94 deletions

File tree

crates/mocktioneer-adapter-spin/.spin/logs/mocktioneer_stderr.txt

Whitespace-only changes.

crates/mocktioneer-adapter-spin/.spin/logs/mocktioneer_stdout.txt

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "mocktioneer-adapter-spin"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
path = "src/lib.rs"
10+
11+
[features]
12+
default = ["spin"]
13+
spin = ["edgezero-adapter-spin/spin"]
14+
15+
[dependencies]
16+
mocktioneer-core = { workspace = true }
17+
edgezero-adapter-spin = { workspace = true }
18+
anyhow = { workspace = true }
19+
20+
[target.'cfg(target_arch = "wasm32")'.dependencies]
21+
edgezero-adapter-spin = { workspace = true, features = ["spin"] }
22+
edgezero-core = { workspace = true }
23+
spin-sdk = { workspace = true }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
spin_manifest_version = 2
2+
3+
[application]
4+
name = "mocktioneer-adapter-spin"
5+
version = "0.1.0"
6+
7+
[[trigger.http]]
8+
route = "/..."
9+
component = "mocktioneer"
10+
11+
[component.mocktioneer]
12+
source = "../../target/wasm32-wasip1/release/mocktioneer_adapter_spin.wasm"
13+
allowed_outbound_hosts = ["https://*:*"]
14+
[component.mocktioneer.build]
15+
command = "cargo build --target wasm32-wasip1 --release"
16+
watch = ["src/**/*.rs", "Cargo.toml"]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#[cfg(target_arch = "wasm32")]
2+
use mocktioneer_core::MocktioneerApp;
3+
#[cfg(target_arch = "wasm32")]
4+
use spin_sdk::http::{IncomingRequest, IntoResponse};
5+
#[cfg(target_arch = "wasm32")]
6+
use spin_sdk::http_component;
7+
8+
#[cfg(target_arch = "wasm32")]
9+
#[http_component]
10+
async fn handle(req: IncomingRequest) -> anyhow::Result<impl IntoResponse> {
11+
edgezero_adapter_spin::run_app::<MocktioneerApp>(req).await
12+
}

crates/mocktioneer-core/src/auction.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::aps::{ApsBidRequest, ApsBidResponse, ApsContextual, ApsSlotResponse};
2+
use crate::new_id;
23
use crate::openrtb::{
34
Bid as OpenrtbBid, Imp as OpenrtbImp, MediaType, OpenRTBRequest, OpenRTBResponse, SeatBid,
45
};
56
use crate::render::iframe_html;
67
use phf::phf_map;
78
use serde_json::json;
8-
use uuid::Uuid;
99

1010
// ============================================================================
1111
// Standard Ad Sizes - single source of truth for supported sizes and pricing
@@ -82,10 +82,6 @@ pub fn standard_sizes() -> impl Iterator<Item = (i64, i64)> {
8282
sizes.into_iter()
8383
}
8484

85-
fn new_id() -> String {
86-
Uuid::now_v7().simple().to_string()
87-
}
88-
8985
pub fn size_from_imp(imp: &OpenrtbImp) -> (i64, i64) {
9086
// Prefer imp.banner.w/h; fallback to banner.format[0].w/h; default 300x250
9187
if let Some(banner) = &imp.banner {

crates/mocktioneer-core/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ pub mod verification;
99
edgezero_core::app!("../../edgezero.toml", MocktioneerApp);
1010

1111
use edgezero_core::app::Hooks;
12+
use uuid::Uuid;
13+
14+
/// Generate a new UUIDv7 identifier as a lowercase hex string.
15+
/// Shared across auction, mediation, and other modules that need unique IDs.
16+
pub(crate) fn new_id() -> String {
17+
Uuid::now_v7().simple().to_string()
18+
}
1219

1320
pub fn build_app() -> edgezero_core::app::App {
1421
MocktioneerApp::build_app()

crates/mocktioneer-core/src/mediation.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
//! Provides a simple mediation endpoint that accepts bids from multiple bidders
44
//! and selects winners based on price (highest price wins).
55
6+
use crate::new_id;
67
use crate::openrtb::{Bid as OpenRTBBid, Imp, MediaType, OpenRTBResponse, SeatBid};
78
use serde::{Deserialize, Serialize};
89
use std::cmp::Ordering;
910
use std::collections::HashMap;
10-
use uuid::Uuid;
1111
use validator::Validate;
1212

13-
fn new_id() -> String {
14-
Uuid::now_v7().simple().to_string()
15-
}
16-
1713
/// Mediation request containing impression definitions and bidder responses
1814
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
1915
pub struct MediationRequest {

crates/mocktioneer-core/src/render.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ pub fn creative_html(w: i64, h: i64, pixel_html: bool, pixel_js: bool, host: &st
5959
const INFO_TMPL: &str = include_str!("../static/templates/info.html.hbs");
6060
pub fn info_html(host: &str) -> String {
6161
use std::env;
62-
let service_id = env::var("FASTLY_SERVICE_ID").unwrap_or_else(|_| "".to_string());
63-
let service_version = env::var("FASTLY_SERVICE_VERSION").unwrap_or_else(|_| "".to_string());
62+
let service_id = env::var("FASTLY_SERVICE_ID").unwrap_or_default();
63+
let service_version = env::var("FASTLY_SERVICE_VERSION").unwrap_or_default();
6464
let datacenter = env::var("FASTLY_DATACENTER")
6565
.or_else(|_| env::var("FASTLY_REGION"))
66-
.unwrap_or_else(|_| "".to_string());
66+
.unwrap_or_default();
6767
let pkg_version = env!("CARGO_PKG_VERSION");
6868
let data = serde_json::json!({
6969
"DATACENTER": datacenter,

crates/mocktioneer-core/src/routes.rs

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ struct SizeDimensions {
111111
height: i64,
112112
}
113113

114-
impl SizeDimensions {}
115-
116114
struct ValidatedSize<F>(SizeDimensions, PhantomData<F>);
117115

118116
async fn extract_size<F>(ctx: &RequestContext) -> Result<ValidatedSize<F>, EdgeError>
@@ -180,6 +178,24 @@ fn build_response(status: StatusCode, body: Body) -> Response {
180178
.expect("static response builder should not fail")
181179
}
182180

181+
fn json_response(body: Body) -> Response {
182+
let mut response = build_response(StatusCode::OK, body);
183+
response.headers_mut().insert(
184+
header::CONTENT_TYPE,
185+
HeaderValue::from_static("application/json"),
186+
);
187+
response
188+
}
189+
190+
fn html_response(body: Body) -> Response {
191+
let mut response = build_response(StatusCode::OK, body);
192+
response.headers_mut().insert(
193+
header::CONTENT_TYPE,
194+
HeaderValue::from_static("text/html; charset=utf-8"),
195+
);
196+
response
197+
}
198+
183199
fn apply_cors(headers: &mut HeaderMap) {
184200
headers.insert("Access-Control-Allow-Origin", HeaderValue::from_static("*"));
185201
headers.insert(
@@ -225,12 +241,7 @@ fn options_response() -> Response {
225241
#[action]
226242
pub async fn handle_root(ForwardedHost(host): ForwardedHost) -> Response {
227243
let html = info_html(&host);
228-
let mut response = build_response(StatusCode::OK, Body::text(html));
229-
response.headers_mut().insert(
230-
header::CONTENT_TYPE,
231-
HeaderValue::from_static("text/html; charset=utf-8"),
232-
);
233-
response
244+
html_response(Body::text(html))
234245
}
235246

236247
#[action]
@@ -266,12 +277,7 @@ pub async fn handle_openrtb_auction(
266277
log::error!("Failed to serialize OpenRTB response: {}", e);
267278
EdgeError::internal(e)
268279
})?;
269-
let mut response = build_response(StatusCode::OK, body);
270-
response.headers_mut().insert(
271-
header::CONTENT_TYPE,
272-
HeaderValue::from_static("application/json"),
273-
);
274-
Ok(response)
280+
Ok(json_response(body))
275281
}
276282

277283
#[action]
@@ -305,12 +311,7 @@ pub async fn handle_static_creatives(
305311
let pixel_html = query.pixel_html.unwrap_or(true);
306312
let pixel_js = query.pixel_js.unwrap_or(false);
307313
let html = creative_html(w, h, pixel_html, pixel_js, &host);
308-
let mut response = build_response(StatusCode::OK, Body::from(html));
309-
response.headers_mut().insert(
310-
header::CONTENT_TYPE,
311-
HeaderValue::from_static("text/html; charset=utf-8"),
312-
);
313-
response
314+
html_response(Body::from(html))
314315
}
315316

316317
fn parse_cookie<'a>(cookie_header: &'a str, name: &str) -> Option<&'a str> {
@@ -330,13 +331,11 @@ const PIXEL_GIF: &[u8] = include_bytes!("../static/pixel.gif");
330331
#[action]
331332
pub async fn handle_pixel(
332333
Headers(headers): Headers,
333-
ValidatedQuery(params): ValidatedQuery<PixelQueryParams>,
334+
ValidatedQuery(_params): ValidatedQuery<PixelQueryParams>,
334335
) -> Response {
335336
let cookie_name = "mtkid";
336337
let mut set_cookie = None;
337338

338-
let PixelQueryParams { pid: _ } = params;
339-
340339
let existing = headers
341340
.get(header::COOKIE)
342341
.and_then(|c| c.to_str().ok())
@@ -353,23 +352,21 @@ pub async fn handle_pixel(
353352
}
354353

355354
let mut response = build_response(StatusCode::OK, Body::from(PIXEL_GIF));
356-
{
357-
let headers = response.headers_mut();
358-
headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("image/gif"));
359-
headers.insert(
360-
header::CACHE_CONTROL,
361-
HeaderValue::from_static("no-store, no-cache, must-revalidate, max-age=0"),
362-
);
363-
headers.insert("Pragma", HeaderValue::from_static("no-cache"));
364-
headers.insert(
365-
header::CONTENT_LENGTH,
366-
HeaderValue::from_str(&PIXEL_GIF.len().to_string()).expect("length"),
367-
);
368-
}
355+
let resp_headers = response.headers_mut();
356+
resp_headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("image/gif"));
357+
resp_headers.insert(
358+
header::CACHE_CONTROL,
359+
HeaderValue::from_static("no-store, no-cache, must-revalidate, max-age=0"),
360+
);
361+
resp_headers.insert("Pragma", HeaderValue::from_static("no-cache"));
362+
resp_headers.insert(
363+
header::CONTENT_LENGTH,
364+
HeaderValue::from_str(&PIXEL_GIF.len().to_string()).expect("length"),
365+
);
369366

370367
if let Some(cookie) = set_cookie {
371368
if let Ok(value) = HeaderValue::from_str(&cookie) {
372-
response.headers_mut().append("Set-Cookie", value);
369+
resp_headers.append("Set-Cookie", value);
373370
}
374371
}
375372

@@ -400,12 +397,7 @@ pub async fn handle_aps_bid(
400397
log::error!("Failed to serialize APS response: {}", e);
401398
EdgeError::internal(e)
402399
})?;
403-
let mut response = build_response(StatusCode::OK, body);
404-
response.headers_mut().insert(
405-
header::CONTENT_TYPE,
406-
HeaderValue::from_static("application/json"),
407-
);
408-
Ok(response)
400+
Ok(json_response(body))
409401
}
410402

411403
#[action]
@@ -442,12 +434,7 @@ pub async fn handle_adserver_mediate(
442434
log::error!("Failed to serialize mediation response: {}", e);
443435
EdgeError::internal(e)
444436
})?;
445-
let mut response = build_response(StatusCode::OK, body);
446-
response.headers_mut().insert(
447-
header::CONTENT_TYPE,
448-
HeaderValue::from_static("application/json"),
449-
);
450-
Ok(response)
437+
Ok(json_response(body))
451438
}
452439

453440
#[action]
@@ -473,12 +460,7 @@ pub async fn handle_click(ValidatedQuery(params): ValidatedQuery<ClickQueryParam
473460
"EXTRA": extra_json,
474461
}),
475462
);
476-
let mut response = build_response(StatusCode::OK, Body::from(html));
477-
response.headers_mut().insert(
478-
header::CONTENT_TYPE,
479-
HeaderValue::from_static("text/html; charset=utf-8"),
480-
);
481-
response
463+
html_response(Body::from(html))
482464
}
483465

484466
/// Returns all standard ad sizes as JSON array.
@@ -509,12 +491,7 @@ pub async fn handle_sizes() -> Response {
509491
.collect();
510492

511493
let body = serde_json::json!({ "sizes": sizes });
512-
let mut response = build_response(StatusCode::OK, Body::from(body.to_string()));
513-
response.headers_mut().insert(
514-
header::CONTENT_TYPE,
515-
HeaderValue::from_static("application/json"),
516-
);
517-
response
494+
json_response(Body::from(body.to_string()))
518495
}
519496

520497
#[cfg(test)]

0 commit comments

Comments
 (0)