use crate::protocol::Cohort;
use serde::{Serialize, Serializer};
use serde_repr::Serialize_repr;
use std::collections::HashMap;
#[cfg(test)]
mod tests;
pub const HEADER_UPDATER_NAME: &str = "X-Goog-Update-Updater";
pub const HEADER_INTERACTIVITY: &str = "X-Goog-Update-Interactivity";
pub const HEADER_APP_ID: &str = "X-Goog-Update-AppId";
#[derive(Debug, Default, Serialize)]
pub struct Request {
#[serde(rename = "protocol")]
pub protocol_version: String,
pub updater: String,
#[serde(rename = "updaterversion")]
pub updater_version: String,
#[serde(rename = "installsource")]
pub install_source: InstallSource,
#[serde(rename = "ismachine")]
pub is_machine: bool,
#[serde(rename = "requestid")]
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<GUID>,
#[serde(rename = "sessionid")]
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<GUID>,
pub os: OS,
#[serde(rename = "app")]
pub apps: Vec<App>,
}
#[derive(Debug, Default, Serialize)]
pub struct RequestWrapper {
pub request: Request,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum InstallSource {
OnDemand,
#[default]
ScheduledTask,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct OS {
pub platform: String,
pub version: String,
#[serde(rename = "sp")]
pub service_pack: String,
pub arch: String,
}
#[derive(Debug, Default, Clone, Serialize)]
pub struct App {
#[serde(rename = "appid")]
pub id: String,
pub version: String,
#[serde(rename = "fp")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fingerprint: Option<String>,
#[serde(flatten)]
pub cohort: Option<Cohort>,
#[serde(rename = "updatecheck")]
#[serde(skip_serializing_if = "Option::is_none")]
pub update_check: Option<UpdateCheck>,
#[serde(rename = "event")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub events: Vec<Event>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ping: Option<Ping>,
#[serde(flatten)]
pub extra_fields: HashMap<String, String>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct UpdateCheck {
#[serde(skip_serializing_if = "std::ops::Not::not")]
#[serde(rename = "updatedisabled")]
pub disabled: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
#[serde(rename = "sameversionupdate")]
pub offer_update_if_same_version: bool,
}
impl UpdateCheck {
pub fn disabled() -> Self {
UpdateCheck {
disabled: true,
offer_update_if_same_version: false,
}
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize)]
pub struct Ping {
#[serde(rename = "ad")]
#[serde(skip_serializing_if = "Option::is_none")]
pub date_last_active: Option<u32>,
#[serde(rename = "rd")]
#[serde(skip_serializing_if = "Option::is_none")]
pub date_last_roll_call: Option<u32>,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize)]
pub struct Event {
#[serde(rename = "eventtype")]
pub event_type: EventType,
#[serde(rename = "eventresult")]
pub event_result: EventResult,
#[serde(skip_serializing_if = "Option::is_none")]
pub errorcode: Option<EventErrorCode>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "previousversion")]
pub previous_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "nextversion")]
pub next_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub download_time_ms: Option<u64>,
}
impl Event {
pub fn success(event_type: EventType) -> Self {
Self {
event_type,
event_result: EventResult::Success,
..Self::default()
}
}
pub fn error(errorcode: EventErrorCode) -> Self {
Self {
event_type: EventType::UpdateComplete,
event_result: EventResult::Error,
errorcode: Some(errorcode),
..Self::default()
}
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize_repr)]
#[repr(u8)]
pub enum EventType {
#[default]
Unknown = 0,
DownloadComplete = 1,
InstallComplete = 2,
UpdateComplete = 3,
UpdateDownloadStarted = 13,
UpdateDownloadFinished = 14,
RebootedAfterUpdate = 54,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize_repr)]
#[repr(u8)]
pub enum EventResult {
#[default]
Error = 0,
Success = 1,
SuccessAndRestartRequired = 2,
SuccessAndAppRestartRequired = 3,
Cancelled = 4,
ErrorInSystemInstaller = 8,
UpdateDeferred = 9,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize_repr)]
#[repr(i32)]
pub enum EventErrorCode {
#[default]
ParseResponse = 0,
ConstructInstallPlan = 1,
Installation = 2,
DeniedByPolicy = 3,
}
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct GUID {
uuid: uuid::Uuid,
}
impl GUID {
#[cfg(not(test))]
pub fn new() -> Self {
Self {
uuid: uuid::Uuid::new_v4(),
}
}
#[cfg(test)]
pub fn new() -> Self {
thread_local! {
static COUNTER: std::cell::RefCell<u128> =
const { std::cell::RefCell::new(0) };
}
COUNTER.with(|counter| {
let mut counter = counter.borrow_mut();
let guid = Self::from_u128(*counter);
*counter += 1;
guid
})
}
#[cfg(test)]
pub fn from_u128(n: u128) -> Self {
Self {
uuid: uuid::Uuid::from_u128(n),
}
}
}
impl Serialize for GUID {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.uuid.as_braced().serialize(serializer)
}
}