You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
sequenceDiagram
participant Client
participant C@E
participant WeatherAPI
participant LogService
Client->>C@E: Beacon
C@E->>Client: 204
Note over C@E: Check Geo and User-Agent
C@E->>WeatherAPI: Request Weather
WeatherAPI->>C@E: 200
Note over C@E: Generate JSON data
C@E->>LogService: Log
LogService->>C@E: 200
main.rs
use std::time::Instant;use fastly::geo::geo_lookup;use fastly::http::{StatusCode, header};use fastly::{Request,Response};use serde::Deserialize;use serde_json::json;use woothee::parser::Parser;use log::LevelFilter::*;fnmain() -> anyhow::Result<()>{let timing = Instant::now();println!("request received ({} ms)", timing.elapsed().as_millis());// Immediately return a 204 No Content response to the clientlet resp = Response::from_status(StatusCode::NO_CONTENT).with_header(header::CACHE_CONTROL,"no-store, private");
resp.send_to_client();println!("response returned ({} ms)", timing.elapsed().as_millis());// Get the client's request and IP addresslet req = Request::from_client();let client_ip = req.get_client_ip_addr().unwrap();// Use the Fastly geo_lookup function to get geographical information based on the IP addresslet geo = geo_lookup(client_ip).unwrap();let latitude = geo.latitude();let longitude = geo.longitude();// Use the geographical information to get weather dataletmut beresp = Request::get(format!("https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t_weather=true")).with_pass(true)// Don't cache response.send("weather_api")?;// Deserialize the weather datalet weather = beresp.take_body_json::<WeatherResponse>()?;// Parse the User-Agent header to get information about the client's devicelet raw_user_agent = req.get_header_str(header::USER_AGENT).unwrap();let parser = Parser::new();let user_agent = parser.parse(raw_user_agent).unwrap();// Build a JSON string with the gathered datalet data = json!({"ip": client_ip.to_string(),
"as_name": geo.as_name(),
"latitude": latitude,
"longitude": longitude,
"conn_speed": geo.conn_speed(),
"device_type": user_agent.category,
"app_name": user_agent.name,
"weather_code": weather.current_weather.weathercode,
"temperature": weather.current_weather.temperature
});// Log the JSON data
log_fastly::init_simple("papertrail",Info);
log::info!("{data}");println!("data logged ({} ms)", timing.elapsed().as_millis());Ok(())}// Define a struct for deserializing the weather data#[derive(Debug,Deserialize)]structWeather{temperature:f64,weathercode:i32,}// Define a struct for deserializing the full response#[derive(Debug,Deserialize)]structWeatherResponse{current_weather:Weather,}
Cargo.toml
[package]
name = "fastly-compute-project"version = "0.1.0"edition = "2021"# Remove this line if you want to be able to publish this crate as open source on crates.io.# Otherwise, `publish = false` prevents an accidental `cargo publish` from revealing private source.publish = false
[profile.release]
debug = 1
[dependencies]
anyhow = "1.0.71"fastly = "^0.9.2"log = "0.4.17"log-fastly = "=0.9.1"serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"woothee = "0.13.0"
faslty.toml
# This file describes a Fastly Compute@Edge package. To learn more visit:# https://developer.fastly.com/reference/fastly-toml/authors = ["foo@example"]
description = ""language = "rust"manifest_version = 3name = "logging"service_id = "MKUK9EASSwkvZvi8Cs1bQ7"
[local_server]
[local_server.backends]
[local_server.backends.weather_api]
override_host = "api.open-meteo.com"url = "https://api.open-meteo.com/"