Skip to content

Commit

Permalink
[rust] Send stats to Plausible (#11211)
Browse files Browse the repository at this point in the history
  • Loading branch information
bonigarcia committed Nov 18, 2023
1 parent eb0a321 commit 64e81e8
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
2 changes: 2 additions & 0 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct ManagerConfig {
pub offline: bool,
pub force_browser_download: bool,
pub avoid_browser_download: bool,
pub language_binding: String,
}

impl ManagerConfig {
Expand Down Expand Up @@ -111,6 +112,7 @@ impl ManagerConfig {
offline: BooleanKey("offline", false).get_value(),
force_browser_download: BooleanKey("force-browser-download", false).get_value(),
avoid_browser_download: BooleanKey("avoid-browser-download", false).get_value(),
language_binding: StringKey(vec!["language-binding"], "").get_value(),
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use crate::safaritp::{SafariTPManager, SAFARITP_NAMES};
use crate::shell::{
run_shell_command, run_shell_command_by_os, run_shell_command_with_log, split_lines, Command,
};
use crate::stats::{send_stats_to_plausible, Props};
use anyhow::anyhow;
use anyhow::Error;
use is_executable::IsExecutable;
Expand All @@ -61,6 +62,7 @@ pub mod mirror;
pub mod safari;
pub mod safaritp;
pub mod shell;
pub mod stats;

pub const REQUEST_TIMEOUT_SEC: u64 = 300; // The timeout is applied from when the request starts connecting until the response body has finished
pub const STABLE: &str = "stable";
Expand Down Expand Up @@ -111,6 +113,7 @@ pub const NOT_ADMIN_FOR_EDGE_INSTALLER_ERR_MSG: &str =
"{} can only be installed in Windows with administrator permissions";
pub const ONLINE_DISCOVERY_ERROR_MESSAGE: &str = "Unable to discover {}{} in online repository";
pub const UNC_PREFIX: &str = r"\\?\";
pub const SM_BETA_LABEL: &str = "0.";

pub trait SeleniumManager {
// ----------------------------------------------------------
Expand Down Expand Up @@ -825,6 +828,20 @@ pub trait SeleniumManager {
Ok(driver_path)
}

fn stats(&self) {
let sm_version = env!("CARGO_PKG_VERSION");
let selenium_version = sm_version.strip_prefix(SM_BETA_LABEL).unwrap_or(sm_version);
let props = Props {
browser: self.get_browser_name().to_string(),
browser_version: self.get_browser_version().to_string(),
os: self.get_os().to_string(),
arch: self.get_arch().to_string(),
lang: self.get_language_binding().to_string(),
selenium_version: selenium_version.to_string(),
};
send_stats_to_plausible(self.get_http_client(), props, self.get_logger());
}

fn check_error_with_driver_in_path(
&mut self,
is_driver_in_path: &bool,
Expand Down Expand Up @@ -1395,6 +1412,16 @@ pub trait SeleniumManager {
self.get_config_mut().cache_path = cache_path;
}
}

fn get_language_binding(&self) -> &str {
self.get_config().language_binding.as_str()
}

fn set_language_binding(&mut self, language_binding: String) {
if !language_binding.is_empty() {
self.get_config_mut().language_binding = language_binding;
}
}
}

// ----------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ struct Cli {
/// Avoid to download browser (even when browser-version is specified)
#[clap(long)]
avoid_browser_download: bool,

/// Selenium language bindings that invokes Selenium Manager (e.g., Java, JavaScript, Python,
/// DotNet, Ruby)
#[clap(long)]
language_binding: Option<String>,
}

fn main() {
Expand Down Expand Up @@ -197,6 +202,7 @@ fn main() {
selenium_manager.set_avoid_browser_download(cli.avoid_browser_download);
selenium_manager.set_cache_path(cache_path.clone());
selenium_manager.set_offline(cli.offline);
selenium_manager.set_language_binding(cli.language_binding.unwrap_or_default());

if cli.clear_cache || BooleanKey("clear-cache", false).get_value() {
clear_cache(selenium_manager.get_logger(), &cache_path);
Expand All @@ -212,6 +218,7 @@ fn main() {
.map(|driver_path| {
let log = selenium_manager.get_logger();
log_driver_and_browser_path(log, &driver_path, selenium_manager.get_browser_path());
selenium_manager.stats();
flush_and_exit(OK, log, None);
})
.unwrap_or_else(|err| {
Expand Down
75 changes: 75 additions & 0 deletions rust/src/stats.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::format_one_arg;
use crate::logger::Logger;
use reqwest::header::CONTENT_TYPE;
use reqwest::header::USER_AGENT;
use reqwest::Client;
use serde::{Deserialize, Serialize};

const PLAUSIBLE_URL: &str = "https://plausible.io/api/event";
const SM_USER_AGENT: &str = "Selenium Manager {}";
const APP_JSON: &str = "application/json";
const PAGE_VIEW: &str = "pageview";
const SELENIUM_DOMAIN: &str = "bonigarcia.dev"; // TODO change with selenium.dev
const SM_STATS_URL: &str = "https://{}/sm-stats";

#[derive(Default, Serialize, Deserialize)]
pub struct Data {
pub name: String,
pub url: String,
pub domain: String,
pub props: Props,
}

#[derive(Default, Serialize, Deserialize)]
pub struct Props {
pub browser: String,
pub browser_version: String,
pub os: String,
pub arch: String,
pub lang: String,
pub selenium_version: String,
}

#[tokio::main]
pub async fn send_stats_to_plausible(http_client: &Client, props: Props, log: &Logger) {
let sm_version = env!("CARGO_PKG_VERSION");
let user_agent = format_one_arg(SM_USER_AGENT, sm_version);
let sm_stats_url = format_one_arg(SM_STATS_URL, SELENIUM_DOMAIN);

let data = Data {
name: PAGE_VIEW.to_string(),
url: sm_stats_url,
domain: SELENIUM_DOMAIN.to_string(),
props,
};
let body = serde_json::to_string(&data).unwrap_or_default();
log.trace(format!("Sending props to plausible: {}", body));

let request = http_client
.post(PLAUSIBLE_URL)
.header(USER_AGENT, user_agent)
.header(CONTENT_TYPE, APP_JSON)
.body(body);
// TODO proxy

if let Err(err) = request.send().await {
log.warn(format!("Error sending stats to Plausible: {}", err));
}
}

0 comments on commit 64e81e8

Please sign in to comment.