rustwasm / wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript
https://rustwasm.github.io/docs/wasm-bindgen/
Apache License 2.0
7.67k stars 1.06k forks source link

The geolocation callback functions yield empty structs #2491

Open torhovland opened 3 years ago

torhovland commented 3 years ago

Describe the Bug

Given the following code:

            let window = web_sys::window().expect("Unable to get browser window");
            let navigator = window.navigator();
            let geolocation = navigator.geolocation().expect("Unable to get geolocation");
            let geo_callback_function =
                Closure::wrap(Box::new(|pos| geo_callback(pos)) as Box<dyn Fn(JsValue)>);
            geolocation
                .get_current_position(&geo_callback_function.as_ref().unchecked_ref())
                .expect("Unable to get position");
            geo_callback_function.forget();

and the following callback function:

fn geo_callback(position: JsValue) {
    let s = js_sys::JSON::stringify(&position).expect("Unable to stringify JSON");
    info!("Geo callback: {:?}", s);
}

the result is simply:

Geo callback: "{}"

In other words, the returned GeolocationPosition doesn't contain the coords and timestamp properties that it should have.

Expected Behavior

The sample geo_callback function above should log coordinates and a timestamp.

Actual Behavior

Geo callback: "{}"

Additional Context

It looks like this is related to https://stackoverflow.com/questions/32882035/cordova-geolocation-plugin-returning-empty-position-object-on-android/34302473#34302473

That indicates that GeolocationPosition doesn't contain actual properties, but getters. How do we make that work through wasm-bindgen?

As a workaround, I am able to execute the geolocation code in Javascript, extract the values I need from GeolocationPosition and pass them to Rust using wasm-bindgen.

ghost commented 3 years ago

As always, one can access those getters via Reflect::get, and stringify manually, if wasm-bindgen doesn't expose an API correctly, at least, until it does.

torhovland commented 3 years ago

Interesting! I'll try that as a possible better workaround.

torhovland commented 3 years ago

Also, with help from "Calculator" on Discord, I got this working:

#[wasm_bindgen]
extern "C" {
    type GeolocationCoordinates;

    #[wasm_bindgen(method, getter)]
    fn latitude(this: &GeolocationCoordinates) -> f64;

    #[wasm_bindgen(method, getter)]
    fn longitude(this: &GeolocationCoordinates) -> f64;

    type GeolocationPosition;

    #[wasm_bindgen(method, getter)]
    fn coords(this: &GeolocationPosition) -> GeolocationCoordinates;
}

fn geo_callback(position: JsValue) {
    let pos = JsCast::unchecked_into::<GeolocationPosition>(position);
    let coords = pos.coords();
    info!(
        "Latitude: {}. Longitude: {}.",
        coords.latitude(),
        coords.longitude()
    );
}
mkroehnert commented 3 years ago

@torhovland thanks to your blogpost on the OSM app and this issue report, I could get Geolocation to work myself.

@CrimsonCodes0 what I found out is, that the WebIDL checked into the repository does not seem to match the latest draft.

I found the following differences compared to the latest draft:

Would making this up to date 'just' involve changing the IDL file? Or is there a specific reason to keep this at the currently checked in version?

mkroehnert commented 3 years ago

@torhovland I updated the bindings on the following branch https://github.com/mkroehnert/wasm-bindgen/tree/update-web-sys-geolocation

Will need to do some more testing before opening a pullrequest.