2017-07-21 18 views
10

Tôi đang cố gắng tạo một nhân viên web từ Rust, gọi một hàm trong tệp công nhân và chuyển một số dữ liệu đến chuỗi chính.Tạo công nhân web từ Rust với mục tiêu Emscripten

main.rs

mod externs; 
extern crate libc; 

fn main() { 
    println!("starting worker"); 
    let worker = externs::create_worker("./worker.js"); 
    externs::call_worker(worker, "worker_fn", "", 0); 
    println!("worker called"); 
} 

worker.rs

#![feature(link_args)] 
#[link_args = "-s EXPORTED_FUNCTIONS=['_worker_fn'] -s BUILD_AS_WORKER=1"] 

extern crate libc; 

mod externs; 

extern {} 

fn main() { 
    println!("worker main"); 
} 

#[no_mangle] 
pub extern fn worker_fn() { 
    println!("hello from the other side!"); 
} 

Khi tôi biên dịch các tập tin người lao động và chính, tôi có thể nhìn thấy thông báo từ main.rs và thậm chí cả thông báo "công nhân chính" trong tệp công nhân. Tôi cũng có thể thấy rằng trình duyệt gửi yêu cầu đến worker.js, nhưng có vẻ như chuỗi chính không gọi worker_fn bên trong tệp công nhân.

Đây là externs file:

use std::ffi::CString; 
use libc::*; 
use std::str::FromStr; 

/// Creating web worker 
pub fn create_worker(url: &str) -> ffi::worker_handle { 
    let url = CString::new(url).unwrap(); 
    let ptr = url.as_ptr(); 
    unsafe { ffi::emscripten_create_worker(ptr) } 
} 

extern "C" fn do_something_handler(arg1: *mut c_char, arg2: c_int, arg3: *mut c_void) { 
    println!("worker done!"); 
} 

/// Creating web worker 
pub fn call_worker(worker: ffi::worker_handle, func_name: &str, data: &str, size: i32) { 
    let func_name = CString::new(func_name).unwrap(); 

    let mut string = String::from_str(data).unwrap(); 
    let bytes = string.into_bytes(); 
    let mut cchar : Vec<c_char> = bytes.iter().map(|&w| w as c_char).collect(); 
    let data_slice = cchar.as_mut_slice(); 

    let mut state = 42; 
    let state_ptr: *mut c_void = &mut state as *mut _ as *mut c_void; 

    unsafe { 
     ffi::emscripten_call_worker(
      worker, 
      func_name.as_ptr(), 
      data_slice.as_mut_ptr(), 
      size as c_int, 
      Some(do_something_handler), 
      state_ptr 
     ) 
    }; 
} 

// This is mostly standard Rust-C FFI stuff. 
mod ffi { 
    use libc::*; 
    pub type worker_handle = c_int; 
    pub type em_worker_callback_func = Option<unsafe extern "C" fn(arg1: *mut c_char, 
                    arg2: c_int, 
                    arg3: *mut c_void)>; 

    extern "C" { 
     pub fn emscripten_run_script_int(x: *const c_char) -> c_int; 
     pub fn emscripten_create_worker(url: *const c_char) -> worker_handle; 
     pub fn emscripten_call_worker(
      worker: worker_handle, 
      funcname: *const c_char, 
      data: *mut c_char, 
      size: c_int, 
      callback: em_worker_callback_func, 
      arg: *mut c_void 
     ); 
     pub fn emscripten_worker_respond(data: *mut c_char, size: c_int); 
     pub fn emscripten_worker_respond_provisionally(data: *mut c_char, size: c_int); 
    } 
} 

Tôi không hiểu vấn đề là gì. Tôi có nên thay đổi tập tin công nhân hay thậm chí là link_args?

Trả lời

4

Tôi cố định vấn đề bằng cách sử dụng stdweb thùng như thế này (Cảm ơn ivanceras):

worker.rs

#![feature(link_args)] 
#[link_args = "-s BUILD_AS_WORKER=1"] 

#[macro_use] 
extern crate stdweb; 

fn main(){ 
    stdweb::initialize(); 

    js! { 
     this.addEventListener("message", (e) => { 
      console.log("The main thread said something", e.data); 
     }) 
    } 
    stdweb::event_loop(); 
} 

loader.js

var wasm_file = "worker.wasm"; // wasm file 
var wjs_file = "worker.js"; // w.js file that links the wasm file 

Module = {} 
console.log("Loading webassembly version"); 
/// fetch wasm file and inject the js file 
fetch(wasm_file) 
    .then(response => response.arrayBuffer()) 
    .then(bytes => { 
    Module.wasmBinary = bytes; 
    console.log("wasm has loaded.."); 
    console.log("attaching as script"); 
    self.importScripts(wjs_file); 
    }); 

và cuối cùng, Tệp HTML:

<script> 
    var worker = new Worker("loader.js"); 
    setTimeout(function() { 
     worker.postMessage({"cmd":"doSomething"}); 
    }, 1000); 
</script> 

Đừng quên thêm cờ --target=wasm32-unknown-emscripten khi bạn tạo tệp Rust.

+0

Giúp tôi hiểu tại sao 'worker.js' là cần thiết. Nếu 'loader.js' được chạy trong' Worker', tại sao nó không tải trực tiếp tập tin wasm? Thay vào đó, nó sử dụng 'importScripts' để chuyển thành' worker.js' được cho là để nạp tập tin wasm. Tại sao thêm lớp indirection này? –

Các vấn đề liên quan