Last active
November 28, 2021 08:53
-
-
Save estin/fca8782e5805403423207b7b67eba8f6 to your computer and use it in GitHub Desktop.
Rust Webkit2GTK Ping Pong Example https://www.reddit.com/r/rust/comments/p79nlm/rust_webkit2gtk_ping_pong_example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ### Usage | |
// $ cargo run | |
// open develop consonle on opened browser | |
// and execute in consle myPostMessage("it works").then(r => console.log("Result is:", r)); | |
// ### Cargo.toml | |
// | |
// [package] | |
// name = "reddit-ex" | |
// version = "0.1.0" | |
// edition = "2018" | |
// [dependencies] | |
// glib = "0.14" | |
// gtk = "0.14" | |
// gio = "0.14" | |
// webkit2gtk = { version = "0.14", features = ["v2_26"] } | |
// serde = { version = "1.0", features = ["derive"] } | |
// serde_json = "1.0" | |
// src/main.rs | |
use gio::Cancellable; | |
use gtk::{ | |
traits::{ContainerExt, WidgetExt}, | |
Inhibit, Window, WindowType, | |
}; | |
use serde::{Deserialize, Serialize}; | |
use webkit2gtk::traits::{SettingsExt, UserContentManagerExt, WebViewExt}; | |
use webkit2gtk::{self, LoadEvent, UserContentManager, WebContext, WebView, WebViewExtManual}; | |
#[derive(Deserialize)] | |
struct Request { | |
id: usize, | |
data: serde_json::Value, | |
} | |
#[derive(Serialize)] | |
struct Response { | |
id: usize, | |
data: serde_json::Value, | |
} | |
fn main() { | |
gtk::init().unwrap(); | |
let window = Window::new(WindowType::Toplevel); | |
let context = WebContext::default().unwrap(); | |
let ucm = UserContentManager::new(); | |
let webview = WebView::new_with_context_and_user_content_manager(&context, &ucm); | |
webview.load_uri("https://crates.io/"); | |
window.add(&webview); | |
let settings = WebViewExt::settings(&webview).unwrap(); | |
settings.set_enable_developer_extras(true); | |
// On page load inject javascript to handle request-response communication | |
webview.connect_load_changed(|wv, event| { | |
if event != LoadEvent::Finished { | |
return; | |
} | |
let cancellable: Option<&Cancellable> = None; | |
wv.run_javascript( | |
" | |
window._requests = {}; | |
window._request_id = 0; | |
window.myPostMessage = function (data) { | |
return new Promise((resolve, reject) => { | |
window._request_id += 1; | |
window._requests[window._request_id] = [resolve, reject]; | |
let request = JSON.stringify({id: window._request_id, data: data}); | |
console.log('Request', request); | |
window.webkit.messageHandlers.external.postMessage(request); | |
}); | |
}; | |
window._myPostMessageResponse = function(response) { | |
console.log('Response', response); | |
let [resolve, reject] = window._requests[response.id]; | |
resolve(response.data); | |
delete window._requests[response.id]; | |
}; | |
", | |
cancellable, | |
|result| { | |
println!("inject internal js code result {:?}", result); | |
}, | |
); | |
}); | |
window.show_all(); | |
webview | |
.user_content_manager() | |
.unwrap() | |
.register_script_message_handler("external"); | |
webview | |
.user_content_manager() | |
.unwrap() | |
.connect_script_message_received(Some("external"), move |_ucm, jsr| { | |
let ctx = jsr.global_context().unwrap(); | |
let val = jsr.value().unwrap(); | |
let request = val.to_string(&ctx).unwrap(); | |
println!("Request {}", request); | |
let request: Request = serde_json::from_str(&request).unwrap(); | |
// Some app logic | |
// TODO | |
// genereate response | |
let response = serde_json::to_string(&Response { | |
id: request.id, | |
data: serde_json::Value::String(format!("pong: {}", request.data)), | |
}) | |
.unwrap(); | |
println!("Response {}", response); | |
let cancellable: Option<&Cancellable> = None; | |
webview.run_javascript( | |
&format!("window._myPostMessageResponse({});", response), | |
cancellable, | |
|result| { | |
println!("myPostMessageResponse result {:?}", result); | |
}, | |
); | |
}); | |
window.connect_delete_event(|_, _| { | |
gtk::main_quit(); | |
Inhibit(false) | |
}); | |
gtk::main(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment