Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/sync15/src/clients_engine/   (Firefox Browser Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 7 kB image not shown  

Quelle  record.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


use serde_derive::*;

use super::Command;

/// The serialized form of a client record.
#[derive(Clone, Debug, Eq, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ClientRecord {
    #[serde(rename = "id")]
    pub id: String,

    pub name: String,

    #[serde(rename = "type")]
    pub typ: crate::DeviceType,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub commands: Vec<CommandRecord>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub fxa_device_id: Option<String>,

    /// `version`, `protocols`, `formfactor`, `os`, `appPackage`, `application`,
    /// and `device` are unused and optional in all implementations (Desktop,
    /// iOS, and Fennec), but we round-trip them.

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub protocols: Vec<String>,

    #[serde(
        default,
        rename = "formfactor",
        skip_serializing_if = "Option::is_none"
    )]
    pub form_factor: Option<String>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub os: Option<String>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub app_package: Option<String>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub application: Option<String>,

    /// The model of the device, like "iPhone" or "iPod touch" on iOS. Note
    /// that this is _not_ the client ID (`id`) or the FxA device ID
    /// (`fxa_device_id`).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub device: Option<String>,
}

impl From<&ClientRecord> for crate::RemoteClient {
    fn from(record: &ClientRecord) -> crate::RemoteClient {
        crate::RemoteClient {
            fxa_device_id: record.fxa_device_id.clone(),
            device_name: record.name.clone(),
            device_type: record.typ,
        }
    }
}

/// The serialized form of a client command.
#[derive(Clone, Debug, Eq, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CommandRecord {
    /// The command name. This is a string, not an enum, because we want to
    /// round-trip commands that we don't support yet.
    #[serde(rename = "command")]
    pub name: String,

    /// Extra, command-specific arguments. Note that we must send an empty
    /// array if the command expects no arguments.
    #[serde(default)]
    pub args: Vec<Option<String>>,

    /// Some commands, like repair, send a "flow ID" that other cliennts can
    /// record in their telemetry. We don't currently send commands with
    /// flow IDs, but we round-trip them.
    #[serde(default, rename = "flowID", skip_serializing_if = "Option::is_none")]
    pub flow_id: Option<String>,
}

impl CommandRecord {
    // In an ideal future we'd treat non-string args as "soft errors" rather than a hard
    // serde failure, but there's no evidence we actually see these. There *is* evidence of
    // seeing nulls instead of strings though (presumably due to old sendTab commands), so we
    // do handle that.
    fn get_single_string_arg(&self) -> Option<String> {
        let cmd_name = &self.name;
        if self.args.len() == 1 {
            match &self.args[0] {
                Some(name) => Some(name.into()),
                None => {
                    log::error!("Incoming '{cmd_name}' command has null argument");
                    None
                }
            }
        } else {
            log::error!(
                "Incoming '{cmd_name}' command has wrong number of arguments ({})",
                self.args.len()
            );
            None
        }
    }

    /// Converts a serialized command into one that we can apply. Returns `None`
    /// if we don't support the command.
    pub fn as_command(&self) -> Option<Command> {
        match self.name.as_str() {
            "wipeEngine" => self.get_single_string_arg().map(Command::Wipe),
            "resetEngine" => self.get_single_string_arg().map(Command::Reset),
            "resetAll" => {
                if self.args.is_empty() {
                    Some(Command::ResetAll)
                } else {
                    log::error!("Invalid arguments for 'resetAll' command");
                    None
                }
            }
            // Note callers are expected to log on an unknown command.
            _ => None,
        }
    }
}

impl From<Command> for CommandRecord {
    fn from(command: Command) -> CommandRecord {
        match command {
            Command::Wipe(engine) => CommandRecord {
                name: "wipeEngine".into(),
                args: vec![Some(engine)],
                flow_id: None,
            },
            Command::Reset(engine) => CommandRecord {
                name: "resetEngine".into(),
                args: vec![Some(engine)],
                flow_id: None,
            },
            Command::ResetAll => CommandRecord {
                name: "resetAll".into(),
                args: Vec::new(),
                flow_id: None,
            },
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_valid_commands() {
        let ser = serde_json::json!({"command""wipeEngine""args": ["foo"]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), Some(Command::Wipe("foo".to_string())));

        let ser = serde_json::json!({"command""resetEngine""args": ["foo"]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), Some(Command::Reset("foo".to_string())));

        let ser = serde_json::json!({"command""resetAll"});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), Some(Command::ResetAll));
    }

    #[test]
    fn test_unknown_command() {
        let ser = serde_json::json!({"command""unknown""args": ["foo""bar"]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), None);
    }

    #[test]
    fn test_bad_args() {
        let ser = serde_json::json!({"command""wipeEngine""args": ["foo""bar"]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), None);

        let ser = serde_json::json!({"command""wipeEngine"});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), None);

        let ser = serde_json::json!({"command""resetAll""args": ["foo"]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), None);
    }

    #[test]
    fn test_null_args() {
        let ser = serde_json::json!({"command""unknown""args": ["foo", null]});
        let record: CommandRecord = serde_json::from_value(ser).unwrap();
        assert_eq!(record.as_command(), None);
    }
}

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-07-05) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.