-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
[rust] Publish Selenium Manager as native shared library #15368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
rust/src/lib.rs
Outdated
// Exported functions | ||
// ---------------------------------------------------------- | ||
|
||
// this just an example how to expose function for external usage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bonigarcia can you please help to implement this function in rust? This function should be equivalent of selenium-manager.exe --browser chrome --browser-version 130 --browser-path /some/path --proxy some_value
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a major change, so there should be a project consensus on this feature first. Personally, I am not sure about it. Are the other bindings (in addition to .Net) following this approach?
@nvborisenko since this will be easiest for .NET, what would those bindings need to do to use this? What would be next steps/timeframe? |
I have prepared a checklist:
|
I asked big brain, seems it is easy to do for all bindings. But, yes, .NET is the easiest. |
I think this is what it would look like, and probably pretty straightforward: src/ Move the implementation details from main.rs to lib.rs I'm not sure how .NET handles streaming the logs via ffi, and I think we're also supposed to call in to free the memory once we've gotten the paths and stuff, but should all be doable. |
All the logistics for building/storing should be just updating this one file - https://github.com/SeleniumHQ/selenium/blob/trunk/.github/workflows/ci-rust.yml FFI needs a get_paths function that accepts a JSON object and returns a JSON object. We need both browser path and driver path to send back to the bindings. Service class starts the driver at the provided path, then the driver needs to reference the matching browser location when sending capabilities to the driver |
No json objects in native functions, please. We have primitive strings, numbers, booleans, delegates (callback functions).
To "stream" logs in runtime, rust will just call this delegate (pointer to function), provided by bindings. |
We need to send key value pairs back and forth, there's no primitive for a map, and everything works with json |
Structures. |
Streaming log messages is resolved (I am not care about memory leaking yet). Verified, works good. About returning of |
Excellent!
I was going to say no, but we might be able to do it in 2 method calls...
Eesh, I thought the point was to decrease the code we needed in the bindings? 😂 JSON would be a lot simpler, wouldn't require managing memory, and the overhead is going to be a lot less than what we have now. But I'm open to it. |
Memory management is resolved. Rust part is here. C# full example: using System;
using System.Runtime.InteropServices;
namespace ClassLibrary1
{
public static partial class SeleniumManager
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LogCallback(int level, string message);
private static readonly LogCallback _callback;
static SeleniumManager()
{
// Define the callback logic
_callback = (result, message) =>
{
Console.WriteLine($"Result: {result}, Message: {message}");
};
}
public static string GetDummyDriverPath(string driverName)
{
// Convert the delegate to a function pointer
IntPtr _callbackPtr = Marshal.GetFunctionPointerForDelegate(_callback);
var result = get_dummy_webdriver_path(driverName, _callbackPtr);
try
{
return Marshal.PtrToStringAnsi(result.DriverPath);
}
finally
{
free_webdriver_path_result(ref result);
}
}
[StructLayout(LayoutKind.Sequential)]
struct WebDriverPathResult
{
public bool IsSuccess;
public IntPtr DriverPath;
public IntPtr Error;
}
[DllImport("selenium_manager", CallingConvention = CallingConvention.Cdecl)]
static extern WebDriverPathResult get_dummy_webdriver_path(string driverName, IntPtr callback);
[DllImport("selenium_manager")]
static extern void free_webdriver_path_result(ref WebDriverPathResult result);
}
} And usage: Console.WriteLine(SeleniumManager.GetDummyDriverPath("chrome").DriverPath) Next step: resolve how rust will share errors (even unhandled). |
@titusfortner about |
Moved to Now, as a .NET/C# consumer, I am ready to try out real function instead of "dummy". How I see further steps:
|
log(i, message.as_ptr()); | ||
} | ||
|
||
//panic!("Intentional panic for testing"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bonigarcia can you help me here? We want to handle all panics in this block and propagate it in returning result. Seems I do it incorrectly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't have bandwidth for the following weeks. In any case, this deserves to be discussed in the following Selenium Dev Summit in Valencia (24-25 March).
Earlier benchmark results, where
Mean : Arithmetic mean of all measurements |
So, for Windows you'd update the
In Release Job
|
Doing more research...
ffi is like:
Then everything that is in main now needs to get put into |
User description
This is a PR for ongoing collaboration to make Selenium Manager be shipped as native library (C-compatible dynamic library).
Motivation and Context
Implements #15355
Checklist
cargo build
should produce 3 output types (executable, rust lib, native shared lib)bazel
where it is requiredsm.exe --browser chrome
, but now as a function)Types of changes
Checklist
PR Type
Enhancement
Description
Added support for building Selenium Manager as a shared library.
Introduced a new
rust_shared_library
target in Bazel build files.Exported a sample Rust function (
get_test
) for external usage.Updated
Cargo.toml
to define library crate types.Changes walkthrough 📝
defs.bzl
Introduced `rust_shared_library` in Bazel definitions
rust/defs.bzl
rust_shared_library
to the list of available Rust build targets.rustfmt_wrapper.bzl
Added `rust_shared_library` to formatting wrapper
rust/private/rustfmt_wrapper.bzl
rust_shared_library
to the wrapper functions.BUILD.bazel
Defined `rust_shared_library` target in Bazel
rust/BUILD.bazel
rust_shared_library
target for Selenium Manager.Cargo.toml
Updated Cargo.toml for shared library support
rust/Cargo.toml
cdylib
andrlib
).lib.rs
Added exported function for shared library usage
rust/src/lib.rs
get_test
for external usage.