瀏覽代碼

WebDriver: Specify callbacks for clients to launch browser windows

This moves the actual launching of browser windows to the WebDriver main
file. This will allow Ladybird to specify its own callback and re-use
Serenity's Session class.
Timothy Flynn 2 年之前
父節點
當前提交
956fa84f12

+ 8 - 4
Userland/Services/WebDriver/Client.cpp

@@ -20,14 +20,18 @@ namespace WebDriver {
 Atomic<unsigned> Client::s_next_session_id;
 Atomic<unsigned> Client::s_next_session_id;
 NonnullOwnPtrVector<Session> Client::s_sessions;
 NonnullOwnPtrVector<Session> Client::s_sessions;
 
 
-ErrorOr<NonnullRefPtr<Client>> Client::try_create(NonnullOwnPtr<Core::Stream::BufferedTCPSocket> socket, Core::Object* parent)
+ErrorOr<NonnullRefPtr<Client>> Client::try_create(NonnullOwnPtr<Core::Stream::BufferedTCPSocket> socket, LaunchBrowserCallbacks callbacks, Core::Object* parent)
 {
 {
+    if (!callbacks.launch_browser || !callbacks.launch_headless_browser)
+        return Error::from_string_view("All callbacks to launch a browser must be provided"sv);
+
     TRY(socket->set_blocking(true));
     TRY(socket->set_blocking(true));
-    return adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), parent));
+    return adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), move(callbacks), parent));
 }
 }
 
 
-Client::Client(NonnullOwnPtr<Core::Stream::BufferedTCPSocket> socket, Core::Object* parent)
+Client::Client(NonnullOwnPtr<Core::Stream::BufferedTCPSocket> socket, LaunchBrowserCallbacks callbacks, Core::Object* parent)
     : Web::WebDriver::Client(move(socket), parent)
     : Web::WebDriver::Client(move(socket), parent)
+    , m_callbacks(move(callbacks))
 {
 {
 }
 }
 
 
@@ -154,7 +158,7 @@ Web::WebDriver::Response Client::new_session(Web::WebDriver::Parameters, JsonVal
     Web::WebDriver::LadybirdOptions options { capabilities.as_object() };
     Web::WebDriver::LadybirdOptions options { capabilities.as_object() };
     auto session = make<Session>(session_id, *this, move(options));
     auto session = make<Session>(session_id, *this, move(options));
 
 
-    if (auto start_result = session->start(); start_result.is_error())
+    if (auto start_result = session->start(m_callbacks); start_result.is_error())
         return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::SessionNotCreated, DeprecatedString::formatted("Failed to start session: {}", start_result.error().string_literal()));
         return Web::WebDriver::Error::from_code(Web::WebDriver::ErrorCode::SessionNotCreated, DeprecatedString::formatted("Failed to start session: {}", start_result.error().string_literal()));
 
 
     auto& web_content_connection = session->web_content_connection();
     auto& web_content_connection = session->web_content_connection();

+ 10 - 2
Userland/Services/WebDriver/Client.h

@@ -8,6 +8,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AK/Function.h>
 #include <AK/NonnullOwnPtrVector.h>
 #include <AK/NonnullOwnPtrVector.h>
 #include <LibCore/Object.h>
 #include <LibCore/Object.h>
 #include <LibCore/Stream.h>
 #include <LibCore/Stream.h>
@@ -18,17 +19,22 @@
 
 
 namespace WebDriver {
 namespace WebDriver {
 
 
+struct LaunchBrowserCallbacks {
+    Function<ErrorOr<pid_t>(DeprecatedString const&)> launch_browser;
+    Function<ErrorOr<pid_t>(DeprecatedString const&)> launch_headless_browser;
+};
+
 class Client final : public Web::WebDriver::Client {
 class Client final : public Web::WebDriver::Client {
     C_OBJECT_ABSTRACT(Client);
     C_OBJECT_ABSTRACT(Client);
 
 
 public:
 public:
-    static ErrorOr<NonnullRefPtr<Client>> try_create(NonnullOwnPtr<Core::Stream::BufferedTCPSocket>, Core::Object* parent);
+    static ErrorOr<NonnullRefPtr<Client>> try_create(NonnullOwnPtr<Core::Stream::BufferedTCPSocket>, LaunchBrowserCallbacks, Core::Object* parent);
     virtual ~Client() override;
     virtual ~Client() override;
 
 
     void close_session(unsigned session_id);
     void close_session(unsigned session_id);
 
 
 private:
 private:
-    Client(NonnullOwnPtr<Core::Stream::BufferedTCPSocket>, Core::Object* parent);
+    Client(NonnullOwnPtr<Core::Stream::BufferedTCPSocket>, LaunchBrowserCallbacks, Core::Object* parent);
 
 
     ErrorOr<Session*, Web::WebDriver::Error> find_session_with_id(StringView session_id);
     ErrorOr<Session*, Web::WebDriver::Error> find_session_with_id(StringView session_id);
     ErrorOr<NonnullOwnPtr<Session>, Web::WebDriver::Error> take_session_with_id(StringView session_id);
     ErrorOr<NonnullOwnPtr<Session>, Web::WebDriver::Error> take_session_with_id(StringView session_id);
@@ -87,6 +93,8 @@ private:
 
 
     static NonnullOwnPtrVector<Session> s_sessions;
     static NonnullOwnPtrVector<Session> s_sessions;
     static Atomic<unsigned> s_next_session_id;
     static Atomic<unsigned> s_next_session_id;
+
+    LaunchBrowserCallbacks m_callbacks;
 };
 };
 
 
 }
 }

