diff --git a/rust/BUILD.bazel b/rust/BUILD.bazel index 0a29911e1b9fc..e4912b0103d00 100644 --- a/rust/BUILD.bazel +++ b/rust/BUILD.bazel @@ -1,5 +1,5 @@ load("@crates//:defs.bzl", "all_crate_deps") -load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_test", "rustfmt_config") +load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_shared_library", "rust_test", "rustfmt_config") rustfmt_config( name = "enable-rustfmt", @@ -96,6 +96,18 @@ rust_library( deps = all_crate_deps(normal = True), ) +rust_shared_library( + # The name here is used as the crate name + name = "selenium_manager_shared", + srcs = glob( + ["src/**/*.rs"], + exclude = ["main.rs"], + ), + edition = "2021", + visibility = ["//rust:__subpackages__"], + deps = all_crate_deps(normal = True), +) + filegroup( name = "selenium_manager_srcs", srcs = [ diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index f836f33c9d56a..dfa7a31e57523 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "e68bc8d92875cfa0a3769e6e31b05c99d2669f20fda466dd415ef9dcbd361b7d", + "checksum": "04c2f1c8b7c0ac539b226b5da83b0b41311961e3c8b2fed1a3dfae76721fec9c", "crates": { "addr2line 0.21.0": { "name": "addr2line", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 90df54f36e359..196ea74dd8a15 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -11,6 +11,13 @@ description = """ Selenium Manager is a CLI tool that automatically manages the browser/driver infrastructure required by Selenium. """ +[[bin]] +name = "selenium-manager" + +[lib] +name = "selenium_manager" +crate-type = ["cdylib", "rlib"] + [dependencies] clap = { version = "4.5.23", features = ["derive", "cargo"] } log = "0.4.22" diff --git a/rust/defs.bzl b/rust/defs.bzl index bad75bf29de23..477a42d08a251 100644 --- a/rust/defs.bzl +++ b/rust/defs.bzl @@ -3,12 +3,14 @@ load( "//rust/private:rustfmt_wrapper.bzl", _rust_binary = "rust_binary", _rust_library = "rust_library", + _rust_shared_library = "rust_shared_library", _rust_test = "rust_test", _rust_test_suite = "rust_test_suite", ) rust_binary = _rust_binary rust_library = _rust_library +rust_shared_library = _rust_shared_library rust_test = _rust_test rust_test_suite = _rust_test_suite rustfmt_config = _rustfmt_config diff --git a/rust/private/rustfmt_wrapper.bzl b/rust/private/rustfmt_wrapper.bzl index fbaa3bde53c79..cfa2915731b62 100644 --- a/rust/private/rustfmt_wrapper.bzl +++ b/rust/private/rustfmt_wrapper.bzl @@ -4,6 +4,7 @@ load( "rustfmt_test", _rust_binary = "rust_binary", _rust_library = "rust_library", + _rust_shared_library = "rust_shared_library", _rust_test = "rust_test", _rust_test_suite = "rust_test_suite", ) @@ -27,6 +28,10 @@ def rust_library(name, **kwargs): _rust_library(name = name, **kwargs) _wrap_with_fmt_test(name, kwargs.get("tags", [])) +def rust_shared_library(name, **kwargs): + _rust_shared_library(name = name, **kwargs) + _wrap_with_fmt_test(name, kwargs.get("tags", [])) + def rust_binary(name, **kwargs): _rust_binary(name = name, **kwargs) _wrap_with_fmt_test(name, kwargs.get("tags", [])) diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs new file mode 100644 index 0000000000000..ba521d2bba145 --- /dev/null +++ b/rust/src/ffi.rs @@ -0,0 +1,91 @@ +// 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 std::{ffi::{c_char, c_int, CStr, CString}, ptr::null_mut}; + +// this is callback function to be called each time when rust wants to send log data +type LogCallback = extern "C" fn(level: c_int, message: *const std::os::raw::c_char); + +#[repr(C)] +pub struct WebDriverPathResult { + success: bool, + driver_path: *mut c_char, + error: *mut c_char, +} + +// this is just an example how to expose function for external usage +#[no_mangle] +pub extern "C" fn get_dummy_webdriver_path(driver_name: *const c_char, log: LogCallback) -> WebDriverPathResult { + let result = std::panic::catch_unwind(|| { + + for i in 1..6 { + let message = CString::new("Hello, I am logging message").unwrap(); + //let message = CString::new(String::from("A").repeat(10_000_000)).unwrap(); + log(i, message.as_ptr()); + } + + //panic!("Intentional panic for testing"); + + let driver = unsafe { CStr::from_ptr(driver_name).to_str().unwrap() }; + + return CString::new("This is dummy driver path for ".to_owned() + driver).unwrap().into_raw(); + //return CString::new(String::from("A").repeat(10_000_000)).unwrap().into_raw(); + }); + + match result { + Ok(driver_path) => WebDriverPathResult { + success: true, + driver_path, + error: null_mut(), + }, + Err(panic) => WebDriverPathResult { + success: false, + driver_path: null_mut(), + error: CString::new(extract_panic_message(panic)).unwrap().into_raw(), + } + } +} + +#[no_mangle] +pub extern "C" fn free_webdriver_path_result(result: *mut WebDriverPathResult) { + if result.is_null() { + return; + } + unsafe { + let ffi_result = &mut *result; + if !ffi_result.driver_path.is_null() { + // Reconstruct CString to drop it and free memory + let _ = CString::from_raw(ffi_result.driver_path); + } + if !ffi_result.error.is_null() { + // Reconstruct CString to drop it and free memory + let _ = CString::from_raw(ffi_result.error); + } + } +} + +/// Extract panic message from `Box` +fn extract_panic_message(panic: Box) -> String { + // Try to downcast to common panic types + if let Some(s) = panic.downcast_ref::() { + s.clone() + } else if let Some(s) = panic.downcast_ref::<&str>() { + s.to_string() + } else { + "Unknown panic (non-string payload)".to_string() + } +} \ No newline at end of file diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a2c2411bcb763..2308dccb55673 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -68,6 +68,8 @@ pub mod safaritp; pub mod shell; pub mod stats; +mod ffi; + 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"; pub const BETA: &str = "beta";