Skip to content
This repository has been archived by the owner on Jul 26, 2024. It is now read-only.

Commit

Permalink
chore: Add documentation (#89)
Browse files Browse the repository at this point in the history
chore: Add documentation

Issue #42
  • Loading branch information
jrconlin authored May 19, 2021
1 parent 5e52f24 commit b719705
Show file tree
Hide file tree
Showing 18 changed files with 149 additions and 25 deletions.
28 changes: 23 additions & 5 deletions src/adm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//! ADM partner integration
//!
//! This module handles most of the ADM fetch, validation, and management
//! for tile data. ADM provides a list of partners, along with a set of
//! tile information (e.g. the name of the partner, various URLs, etc.)
//! We only allow a known set of partners, and validate that the tile info
//! offered matches expected values.
use std::{collections::HashMap, fmt::Debug};

use serde::{Deserialize, Serialize};
Expand All @@ -11,18 +19,22 @@ use crate::{
web::{middleware::sentry as l_sentry, FormFactor, OsFamily},
};

/// The name of the "Default" node, which is used as a fall back if no data
/// is defined for a given partner.
pub(crate) const DEFAULT: &str = "DEFAULT";

/// The response message sent to the User Agent.
#[derive(Debug, Deserialize, Serialize)]
pub struct AdmTileResponse {
pub tiles: Vec<AdmTile>,
}

/// Filter criteria for adm Tiles
/// Each "filter" is a set of [AdmAdvertiserFilterSettings] that are
/// Filter criteria for ADM Tiles
///
/// Each "filter" is a set of [crate::adm::AdmAdvertiserFilterSettings] that are
/// specific to a given Advertiser name (the names are matched against
/// the tiles fetch request)
/// In addition there is a special [DEFAULT] value which is a filter
/// In addition there is a special `DEFAULT` value which is a filter
/// that will be applied to all advertisers that do not supply their
/// own values.
#[derive(Default, Clone, Debug)]
Expand All @@ -31,11 +43,12 @@ pub struct AdmFilter {
}

/// The AdmAdvertiserFilterSettings contain the settings for the various
/// ADM provided partners. These are specified as a JSON formatted hash
/// ADM provided partners.
///
/// These are specified as a JSON formatted hash
/// that contains the components. A special "DEFAULT" setting provides
/// information that may be used as a DEFAULT, or commonly appearing set
/// of data.
/// See `impl From<Settings>` for details of the structure.
#[derive(Clone, Debug, Deserialize, Default, Serialize)]
pub struct AdmAdvertiserFilterSettings {
/// Set of valid hosts for the `advertiser_url`
Expand Down Expand Up @@ -75,6 +88,7 @@ fn check_url(url: Url, species: &'static str, filter: &[String]) -> HandlerResul
Ok(true)
}

/// Filter a given tile data set provided by ADM and validate the various elements
impl AdmFilter {
/// Report the error directly to sentry
fn report(&self, error: &HandlerError, tags: &Tags) {
Expand Down Expand Up @@ -262,6 +276,7 @@ impl AdmFilter {
}

/// Construct the AdmFilter from the provided settings.
///
/// This uses a JSON construct of settings, e.g.
/// ```javascript
/// /* for the Example Co advertiser... */
Expand Down Expand Up @@ -299,6 +314,7 @@ impl From<&Settings> for HandlerResult<AdmFilter> {
}
}

/// The tile data provided by ADM
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AdmTile {
pub id: u64,
Expand All @@ -310,6 +326,8 @@ pub struct AdmTile {
pub position: Option<u8>,
}

/// Main handler for the User Agent HTTP request
///
#[allow(clippy::too_many_arguments)]
pub async fn get_tiles(
reqwest_client: &reqwest::Client,
Expand Down
15 changes: 15 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Common errors
use backtrace::Backtrace;
use std::error::Error;
use std::fmt;
Expand All @@ -14,47 +15,61 @@ use actix_web::{
};
use thiserror::Error;

/// The standard Result type for Contile (returns Error = [`HandlerError`])
pub type HandlerResult<T> = result::Result<T, HandlerError>;

/// The Standard Error for most of Contile
#[derive(Debug)]
pub struct HandlerError {
kind: HandlerErrorKind,
backtrace: Backtrace,
}

/// The specific context types of HandlerError.
#[derive(Debug, Error)]
pub enum HandlerErrorKind {
/// An unspecified General error, usually via an external service or crate
#[error("General error: {:?}", _0)]
General(String),

/// A specific Internal error.
#[error("Internal error: {:?}", _0)]
Internal(String),

/// An error fetching information from ADM
#[error("Reqwest error: {:?}", _0)]
Reqwest(#[from] reqwest::Error),

/// An error validating the tile information recv'd from ADM
#[error("Validation error: {:?}", _0)]
Validation(String),

/// A tile contained an invalid host url
#[error("Invalid {} Host: {:?}", _0, _1)]
InvalidHost(&'static str, String),

/// A tile was from an unrecognized host
#[error("Unexpected {} Host: {:?}", _0, _1)]
UnexpectedHost(&'static str, String),

/// A tile contained an unrecognized `advertiser_url` host
#[error("Unexpected Advertiser: {:?}", _0)]
UnexpectedAdvertiser(String),

/// A tile was missing a host, or presented an unparsable one.
#[error("Missing {} Host: {:?}", _0, _1)]
MissingHost(&'static str, String),

/// The Location information for the request could not be resolved
#[error("Location error: {:?}", _0)]
Location(String),

/// ADM returned an invalid or unexpected response
#[error("Bad Adm response: {:?}", _0)]
BadAdmResponse(String),
}

/// A set of Error Context utilities
impl HandlerErrorKind {
/// Return a response Status to be rendered for an error
pub fn http_status(&self) -> StatusCode {
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
#![warn(rust_2018_idioms)]
#![allow(clippy::try_err)]

//! Context Tile service
//!
//! Tiles are the links displayed on a "Firefox Home" page (displayed as
//! a new tab or default open page.) Context tiles are sponsored tiles
//! that can be offered. These tiles are provided by an advertising
//! partner (ADM). Contile provides a level of additional privacy by
//! disclosing only the minimal user info required, and providing a
//! caching system.
#[macro_use]
extern crate slog_scope;

Expand Down
10 changes: 10 additions & 0 deletions src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
//! Mozilla logging initialization and configuration
use std::io;

use crate::error::HandlerResult;

use slog::{self, slog_o, Drain};
use slog_mozlog_json::MozLogJson;

/// Handle logging initialization.
///
/// This uses the `slog_mozlog` crate
/// to extend `slog` logging. The `json` argument flags if output should
/// be in JSON format (the default for production logging), or in
/// a more human readable form. For Contile, this is configured using
/// the `human_logs` setting (see [crate::settings::Settings])
pub fn init_logging(json: bool) -> HandlerResult<()> {
let logger = if json {
let hostname = hostname::get()
Expand Down Expand Up @@ -41,6 +50,7 @@ pub fn init_logging(json: bool) -> HandlerResult<()> {
Ok(())
}

/// Reset the logger
pub fn reset_logging() {
let logger = slog::Logger::root(slog::Discard, slog_o!());
slog_scope::set_global_logger(logger).cancel_reset();
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Main application entry point
use std::error::Error;

#[macro_use]
Expand Down
15 changes: 14 additions & 1 deletion src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Metric collection and reporting via the `cadence` library.
use std::net::UdpSocket;
use std::time::Instant;

Expand All @@ -11,20 +13,23 @@ use crate::server::ServerState;
use crate::settings::Settings;
use crate::tags::Tags;

/// A convenience wrapper to time a given operation
#[derive(Debug, Clone)]
pub struct MetricTimer {
pub label: String,
pub start: Instant,
pub tags: Tags,
}

/// The metric wrapper
#[derive(Debug, Clone)]
pub struct Metrics {
client: Option<StatsdClient>,
tags: Option<Tags>,
timer: Option<MetricTimer>,
}

/// Record the duration of a given Timer metric, if one has been set.
impl Drop for Metrics {
fn drop(&mut self) {
let tags = self.tags.clone().unwrap_or_default();
Expand Down Expand Up @@ -94,6 +99,7 @@ impl From<&ServerState> for Metrics {
}

impl Metrics {
/// No-op metric
pub fn sink() -> StatsdClient {
StatsdClient::builder("", NopMetricSink).build()
}
Expand All @@ -106,6 +112,9 @@ impl Metrics {
}
}

/// Start a timer for a given closure.
///
/// Duration is calculated when this timer is dropped.
pub fn start_timer(&mut self, label: &str, tags: Option<Tags>) {
let mut mtags = self.tags.clone().unwrap_or_default();
if let Some(t) = tags {
Expand All @@ -120,11 +129,12 @@ impl Metrics {
});
}

// increment a counter with no tags data.
/// Increment a counter with no tags data.
pub fn incr(&self, label: &str) {
self.incr_with_tags(label, None)
}

/// Increment a given metric with optional [crate::tags::Tags]
pub fn incr_with_tags(&self, label: &str, tags: Option<Tags>) {
if let Some(client) = self.client.as_ref() {
let mut tagged = client.incr_with_tags(label);
Expand All @@ -149,10 +159,12 @@ impl Metrics {
}
}

/// increment by count with no tags
pub fn count(&self, label: &str, count: i64) {
self.count_with_tags(label, count, None)
}

/// increment by count with [crate::tags::Tags] information
pub fn count_with_tags(&self, label: &str, count: i64, tags: Option<Tags>) {
if let Some(client) = self.client.as_ref() {
let mut tagged = client.count_with_tags(label, count);
Expand All @@ -178,6 +190,7 @@ impl Metrics {
}
}

/// Fetch the metric information from the current [HttpRequest]
pub fn metrics_from_req(req: &HttpRequest) -> Result<Box<StatsdClient>, Error> {
Ok(req
.app_data::<Data<ServerState>>()
Expand Down
11 changes: 9 additions & 2 deletions src/server/cache.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Tile cache manager
use std::{collections::HashMap, fmt::Debug, ops::Deref, sync::Arc, time::Duration};

use cadence::Counted;
Expand All @@ -11,25 +12,30 @@ use crate::{
web::{FormFactor, OsFamily},
};

/// AudienceKey is the primary key used to store and fetch tiles from the
/// local cache.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct AudienceKey {
/// Country in ISO 3166-1 alpha-2 format
pub country: String,
/// Not yet supported: Region/subdivision (e.g. a US state) in ISO
/// 3166-2 format
pub region: String,
/// Only here for use by the periodic updater
// pub fake_ip: String,
/// The stripped User Agent string.(see [crate::web::strip_ua])
pub platform: String,
/// A simplified version of the Platform (see [crate::web::OsFamily]
pub os_family: OsFamily,
/// A simplified version of the display format (see [crate::web::FormFactor]
pub form_factor: FormFactor,
}

/// The stored Tile cache data
#[derive(Debug)]
pub struct Tiles {
pub json: String,
}

/// The simple tile Cache
#[derive(Debug, Clone)]
pub struct TilesCache {
inner: Arc<RwLock<HashMap<AudienceKey, Tiles>>>,
Expand All @@ -51,6 +57,7 @@ impl Deref for TilesCache {
}
}

/// Background tile refresh process
pub fn spawn_tile_cache_updater(interval: Duration, state: ServerState) {
actix_rt::spawn(async move {
loop {
Expand Down
Loading

0 comments on commit b719705

Please sign in to comment.