+ 5 - 21
Userland/Services/WebDriver/Session.cpp

@@ -58,33 +58,17 @@ ErrorOr<NonnullRefPtr<Core::LocalServer>> Session::create_server(DeprecatedStrin
     return server;
     return server;
 }
 }
 
 
-ErrorOr<void> Session::start()
+ErrorOr<void> Session::start(LaunchBrowserCallbacks const& callbacks)
 {
 {
     auto promise = TRY(ServerPromise::try_create());
     auto promise = TRY(ServerPromise::try_create());
 
 
     auto web_content_socket_path = DeprecatedString::formatted("{}/webdriver/session_{}_{}", TRY(Core::StandardPaths::runtime_directory()), getpid(), m_id);
     auto web_content_socket_path = DeprecatedString::formatted("{}/webdriver/session_{}_{}", TRY(Core::StandardPaths::runtime_directory()), getpid(), m_id);
     auto web_content_server = TRY(create_server(web_content_socket_path, promise));
     auto web_content_server = TRY(create_server(web_content_socket_path, promise));
 
 
-    if (m_options.headless) {
-        char const* argv[] = {
-            "/bin/headless-browser",
-            "--webdriver-ipc-path",
-            web_content_socket_path.characters(),
-            "about:blank",
-            nullptr,
-        };
-
-        m_browser_pid = TRY(Core::System::posix_spawn("/bin/headless-browser"sv, nullptr, nullptr, const_cast<char**>(argv), environ));
-    } else {
-        char const* argv[] = {
-            "/bin/Browser",
-            "--webdriver-content-path",
-            web_content_socket_path.characters(),
-            nullptr,
-        };
-
-        m_browser_pid = TRY(Core::System::posix_spawn("/bin/Browser"sv, nullptr, nullptr, const_cast<char**>(argv), environ));
-    }
+    if (m_options.headless)
+        m_browser_pid = TRY(callbacks.launch_headless_browser(web_content_socket_path));
+    else
+        m_browser_pid = TRY(callbacks.launch_browser(web_content_socket_path));
 
 
     // FIXME: Allow this to be more asynchronous. For now, this at least allows us to propagate
     // FIXME: Allow this to be more asynchronous. For now, this at least allows us to propagate
     //        errors received while accepting the Browser and WebContent sockets.
     //        errors received while accepting the Browser and WebContent sockets.

+ 3 - 1
Userland/Services/WebDriver/Session.h

@@ -19,6 +19,8 @@
 
 
 namespace WebDriver {
 namespace WebDriver {
 
 
+struct LaunchBrowserCallbacks;
+
 class Session {
 class Session {
 public:
 public:
     Session(unsigned session_id, NonnullRefPtr<Client> client, Web::WebDriver::LadybirdOptions options);
     Session(unsigned session_id, NonnullRefPtr<Client> client, Web::WebDriver::LadybirdOptions options);
@@ -32,7 +34,7 @@ public:
         return *m_web_content_connection;
         return *m_web_content_connection;
     }
     }
 
 
-    ErrorOr<void> start();
+    ErrorOr<void> start(LaunchBrowserCallbacks const&);
     Web::WebDriver::Response stop();
     Web::WebDriver::Response stop();
 
 
 private:
 private:

+ 26 - 1
Userland/Services/WebDriver/main.cpp

@@ -13,6 +13,31 @@
 #include <LibMain/Main.h>
 #include <LibMain/Main.h>
 #include <WebDriver/Client.h>
 #include <WebDriver/Client.h>
 
 
+static ErrorOr<pid_t> launch_browser(DeprecatedString const& socket_path)
+{
+    char const* argv[] = {
+        "/bin/Browser",
+        "--webdriver-content-path",
+        socket_path.characters(),
+        nullptr,
+    };
+
+    return Core::System::posix_spawn("/bin/Browser"sv, nullptr, nullptr, const_cast<char**>(argv), environ);
+}
+
+static ErrorOr<pid_t> launch_headless_browser(DeprecatedString const& socket_path)
+{
+    char const* argv[] = {
+        "/bin/headless-browser",
+        "--webdriver-ipc-path",
+        socket_path.characters(),
+        "about:blank",
+        nullptr,
+    };
+
+    return Core::System::posix_spawn("/bin/headless-browser"sv, nullptr, nullptr, const_cast<char**>(argv), environ);
+}
+
 ErrorOr<int> serenity_main(Main::Arguments arguments)
 ErrorOr<int> serenity_main(Main::Arguments arguments)
 {
 {
     DeprecatedString default_listen_address = "0.0.0.0";
     DeprecatedString default_listen_address = "0.0.0.0";
@@ -62,7 +87,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
             return;
             return;
         }
         }
 
 
-        auto maybe_client = WebDriver::Client::try_create(maybe_buffered_socket.release_value(), server);
+        auto maybe_client = WebDriver::Client::try_create(maybe_buffered_socket.release_value(), { launch_browser, launch_headless_browser }, server);
         if (maybe_client.is_error()) {
         if (maybe_client.is_error()) {
             warnln("Could not create a WebDriver client: {}", maybe_client.error());
             warnln("Could not create a WebDriver client: {}", maybe_client.error());
             return;
             return;