aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/dedicatedworkerglobalscope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/dedicatedworkerglobalscope.rs')
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs200
1 files changed, 200 insertions, 0 deletions
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
new file mode 100644
index 00000000000..15bf075df44
--- /dev/null
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -0,0 +1,200 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
+use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::InheritTypes::DedicatedWorkerGlobalScopeDerived;
+use dom::bindings::codegen::InheritTypes::{EventTargetCast, WorkerGlobalScopeCast};
+use dom::bindings::global::Worker;
+use dom::bindings::js::{JSRef, Temporary, RootCollection};
+use dom::bindings::trace::Untraceable;
+use dom::bindings::utils::{Reflectable, Reflector};
+use dom::eventtarget::{EventTarget, EventTargetHelpers};
+use dom::eventtarget::WorkerGlobalScopeTypeId;
+use dom::messageevent::MessageEvent;
+use dom::worker::{Worker, TrustedWorkerAddress};
+use dom::workerglobalscope::DedicatedGlobalScope;
+use dom::workerglobalscope::WorkerGlobalScope;
+use dom::xmlhttprequest::XMLHttpRequest;
+use script_task::{ScriptTask, ScriptChan};
+use script_task::{ScriptMsg, DOMMessage, XHRProgressMsg, WorkerRelease};
+use script_task::WorkerPostMessage;
+use script_task::StackRootTLS;
+
+use servo_net::resource_task::{ResourceTask, load_whole_resource};
+
+use js::glue::JS_STRUCTURED_CLONE_VERSION;
+use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_WriteStructuredClone};
+use js::jsval::{JSVal, UndefinedValue};
+use js::rust::Cx;
+
+use std::rc::Rc;
+use std::ptr;
+use std::task::TaskBuilder;
+use native::task::NativeTaskBuilder;
+use url::Url;
+
+#[deriving(Encodable)]
+pub struct DedicatedWorkerGlobalScope {
+ workerglobalscope: WorkerGlobalScope,
+ receiver: Untraceable<Receiver<ScriptMsg>>,
+ /// Sender to the parent thread.
+ parent_sender: ScriptChan,
+ worker: Untraceable<TrustedWorkerAddress>,
+}
+
+impl DedicatedWorkerGlobalScope {
+ pub fn new_inherited(worker_url: Url,
+ worker: TrustedWorkerAddress,
+ cx: Rc<Cx>,
+ resource_task: ResourceTask,
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>)
+ -> DedicatedWorkerGlobalScope {
+ DedicatedWorkerGlobalScope {
+ workerglobalscope: WorkerGlobalScope::new_inherited(
+ DedicatedGlobalScope, worker_url, cx, resource_task,
+ own_sender),
+ receiver: Untraceable::new(receiver),
+ parent_sender: parent_sender,
+ worker: Untraceable::new(worker),
+ }
+ }
+
+ pub fn new(worker_url: Url,
+ worker: TrustedWorkerAddress,
+ cx: Rc<Cx>,
+ resource_task: ResourceTask,
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>)
+ -> Temporary<DedicatedWorkerGlobalScope> {
+ let scope = box DedicatedWorkerGlobalScope::new_inherited(
+ worker_url, worker, cx.clone(), resource_task, parent_sender,
+ own_sender, receiver);
+ DedicatedWorkerGlobalScopeBinding::Wrap(cx.ptr, scope)
+ }
+}
+
+impl DedicatedWorkerGlobalScope {
+ pub fn run_worker_scope(worker_url: Url,
+ worker: TrustedWorkerAddress,
+ resource_task: ResourceTask,
+ parent_sender: ScriptChan,
+ own_sender: ScriptChan,
+ receiver: Receiver<ScriptMsg>) {
+ TaskBuilder::new()
+ .native()
+ .named(format!("Web Worker at {}", worker_url.serialize()))
+ .spawn(proc() {
+ let roots = RootCollection::new();
+ let _stack_roots_tls = StackRootTLS::new(&roots);
+
+ let (url, source) = match load_whole_resource(&resource_task, worker_url.clone()) {
+ Err(_) => {
+ println!("error loading script {}", worker_url.serialize());
+ return;
+ }
+ Ok((metadata, bytes)) => {
+ (metadata.final_url, String::from_utf8(bytes).unwrap())
+ }
+ };
+
+ let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx();
+ let global = DedicatedWorkerGlobalScope::new(
+ worker_url, worker, js_context.clone(), resource_task,
+ parent_sender, own_sender, receiver).root();
+ match js_context.evaluate_script(
+ global.reflector().get_jsobject(), source, url.serialize(), 1) {
+ Ok(_) => (),
+ Err(_) => println!("evaluate_script failed")
+ }
+ global.delayed_release_worker();
+
+ let scope: &JSRef<WorkerGlobalScope> =
+ WorkerGlobalScopeCast::from_ref(&*global);
+ let target: &JSRef<EventTarget> =
+ EventTargetCast::from_ref(&*global);
+ loop {
+ match global.receiver.recv_opt() {
+ Ok(DOMMessage(data, nbytes)) => {
+ let mut message = UndefinedValue();
+ unsafe {
+ assert!(JS_ReadStructuredClone(
+ js_context.ptr, data as *const u64, nbytes,
+ JS_STRUCTURED_CLONE_VERSION, &mut message,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ MessageEvent::dispatch_jsval(target, &Worker(*scope), message);
+ global.delayed_release_worker();
+ },
+ Ok(XHRProgressMsg(addr, progress)) => {
+ XMLHttpRequest::handle_xhr_progress(addr, progress)
+ },
+ Ok(WorkerPostMessage(addr, data, nbytes)) => {
+ Worker::handle_message(addr, data, nbytes);
+ },
+ Ok(WorkerRelease(addr)) => {
+ Worker::handle_release(addr)
+ },
+ Ok(_) => fail!("Unexpected message"),
+ Err(_) => break,
+ }
+ }
+ });
+ }
+}
+
+impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalScope> {
+ fn PostMessage(&self, cx: *mut JSContext, message: JSVal) {
+ let mut data = ptr::mut_null();
+ let mut nbytes = 0;
+ unsafe {
+ assert!(JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes,
+ ptr::null(), ptr::mut_null()) != 0);
+ }
+
+ let ScriptChan(ref sender) = self.parent_sender;
+ sender.send(WorkerPostMessage(*self.worker, data, nbytes));
+ }
+
+ fn GetOnmessage(&self) -> Option<EventHandlerNonNull> {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.get_event_handler_common("message")
+ }
+
+ fn SetOnmessage(&self, listener: Option<EventHandlerNonNull>) {
+ let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ eventtarget.set_event_handler_common("message", listener)
+ }
+}
+
+trait PrivateDedicatedWorkerGlobalScopeHelpers {
+ fn delayed_release_worker(&self);
+}
+
+impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> {
+ fn delayed_release_worker(&self) {
+ let ScriptChan(ref sender) = self.parent_sender;
+ sender.send(WorkerRelease(*self.worker));
+ }
+}
+
+impl Reflectable for DedicatedWorkerGlobalScope {
+ fn reflector<'a>(&'a self) -> &'a Reflector {
+ self.workerglobalscope.reflector()
+ }
+}
+
+impl DedicatedWorkerGlobalScopeDerived for EventTarget {
+ fn is_dedicatedworkerglobalscope(&self) -> bool {
+ match self.type_id {
+ WorkerGlobalScopeTypeId(DedicatedGlobalScope) => true,
+ _ => false
+ }
+ }
+}