mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Make service workers talk to their serviceworkerglobalscopes
This commit is contained in:
parent
72279cc7eb
commit
0996b38ade
13 changed files with 184 additions and 46 deletions
|
@ -738,6 +738,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
// store service worker manager for communicating with it.
|
// store service worker manager for communicating with it.
|
||||||
self.swmanager_chan = Some(sw_sender);
|
self.swmanager_chan = Some(sw_sender);
|
||||||
}
|
}
|
||||||
|
SWManagerMsg::ConnectServiceWorker(scope_url, pipeline_id, msg_chan) => {
|
||||||
|
if let Some(ref parent_info) = self.pipelines.get(&pipeline_id) {
|
||||||
|
let from_cons_msg = ConstellationControlMsg::ConnectServiceWorker(scope_url, msg_chan);
|
||||||
|
let _ = parent_info.script_chan.send(from_cons_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_STRUCTURED_CLONE_VERSION};
|
||||||
use js::jsapi::{JS_ClearPendingException, JS_WriteStructuredClone};
|
use js::jsapi::{JS_ClearPendingException, JS_WriteStructuredClone};
|
||||||
use libc::size_t;
|
use libc::size_t;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
/// A buffer for a structured clone.
|
/// A buffer for a structured clone.
|
||||||
pub struct StructuredCloneData {
|
pub struct StructuredCloneData {
|
||||||
|
@ -45,6 +46,21 @@ impl StructuredCloneData {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a StructuredCloneData to Vec<u64>
|
||||||
|
pub fn move_to_arraybuffer(self) -> Vec<u64> {
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts(self.data, self.nbytes).to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts back to StructuredCloneData using a pointer and no of bytes
|
||||||
|
pub fn make_structured_clone(data: *mut u64, nbytes: size_t) -> StructuredCloneData {
|
||||||
|
StructuredCloneData {
|
||||||
|
data: data,
|
||||||
|
nbytes: nbytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a structured clone.
|
/// Reads a structured clone.
|
||||||
///
|
///
|
||||||
/// Panics if `JS_ReadStructuredClone` fails.
|
/// Panics if `JS_ReadStructuredClone` fails.
|
||||||
|
|
|
@ -2,20 +2,24 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
|
use dom::abstractworker::SimpleWorkerErrorHandler;
|
||||||
use dom::bindings::cell::DOMRefCell;
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
|
use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
|
||||||
|
use dom::bindings::error::ErrorResult;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::inheritance::Castable;
|
use dom::bindings::inheritance::Castable;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::refcounted::Trusted;
|
use dom::bindings::refcounted::Trusted;
|
||||||
use dom::bindings::reflector::reflect_dom_object;
|
use dom::bindings::reflector::reflect_dom_object;
|
||||||
use dom::bindings::str::USVString;
|
use dom::bindings::str::USVString;
|
||||||
|
use dom::bindings::structuredclone::StructuredCloneData;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
use js::jsapi::{HandleValue, JSContext};
|
||||||
use script_thread::Runnable;
|
use script_thread::Runnable;
|
||||||
|
use script_traits::DOMMessage;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::sync::mpsc::Sender;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
|
pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
|
||||||
|
@ -26,7 +30,7 @@ pub struct ServiceWorker {
|
||||||
script_url: DOMRefCell<String>,
|
script_url: DOMRefCell<String>,
|
||||||
state: Cell<ServiceWorkerState>,
|
state: Cell<ServiceWorkerState>,
|
||||||
#[ignore_heap_size_of = "Defined in std"]
|
#[ignore_heap_size_of = "Defined in std"]
|
||||||
sender: Option<Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>>,
|
msg_sender: DOMRefCell<Option<IpcSender<DOMMessage>>>,
|
||||||
skip_waiting: Cell<bool>
|
skip_waiting: Cell<bool>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +39,10 @@ impl ServiceWorker {
|
||||||
skip_waiting: bool) -> ServiceWorker {
|
skip_waiting: bool) -> ServiceWorker {
|
||||||
ServiceWorker {
|
ServiceWorker {
|
||||||
eventtarget: EventTarget::new_inherited(),
|
eventtarget: EventTarget::new_inherited(),
|
||||||
sender: None,
|
|
||||||
script_url: DOMRefCell::new(String::from(script_url)),
|
script_url: DOMRefCell::new(String::from(script_url)),
|
||||||
state: Cell::new(ServiceWorkerState::Installing),
|
state: Cell::new(ServiceWorkerState::Installing),
|
||||||
skip_waiting: Cell::new(skip_waiting)
|
skip_waiting: Cell::new(skip_waiting),
|
||||||
|
msg_sender: DOMRefCell::new(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +73,13 @@ impl ServiceWorker {
|
||||||
script_url.as_str(),
|
script_url.as_str(),
|
||||||
skip_waiting)
|
skip_waiting)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn store_sender(trusted_worker: TrustedServiceWorkerAddress, sender: IpcSender<DOMMessage>) {
|
||||||
|
let worker = trusted_worker.root();
|
||||||
|
// This channel is used for sending message from the ServiceWorker object to its
|
||||||
|
// corresponding ServiceWorkerGlobalScope
|
||||||
|
*worker.msg_sender.borrow_mut() = Some(sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceWorkerMethods for ServiceWorker {
|
impl ServiceWorkerMethods for ServiceWorker {
|
||||||
|
@ -82,6 +93,18 @@ impl ServiceWorkerMethods for ServiceWorker {
|
||||||
USVString(self.script_url.borrow().clone())
|
USVString(self.script_url.borrow().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-postmessage
|
||||||
|
fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult {
|
||||||
|
let data = try!(StructuredCloneData::write(cx, message));
|
||||||
|
let msg_vec = DOMMessage(data.move_to_arraybuffer());
|
||||||
|
if let Some(ref sender) = *self.msg_sender.borrow() {
|
||||||
|
let _ = sender.send(msg_vec);
|
||||||
|
} else {
|
||||||
|
warn!("Could not communicate message to ServiceWorkerGlobalScope");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-onerror-attribute
|
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-onerror-attribute
|
||||||
event_handler!(error, GetOnerror, SetOnerror);
|
event_handler!(error, GetOnerror, SetOnerror);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
use devtools;
|
use devtools;
|
||||||
use devtools_traits::DevtoolScriptControlMsg;
|
use devtools_traits::DevtoolScriptControlMsg;
|
||||||
use dom::abstractworker::WorkerScriptMsg;
|
use dom::abstractworker::WorkerScriptMsg;
|
||||||
use dom::bindings::cell::DOMRefCell;
|
|
||||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
|
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
|
||||||
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
|
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
|
||||||
|
@ -14,9 +13,9 @@ use dom::bindings::inheritance::Castable;
|
||||||
use dom::bindings::js::{Root, RootCollection};
|
use dom::bindings::js::{Root, RootCollection};
|
||||||
use dom::bindings::reflector::Reflectable;
|
use dom::bindings::reflector::Reflectable;
|
||||||
use dom::bindings::str::DOMString;
|
use dom::bindings::str::DOMString;
|
||||||
|
use dom::bindings::structuredclone::StructuredCloneData;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::messageevent::MessageEvent;
|
use dom::messageevent::MessageEvent;
|
||||||
use dom::serviceworker::TrustedServiceWorkerAddress;
|
|
||||||
use dom::workerglobalscope::WorkerGlobalScope;
|
use dom::workerglobalscope::WorkerGlobalScope;
|
||||||
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
|
@ -26,8 +25,8 @@ use js::rust::Runtime;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator};
|
use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx};
|
use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan};
|
||||||
use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg};
|
use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg, DOMMessage};
|
||||||
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
|
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -49,6 +48,27 @@ pub enum MixedMessage {
|
||||||
FromServiceWorker(ServiceWorkerScriptMsg),
|
FromServiceWorker(ServiceWorkerScriptMsg),
|
||||||
FromDevtools(DevtoolScriptControlMsg),
|
FromDevtools(DevtoolScriptControlMsg),
|
||||||
FromTimeoutThread(()),
|
FromTimeoutThread(()),
|
||||||
|
PostMessage(DOMMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required for run_with_memory_reporting
|
||||||
|
#[derive(JSTraceable, Clone)]
|
||||||
|
pub struct ServiceWorkerChan {
|
||||||
|
pub sender: Sender<ServiceWorkerScriptMsg>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptChan for ServiceWorkerChan {
|
||||||
|
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
|
||||||
|
self.sender
|
||||||
|
.send(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)))
|
||||||
|
.map_err(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone(&self) -> Box<ScriptChan + Send> {
|
||||||
|
box ServiceWorkerChan {
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -61,12 +81,12 @@ pub struct ServiceWorkerGlobalScope {
|
||||||
own_sender: Sender<ServiceWorkerScriptMsg>,
|
own_sender: Sender<ServiceWorkerScriptMsg>,
|
||||||
#[ignore_heap_size_of = "Defined in std"]
|
#[ignore_heap_size_of = "Defined in std"]
|
||||||
timer_event_port: Receiver<()>,
|
timer_event_port: Receiver<()>,
|
||||||
#[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"]
|
|
||||||
worker: DOMRefCell<Option<TrustedServiceWorkerAddress>>,
|
|
||||||
#[ignore_heap_size_of = "Defined in std"]
|
#[ignore_heap_size_of = "Defined in std"]
|
||||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
#[ignore_heap_size_of = "Defined in std"]
|
#[ignore_heap_size_of = "Defined in std"]
|
||||||
scope_url: Url
|
msg_port: Receiver<DOMMessage>,
|
||||||
|
#[ignore_heap_size_of = "Defined in std"]
|
||||||
|
scope_url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceWorkerGlobalScope {
|
impl ServiceWorkerGlobalScope {
|
||||||
|
@ -80,7 +100,8 @@ impl ServiceWorkerGlobalScope {
|
||||||
timer_event_chan: IpcSender<TimerEvent>,
|
timer_event_chan: IpcSender<TimerEvent>,
|
||||||
timer_event_port: Receiver<()>,
|
timer_event_port: Receiver<()>,
|
||||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
scope_url: Url)
|
scope_url: Url,
|
||||||
|
msg_port: Receiver<DOMMessage>)
|
||||||
-> ServiceWorkerGlobalScope {
|
-> ServiceWorkerGlobalScope {
|
||||||
ServiceWorkerGlobalScope {
|
ServiceWorkerGlobalScope {
|
||||||
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
||||||
|
@ -93,9 +114,9 @@ impl ServiceWorkerGlobalScope {
|
||||||
receiver: receiver,
|
receiver: receiver,
|
||||||
timer_event_port: timer_event_port,
|
timer_event_port: timer_event_port,
|
||||||
own_sender: own_sender,
|
own_sender: own_sender,
|
||||||
worker: DOMRefCell::new(None),
|
|
||||||
swmanager_sender: swmanager_sender,
|
swmanager_sender: swmanager_sender,
|
||||||
scope_url: scope_url
|
scope_url: scope_url,
|
||||||
|
msg_port: msg_port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +130,8 @@ impl ServiceWorkerGlobalScope {
|
||||||
timer_event_chan: IpcSender<TimerEvent>,
|
timer_event_chan: IpcSender<TimerEvent>,
|
||||||
timer_event_port: Receiver<()>,
|
timer_event_port: Receiver<()>,
|
||||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
scope_url: Url)
|
scope_url: Url,
|
||||||
|
msg_port: Receiver<DOMMessage>)
|
||||||
-> Root<ServiceWorkerGlobalScope> {
|
-> Root<ServiceWorkerGlobalScope> {
|
||||||
let cx = runtime.cx();
|
let cx = runtime.cx();
|
||||||
let scope = box ServiceWorkerGlobalScope::new_inherited(init,
|
let scope = box ServiceWorkerGlobalScope::new_inherited(init,
|
||||||
|
@ -122,7 +144,8 @@ impl ServiceWorkerGlobalScope {
|
||||||
timer_event_chan,
|
timer_event_chan,
|
||||||
timer_event_port,
|
timer_event_port,
|
||||||
swmanager_sender,
|
swmanager_sender,
|
||||||
scope_url);
|
scope_url,
|
||||||
|
msg_port);
|
||||||
ServiceWorkerGlobalScopeBinding::Wrap(cx, scope)
|
ServiceWorkerGlobalScopeBinding::Wrap(cx, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +155,8 @@ impl ServiceWorkerGlobalScope {
|
||||||
receiver: Receiver<ServiceWorkerScriptMsg>,
|
receiver: Receiver<ServiceWorkerScriptMsg>,
|
||||||
devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
||||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
scope_url: Url) {
|
scope_url: Url,
|
||||||
|
msg_port: Receiver<DOMMessage>) {
|
||||||
let ScopeThings { script_url,
|
let ScopeThings { script_url,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
init,
|
init,
|
||||||
|
@ -167,7 +191,7 @@ impl ServiceWorkerGlobalScope {
|
||||||
let global = ServiceWorkerGlobalScope::new(
|
let global = ServiceWorkerGlobalScope::new(
|
||||||
init, url, pipeline_id, devtools_mpsc_port, runtime,
|
init, url, pipeline_id, devtools_mpsc_port, runtime,
|
||||||
own_sender, receiver,
|
own_sender, receiver,
|
||||||
timer_ipc_chan, timer_port, swmanager_sender, scope_url);
|
timer_ipc_chan, timer_port, swmanager_sender, scope_url, msg_port);
|
||||||
let scope = global.upcast::<WorkerGlobalScope>();
|
let scope = global.upcast::<WorkerGlobalScope>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -214,6 +238,17 @@ impl ServiceWorkerGlobalScope {
|
||||||
self.handle_script_event(msg);
|
self.handle_script_event(msg);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
MixedMessage::PostMessage(data) => {
|
||||||
|
let DOMMessage(mut data) = data;
|
||||||
|
let data = StructuredCloneData::make_structured_clone(data.as_mut_ptr(), data.len());
|
||||||
|
let scope = self.upcast::<WorkerGlobalScope>();
|
||||||
|
let target = self.upcast();
|
||||||
|
let _ac = JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
|
||||||
|
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
|
||||||
|
data.read(GlobalRef::Worker(scope), message.handle_mut());
|
||||||
|
MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle());
|
||||||
|
true
|
||||||
|
}
|
||||||
MixedMessage::FromTimeoutThread(_) => {
|
MixedMessage::FromTimeoutThread(_) => {
|
||||||
let _ = self.swmanager_sender.send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
|
let _ = self.swmanager_sender.send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
|
||||||
false
|
false
|
||||||
|
@ -225,15 +260,7 @@ impl ServiceWorkerGlobalScope {
|
||||||
use self::ServiceWorkerScriptMsg::*;
|
use self::ServiceWorkerScriptMsg::*;
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
CommonWorker(WorkerScriptMsg::DOMMessage(data)) => {
|
CommonWorker(WorkerScriptMsg::DOMMessage(_)) => { },
|
||||||
let scope = self.upcast::<WorkerGlobalScope>();
|
|
||||||
let target = self.upcast();
|
|
||||||
let _ac = JSAutoCompartment::new(scope.get_cx(),
|
|
||||||
scope.reflector().get_jsobject().get());
|
|
||||||
rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
|
|
||||||
data.read(GlobalRef::Worker(scope), message.handle_mut());
|
|
||||||
MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle());
|
|
||||||
},
|
|
||||||
CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => {
|
CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => {
|
||||||
runnable.handler()
|
runnable.handler()
|
||||||
},
|
},
|
||||||
|
@ -260,17 +287,20 @@ impl ServiceWorkerGlobalScope {
|
||||||
let worker_port = &self.receiver;
|
let worker_port = &self.receiver;
|
||||||
let devtools_port = scope.from_devtools_receiver();
|
let devtools_port = scope.from_devtools_receiver();
|
||||||
let timer_event_port = &self.timer_event_port;
|
let timer_event_port = &self.timer_event_port;
|
||||||
|
let msg_port = &self.msg_port;
|
||||||
|
|
||||||
let sel = Select::new();
|
let sel = Select::new();
|
||||||
let mut worker_handle = sel.handle(worker_port);
|
let mut worker_handle = sel.handle(worker_port);
|
||||||
let mut devtools_handle = sel.handle(devtools_port);
|
let mut devtools_handle = sel.handle(devtools_port);
|
||||||
let mut timer_port_handle = sel.handle(timer_event_port);
|
let mut timer_port_handle = sel.handle(timer_event_port);
|
||||||
|
let mut msg_port_handle = sel.handle(msg_port);
|
||||||
unsafe {
|
unsafe {
|
||||||
worker_handle.add();
|
worker_handle.add();
|
||||||
if scope.from_devtools_sender().is_some() {
|
if scope.from_devtools_sender().is_some() {
|
||||||
devtools_handle.add();
|
devtools_handle.add();
|
||||||
}
|
}
|
||||||
timer_port_handle.add();
|
timer_port_handle.add();
|
||||||
|
msg_port_handle.add();
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = sel.wait();
|
let ret = sel.wait();
|
||||||
|
@ -280,6 +310,8 @@ impl ServiceWorkerGlobalScope {
|
||||||
Ok(MixedMessage::FromDevtools(try!(devtools_port.recv())))
|
Ok(MixedMessage::FromDevtools(try!(devtools_port.recv())))
|
||||||
} else if ret == timer_port_handle.id() {
|
} else if ret == timer_port_handle.id() {
|
||||||
Ok(MixedMessage::FromTimeoutThread(try!(timer_event_port.recv())))
|
Ok(MixedMessage::FromTimeoutThread(try!(timer_event_port.recv())))
|
||||||
|
} else if ret == msg_port_handle.id() {
|
||||||
|
Ok(MixedMessage::PostMessage(try!(msg_port.recv())))
|
||||||
} else {
|
} else {
|
||||||
panic!("unexpected select result!")
|
panic!("unexpected select result!")
|
||||||
}
|
}
|
||||||
|
@ -292,6 +324,12 @@ impl ServiceWorkerGlobalScope {
|
||||||
pub fn process_event(&self, msg: CommonScriptMsg) {
|
pub fn process_event(&self, msg: CommonScriptMsg) {
|
||||||
self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)));
|
self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
|
||||||
|
box ServiceWorkerChan {
|
||||||
|
sender: self.own_sender.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
|
@ -6,10 +6,11 @@ use dom::bindings::codegen::Bindings::ServiceWorkerBinding::ServiceWorkerState;
|
||||||
use dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::{ServiceWorkerRegistrationMethods, Wrap};
|
use dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::{ServiceWorkerRegistrationMethods, Wrap};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, Root};
|
use dom::bindings::js::{JS, Root};
|
||||||
|
use dom::bindings::refcounted::Trusted;
|
||||||
use dom::bindings::reflector::reflect_dom_object;
|
use dom::bindings::reflector::reflect_dom_object;
|
||||||
use dom::bindings::str::USVString;
|
use dom::bindings::str::USVString;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::serviceworker::ServiceWorker;
|
use dom::serviceworker::{ServiceWorker, TrustedServiceWorkerAddress};
|
||||||
use dom::serviceworkercontainer::Controllable;
|
use dom::serviceworkercontainer::Controllable;
|
||||||
use dom::workerglobalscope::prepare_workerscope_init;
|
use dom::workerglobalscope::prepare_workerscope_init;
|
||||||
use script_traits::{WorkerScriptLoadOrigin, ScopeThings};
|
use script_traits::{WorkerScriptLoadOrigin, ScopeThings};
|
||||||
|
@ -49,6 +50,10 @@ impl ServiceWorkerRegistration {
|
||||||
self.active.as_ref().unwrap()
|
self.active.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_trusted_worker(&self) -> TrustedServiceWorkerAddress {
|
||||||
|
Trusted::new(self.active.as_ref().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_scope_things(global: GlobalRef, script_url: Url) -> ScopeThings {
|
pub fn create_scope_things(global: GlobalRef, script_url: Url) -> ScopeThings {
|
||||||
let worker_load_origin = WorkerScriptLoadOrigin {
|
let worker_load_origin = WorkerScriptLoadOrigin {
|
||||||
referrer_url: None,
|
referrer_url: None,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
interface ServiceWorker : EventTarget {
|
interface ServiceWorker : EventTarget {
|
||||||
readonly attribute USVString scriptURL;
|
readonly attribute USVString scriptURL;
|
||||||
readonly attribute ServiceWorkerState state;
|
readonly attribute ServiceWorkerState state;
|
||||||
//[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
|
[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
|
||||||
|
|
||||||
// event
|
// event
|
||||||
attribute EventHandler onstatechange;
|
attribute EventHandler onstatechange;
|
||||||
|
|
|
@ -392,10 +392,12 @@ impl WorkerGlobalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
|
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
|
||||||
let dedicated =
|
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
|
||||||
self.downcast::<DedicatedWorkerGlobalScope>();
|
let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
|
||||||
if let Some(dedicated) = dedicated {
|
if let Some(dedicated) = dedicated {
|
||||||
return dedicated.script_chan();
|
return dedicated.script_chan();
|
||||||
|
} else if let Some(service_worker) = service_worker {
|
||||||
|
return service_worker.script_chan();
|
||||||
} else {
|
} else {
|
||||||
panic!("need to implement a sender for SharedWorker/ServiceWorker")
|
panic!("need to implement a sender for SharedWorker/ServiceWorker")
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ use dom::element::Element;
|
||||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||||
use dom::htmlanchorelement::HTMLAnchorElement;
|
use dom::htmlanchorelement::HTMLAnchorElement;
|
||||||
use dom::node::{Node, NodeDamage, window_from_node};
|
use dom::node::{Node, NodeDamage, window_from_node};
|
||||||
use dom::serviceworker::TrustedServiceWorkerAddress;
|
use dom::serviceworker::{TrustedServiceWorkerAddress, ServiceWorker};
|
||||||
use dom::serviceworkerregistration::ServiceWorkerRegistration;
|
use dom::serviceworkerregistration::ServiceWorkerRegistration;
|
||||||
use dom::servohtmlparser::ParserContext;
|
use dom::servohtmlparser::ParserContext;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
|
@ -84,7 +84,7 @@ use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
|
||||||
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
||||||
use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
|
use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
|
||||||
use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent};
|
use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent};
|
||||||
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg, DOMMessage};
|
||||||
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
||||||
use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData};
|
use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
@ -924,6 +924,8 @@ impl ScriptThread {
|
||||||
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
|
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
|
||||||
ConstellationControlMsg::Reload(pipeline_id) =>
|
ConstellationControlMsg::Reload(pipeline_id) =>
|
||||||
self.handle_reload(pipeline_id),
|
self.handle_reload(pipeline_id),
|
||||||
|
ConstellationControlMsg::ConnectServiceWorker(scope_url, chan) =>
|
||||||
|
self.connect_serviceworker_to_scope(scope_url, chan),
|
||||||
msg @ ConstellationControlMsg::AttachLayout(..) |
|
msg @ ConstellationControlMsg::AttachLayout(..) |
|
||||||
msg @ ConstellationControlMsg::Viewport(..) |
|
msg @ ConstellationControlMsg::Viewport(..) |
|
||||||
msg @ ConstellationControlMsg::SetScrollState(..) |
|
msg @ ConstellationControlMsg::SetScrollState(..) |
|
||||||
|
@ -1456,7 +1458,16 @@ impl ScriptThread {
|
||||||
let scope_things = ServiceWorkerRegistration::create_scope_things(global_ref, script_url);
|
let scope_things = ServiceWorkerRegistration::create_scope_things(global_ref, script_url);
|
||||||
let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope));
|
let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope));
|
||||||
} else {
|
} else {
|
||||||
warn!("Registration failed for {}", pipeline_id);
|
warn!("Registration failed for {}", scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the sender to the corresponding scope of the service worker object.
|
||||||
|
fn connect_serviceworker_to_scope(&self, scope_url: Url, chan: IpcSender<DOMMessage>) {
|
||||||
|
let ref maybe_registration_ref = *self.registration_map.borrow();
|
||||||
|
if let Some(ref registration) = maybe_registration_ref.get(&scope_url) {
|
||||||
|
let trusted_worker = registration.get_trusted_worker();
|
||||||
|
ServiceWorker::store_sender(trusted_worker, chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,19 +35,23 @@ pub struct ServiceWorkerManager {
|
||||||
// receiver to receive messages from constellation
|
// receiver to receive messages from constellation
|
||||||
own_port: Receiver<ServiceWorkerMsg>,
|
own_port: Receiver<ServiceWorkerMsg>,
|
||||||
// to receive resource messages
|
// to receive resource messages
|
||||||
resource_receiver: Receiver<CustomResponseMediator>
|
resource_receiver: Receiver<CustomResponseMediator>,
|
||||||
|
// to send message to constellation
|
||||||
|
constellation_sender: IpcSender<SWManagerMsg>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceWorkerManager {
|
impl ServiceWorkerManager {
|
||||||
fn new(own_sender: IpcSender<ServiceWorkerMsg>,
|
fn new(own_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
from_constellation_receiver: Receiver<ServiceWorkerMsg>,
|
from_constellation_receiver: Receiver<ServiceWorkerMsg>,
|
||||||
resource_port: Receiver<CustomResponseMediator>) -> ServiceWorkerManager {
|
resource_port: Receiver<CustomResponseMediator>,
|
||||||
|
constellation_sender: IpcSender<SWManagerMsg>) -> ServiceWorkerManager {
|
||||||
ServiceWorkerManager {
|
ServiceWorkerManager {
|
||||||
registered_workers: HashMap::new(),
|
registered_workers: HashMap::new(),
|
||||||
active_workers: HashMap::new(),
|
active_workers: HashMap::new(),
|
||||||
own_sender: own_sender,
|
own_sender: own_sender,
|
||||||
own_port: from_constellation_receiver,
|
own_port: from_constellation_receiver,
|
||||||
resource_receiver: resource_port
|
resource_receiver: resource_port,
|
||||||
|
constellation_sender: constellation_sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +62,12 @@ impl ServiceWorkerManager {
|
||||||
let resource_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(resource_port);
|
let resource_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(resource_port);
|
||||||
let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan));
|
let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan));
|
||||||
let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
|
let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
|
||||||
|
let constellation_sender = sw_senders.swmanager_sender.clone();
|
||||||
spawn_named("ServiceWorkerManager".to_owned(), move || {
|
spawn_named("ServiceWorkerManager".to_owned(), move || {
|
||||||
ServiceWorkerManager::new(own_sender, from_constellation, resource_port).handle_message();
|
ServiceWorkerManager::new(own_sender,
|
||||||
|
from_constellation,
|
||||||
|
resource_port,
|
||||||
|
constellation_sender).handle_message();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,12 +101,20 @@ impl ServiceWorkerManager {
|
||||||
devtools_sender.clone(),
|
devtools_sender.clone(),
|
||||||
page_info));
|
page_info));
|
||||||
};
|
};
|
||||||
|
let (msg_chan, msg_port) = ipc::channel().unwrap();
|
||||||
|
let msg_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(msg_port);
|
||||||
ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
|
ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
|
||||||
sender.clone(),
|
sender.clone(),
|
||||||
receiver,
|
receiver,
|
||||||
devtools_receiver,
|
devtools_receiver,
|
||||||
self.own_sender.clone(),
|
self.own_sender.clone(),
|
||||||
scope_url.clone());
|
scope_url.clone(),
|
||||||
|
msg_port);
|
||||||
|
// Send the message to constellation which then talks to the script thread for storing this msg_chan
|
||||||
|
let connection_msg = SWManagerMsg::ConnectServiceWorker(scope_url.clone(),
|
||||||
|
scope_things.pipeline_id,
|
||||||
|
msg_chan);
|
||||||
|
let _ = self.constellation_sender.send(connection_msg);
|
||||||
// We store the activated worker
|
// We store the activated worker
|
||||||
self.active_workers.insert(scope_url, scope_things.clone());
|
self.active_workers.insert(scope_url, scope_things.clone());
|
||||||
return Some(sender);
|
return Some(sender);
|
||||||
|
|
|
@ -71,7 +71,7 @@ use util::ipc::OptionalOpaqueIpcSender;
|
||||||
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
|
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
|
||||||
|
|
||||||
pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
|
pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
|
||||||
pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders};
|
pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
|
||||||
|
|
||||||
/// The address of a node. Layout sends these back. They must be validated via
|
/// The address of a node. Layout sends these back. They must be validated via
|
||||||
/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
|
/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
|
||||||
|
@ -208,6 +208,8 @@ pub enum ConstellationControlMsg {
|
||||||
ReportCSSError(PipelineId, String, usize, usize, String),
|
ReportCSSError(PipelineId, String, usize, usize, String),
|
||||||
/// Reload the given page.
|
/// Reload the given page.
|
||||||
Reload(PipelineId),
|
Reload(PipelineId),
|
||||||
|
/// Requests the script thread to connect service worker object to its scope
|
||||||
|
ConnectServiceWorker(Url, IpcSender<DOMMessage>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ConstellationControlMsg {
|
impl fmt::Debug for ConstellationControlMsg {
|
||||||
|
@ -237,6 +239,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
||||||
FramedContentChanged(..) => "FramedContentChanged",
|
FramedContentChanged(..) => "FramedContentChanged",
|
||||||
ReportCSSError(..) => "ReportCSSError",
|
ReportCSSError(..) => "ReportCSSError",
|
||||||
Reload(..) => "Reload",
|
Reload(..) => "Reload",
|
||||||
|
ConnectServiceWorker(..) => "ConnectServiceWorker"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,10 @@ pub struct ScopeThings {
|
||||||
pub worker_id: WorkerId,
|
pub worker_id: WorkerId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Message that gets passed to service worker scope on postMessage
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct DOMMessage(pub Vec<u64>);
|
||||||
|
|
||||||
/// Channels to allow service worker manager to communicate with constellation and resource thread
|
/// Channels to allow service worker manager to communicate with constellation and resource thread
|
||||||
pub struct SWManagerSenders {
|
pub struct SWManagerSenders {
|
||||||
/// sender for communicating with constellation
|
/// sender for communicating with constellation
|
||||||
|
@ -182,4 +186,7 @@ pub enum ServiceWorkerMsg {
|
||||||
pub enum SWManagerMsg {
|
pub enum SWManagerMsg {
|
||||||
/// Provide the constellation with a means of communicating with the Service Worker Manager
|
/// Provide the constellation with a means of communicating with the Service Worker Manager
|
||||||
OwnSender(IpcSender<ServiceWorkerMsg>),
|
OwnSender(IpcSender<ServiceWorkerMsg>),
|
||||||
|
/// Message to ask to get a Trusted<ServiceWorker> to constellation
|
||||||
|
ConnectServiceWorker(Url, PipelineId, IpcSender<DOMMessage>)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,8 @@ self.addEventListener('activate', function(e) {
|
||||||
|
|
||||||
self.addEventListener('fetch', function(e) {
|
self.addEventListener('fetch', function(e) {
|
||||||
console.log("A fetch event detected by /iframe service worker");
|
console.log("A fetch event detected by /iframe service worker");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.addEventListener('message', function(e) {
|
||||||
|
console.log('Post message payload ' + e.data.msg);
|
||||||
|
})
|
||||||
|
|
|
@ -23,6 +23,13 @@
|
||||||
console.log("From client worker registered: ", navigator.serviceWorker.controller);
|
console.log("From client worker registered: ", navigator.serviceWorker.controller);
|
||||||
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
|
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
|
||||||
document.getElementById('iframe_sw').src = 'demo_iframe.html';
|
document.getElementById('iframe_sw').src = 'demo_iframe.html';
|
||||||
|
var payload = { msg: 'Hi from /iframe service worker' };
|
||||||
|
|
||||||
|
// The delay is due to the sender being set in the service worker object after the scope starts.
|
||||||
|
// This won't be needed when service workers are wrapped with Promises.
|
||||||
|
setTimeout(function() {
|
||||||
|
navigator.serviceWorker.controller.postMessage(payload);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
function register_zero() {
|
function register_zero() {
|
||||||
var reg = navigator.serviceWorker.register('sw.js', { 'scope': './' });
|
var reg = navigator.serviceWorker.register('sw.js', { 'scope': './' });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue