mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Integrate service worker manager thread
This commit is contained in:
parent
e8fa02a07f
commit
1e6293ea1d
39 changed files with 764 additions and 582 deletions
|
@ -8,8 +8,7 @@
|
|||
use dom::bindings::js::JS;
|
||||
use dom::document::Document;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{PendingAsyncLoad, LoadContext};
|
||||
use net_traits::{RequestSource, AsyncResponseTarget};
|
||||
use net_traits::{PendingAsyncLoad, AsyncResponseTarget, LoadContext};
|
||||
use net_traits::{ResourceThreads, IpcSend};
|
||||
use std::thread;
|
||||
use url::Url;
|
||||
|
@ -130,14 +129,12 @@ impl DocumentLoader {
|
|||
let context = load.to_load_context();
|
||||
let url = load.url().clone();
|
||||
self.add_blocking_load(load);
|
||||
let client_chan = referrer.window().custom_message_chan();
|
||||
PendingAsyncLoad::new(context,
|
||||
self.resource_threads.sender(),
|
||||
url,
|
||||
self.pipeline,
|
||||
referrer.get_referrer_policy(),
|
||||
Some(referrer.url().clone()),
|
||||
RequestSource::Window(client_chan))
|
||||
Some(referrer.url().clone()))
|
||||
}
|
||||
|
||||
/// Create and initiate a new network request.
|
||||
|
|
|
@ -8,10 +8,7 @@ use dom::bindings::str::DOMString;
|
|||
use dom::bindings::structuredclone::StructuredCloneData;
|
||||
use js::jsapi::{JSRuntime, JS_RequestInterruptCallback};
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::{PipelineId, ReferrerPolicy};
|
||||
use net_traits::{LoadOrigin, RequestSource};
|
||||
use script_runtime::CommonScriptMsg;
|
||||
use url::Url;
|
||||
|
||||
/// Messages used to control the worker event loops
|
||||
pub enum WorkerScriptMsg {
|
||||
|
@ -21,29 +18,6 @@ pub enum WorkerScriptMsg {
|
|||
DOMMessage(StructuredCloneData),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WorkerScriptLoadOrigin {
|
||||
pub referrer_url: Option<Url>,
|
||||
pub referrer_policy: Option<ReferrerPolicy>,
|
||||
pub request_source: RequestSource,
|
||||
pub pipeline_id: Option<PipelineId>
|
||||
}
|
||||
|
||||
impl LoadOrigin for WorkerScriptLoadOrigin {
|
||||
fn referrer_url(&self) -> Option<Url> {
|
||||
self.referrer_url.clone()
|
||||
}
|
||||
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
|
||||
self.referrer_policy.clone()
|
||||
}
|
||||
fn request_source(&self) -> RequestSource {
|
||||
self.request_source.clone()
|
||||
}
|
||||
fn pipeline_id(&self) -> Option<PipelineId> {
|
||||
self.pipeline_id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleWorkerErrorHandler<T: Reflectable> {
|
||||
pub addr: Trusted<T>,
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue};
|
|||
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
|
||||
use msg::constellation_msg::{PipelineId, PanicMsg};
|
||||
use net_traits::filemanager_thread::FileManagerThreadMsg;
|
||||
use net_traits::{ResourceThreads, CoreResourceThread, RequestSource, IpcSend};
|
||||
use net_traits::{ResourceThreads, CoreResourceThread, IpcSend};
|
||||
use profile_traits::{mem, time};
|
||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort};
|
||||
use script_thread::{MainThreadScriptChan, ScriptThread, RunnableWrapper};
|
||||
|
@ -66,14 +66,6 @@ impl<'a> GlobalRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// gets the custom message channel associated with global object
|
||||
pub fn request_source(&self) -> RequestSource {
|
||||
match *self {
|
||||
GlobalRef::Window(ref window) => RequestSource::Window(window.custom_message_chan()),
|
||||
GlobalRef::Worker(ref worker) => RequestSource::Worker(worker.custom_message_chan()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `PipelineId` for this global scope.
|
||||
pub fn pipeline(&self) -> PipelineId {
|
||||
match *self {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use devtools;
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt , SimpleWorkerErrorHandler};
|
||||
use dom::abstractworker::{WorkerScriptMsg, SharedRt , SimpleWorkerErrorHandler};
|
||||
use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
|
||||
|
@ -21,7 +21,6 @@ use dom::bindings::structuredclone::StructuredCloneData;
|
|||
use dom::messageevent::MessageEvent;
|
||||
use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler};
|
||||
use dom::workerglobalscope::WorkerGlobalScope;
|
||||
use dom::workerglobalscope::WorkerGlobalScopeInit;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::{HandleValue, JS_SetInterruptCallback};
|
||||
|
@ -29,12 +28,13 @@ use js::jsapi::{JSAutoCompartment, JSContext};
|
|||
use js::jsval::UndefinedValue;
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{LoadContext, load_whole_resource, CustomResponse, IpcSend};
|
||||
use net_traits::{LoadContext, load_whole_resource, IpcSend};
|
||||
use rand::random;
|
||||
use script_runtime::ScriptThreadEventCategory::WorkerEvent;
|
||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
|
||||
use script_traits::{TimerEvent, TimerSource};
|
||||
use script_traits::{TimerEvent, TimerSource, WorkerScriptLoadOrigin, WorkerGlobalScopeInit};
|
||||
use std::mem::replace;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use url::Url;
|
||||
|
@ -70,8 +70,7 @@ impl<'a> Drop for AutoWorkerReset<'a> {
|
|||
enum MixedMessage {
|
||||
FromWorker((TrustedWorkerAddress, WorkerScriptMsg)),
|
||||
FromScheduler((TrustedWorkerAddress, TimerEvent)),
|
||||
FromDevtools(DevtoolScriptControlMsg),
|
||||
FromNetwork(IpcSender<Option<CustomResponse>>),
|
||||
FromDevtools(DevtoolScriptControlMsg)
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dedicatedworkerglobalscope
|
||||
|
@ -102,14 +101,16 @@ impl DedicatedWorkerGlobalScope {
|
|||
own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>)
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||
closing: Arc<AtomicBool>)
|
||||
-> DedicatedWorkerGlobalScope {
|
||||
DedicatedWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
||||
worker_url,
|
||||
runtime,
|
||||
from_devtools_receiver,
|
||||
timer_event_chan),
|
||||
timer_event_chan,
|
||||
Some(closing)),
|
||||
id: id,
|
||||
receiver: receiver,
|
||||
own_sender: own_sender,
|
||||
|
@ -128,7 +129,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>)
|
||||
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
|
||||
closing: Arc<AtomicBool>)
|
||||
-> Root<DedicatedWorkerGlobalScope> {
|
||||
let cx = runtime.cx();
|
||||
let scope = box DedicatedWorkerGlobalScope::new_inherited(init,
|
||||
|
@ -140,7 +142,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
own_sender,
|
||||
receiver,
|
||||
timer_event_chan,
|
||||
timer_event_port);
|
||||
timer_event_port,
|
||||
closing);
|
||||
DedicatedWorkerGlobalScopeBinding::Wrap(cx, scope)
|
||||
}
|
||||
|
||||
|
@ -154,7 +157,8 @@ impl DedicatedWorkerGlobalScope {
|
|||
parent_sender: Box<ScriptChan + Send>,
|
||||
own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
|
||||
worker_load_origin: WorkerScriptLoadOrigin) {
|
||||
worker_load_origin: WorkerScriptLoadOrigin,
|
||||
closing: Arc<AtomicBool>) {
|
||||
let serialized_worker_url = worker_url.to_string();
|
||||
let name = format!("WebWorker for {}", serialized_worker_url);
|
||||
let panic_chan = init.panic_chan.clone();
|
||||
|
@ -193,7 +197,7 @@ impl DedicatedWorkerGlobalScope {
|
|||
let global = DedicatedWorkerGlobalScope::new(
|
||||
init, url, id, devtools_mpsc_port, runtime,
|
||||
parent_sender.clone(), own_sender, receiver,
|
||||
timer_ipc_chan, timer_rx);
|
||||
timer_ipc_chan, timer_rx, closing);
|
||||
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
||||
// registration (#6631), so we instead use a random number and cross our fingers.
|
||||
let scope = global.upcast::<WorkerGlobalScope>();
|
||||
|
@ -254,20 +258,17 @@ impl DedicatedWorkerGlobalScope {
|
|||
let worker_port = &self.receiver;
|
||||
let timer_event_port = &self.timer_event_port;
|
||||
let devtools_port = scope.from_devtools_receiver();
|
||||
let msg_port = scope.custom_message_port();
|
||||
|
||||
let sel = Select::new();
|
||||
let mut worker_handle = sel.handle(worker_port);
|
||||
let mut timer_event_handle = sel.handle(timer_event_port);
|
||||
let mut devtools_handle = sel.handle(devtools_port);
|
||||
let mut msg_port_handle = sel.handle(msg_port);
|
||||
unsafe {
|
||||
worker_handle.add();
|
||||
timer_event_handle.add();
|
||||
if scope.from_devtools_sender().is_some() {
|
||||
devtools_handle.add();
|
||||
}
|
||||
msg_port_handle.add();
|
||||
}
|
||||
let ret = sel.wait();
|
||||
if ret == worker_handle.id() {
|
||||
|
@ -276,8 +277,6 @@ impl DedicatedWorkerGlobalScope {
|
|||
Ok(MixedMessage::FromScheduler(try!(timer_event_port.recv())))
|
||||
} else if ret == devtools_handle.id() {
|
||||
Ok(MixedMessage::FromDevtools(try!(devtools_port.recv())))
|
||||
} else if ret == msg_port_handle.id() {
|
||||
Ok(MixedMessage::FromNetwork(try!(msg_port.recv())))
|
||||
} else {
|
||||
panic!("unexpected select result!")
|
||||
}
|
||||
|
@ -339,10 +338,6 @@ impl DedicatedWorkerGlobalScope {
|
|||
MixedMessage::FromWorker((linked_worker, msg)) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
self.handle_script_event(msg);
|
||||
},
|
||||
MixedMessage::FromNetwork(network_sender) => {
|
||||
// We send None as of now
|
||||
let _ = network_sender.send(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* 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::abstractworker::WorkerScriptMsg;
|
||||
use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerErrorHandler};
|
||||
use dom::abstractworker::{WorkerScriptMsg, WorkerScriptLoadOrigin, SharedRt};
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
|
||||
|
@ -13,19 +13,13 @@ use dom::bindings::js::Root;
|
|||
use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
|
||||
use dom::bindings::str::{DOMString, USVString};
|
||||
use dom::client::Client;
|
||||
use dom::errorevent::ErrorEvent;
|
||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||
use dom::workerglobalscope::prepare_workerscope_init;
|
||||
use ipc_channel::ipc;
|
||||
use js::jsval::UndefinedValue;
|
||||
use script_thread::Runnable;
|
||||
use std::cell::Cell;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::Sender;
|
||||
use url::Url;
|
||||
|
||||
pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
|
||||
|
@ -35,36 +29,27 @@ pub struct ServiceWorker {
|
|||
eventtarget: EventTarget,
|
||||
script_url: DOMRefCell<String>,
|
||||
state: Cell<ServiceWorkerState>,
|
||||
closing: Arc<AtomicBool>,
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
#[ignore_heap_size_of = "Defined in rust-mozjs"]
|
||||
runtime: Arc<Mutex<Option<SharedRt>>>,
|
||||
sender: Option<Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>>,
|
||||
skip_waiting: Cell<bool>
|
||||
}
|
||||
|
||||
impl ServiceWorker {
|
||||
fn new_inherited(sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
closing: Arc<AtomicBool>,
|
||||
script_url: &str,
|
||||
fn new_inherited(script_url: &str,
|
||||
skip_waiting: bool) -> ServiceWorker {
|
||||
ServiceWorker {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
closing: closing,
|
||||
sender: sender,
|
||||
sender: None,
|
||||
script_url: DOMRefCell::new(String::from(script_url)),
|
||||
state: Cell::new(ServiceWorkerState::Installing),
|
||||
runtime: Arc::new(Mutex::new(None)),
|
||||
skip_waiting: Cell::new(skip_waiting)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef,
|
||||
closing: Arc<AtomicBool>,
|
||||
sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
script_url: &str,
|
||||
skip_waiting: bool) -> Root<ServiceWorker> {
|
||||
reflect_dom_object(box ServiceWorker::new_inherited(sender, closing, script_url, skip_waiting), global, Wrap)
|
||||
reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting), global, Wrap)
|
||||
}
|
||||
|
||||
pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) {
|
||||
|
@ -72,23 +57,19 @@ impl ServiceWorker {
|
|||
service_worker.upcast().fire_simple_event("error");
|
||||
}
|
||||
|
||||
pub fn is_closing(&self) -> bool {
|
||||
self.closing.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn set_transition_state(&self, state: ServiceWorkerState) {
|
||||
self.state.set(state);
|
||||
self.upcast::<EventTarget>().fire_simple_event("statechange");
|
||||
}
|
||||
|
||||
pub fn get_script_url(&self) -> Url {
|
||||
Url::parse(&self.script_url.borrow().clone()).unwrap()
|
||||
}
|
||||
|
||||
pub fn handle_error_message(address: TrustedServiceWorkerAddress, message: DOMString,
|
||||
filename: DOMString, lineno: u32, colno: u32) {
|
||||
let worker = address.root();
|
||||
|
||||
if worker.is_closing() {
|
||||
return;
|
||||
}
|
||||
|
||||
let global = worker.r().global();
|
||||
rooted!(in(global.r().get_cx()) let error = UndefinedValue());
|
||||
let errorevent = ErrorEvent::new(global.r(), atom!("error"),
|
||||
|
@ -97,42 +78,12 @@ impl ServiceWorker {
|
|||
errorevent.upcast::<Event>().fire(worker.upcast());
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn init_service_worker(global: GlobalRef,
|
||||
script_url: Url,
|
||||
skip_waiting: bool) -> Root<ServiceWorker> {
|
||||
let (sender, receiver) = channel();
|
||||
let closing = Arc::new(AtomicBool::new(false));
|
||||
let worker = ServiceWorker::new(global,
|
||||
closing.clone(),
|
||||
sender.clone(),
|
||||
script_url.as_str(),
|
||||
skip_waiting);
|
||||
let worker_ref = Trusted::new(worker.r());
|
||||
|
||||
let worker_load_origin = WorkerScriptLoadOrigin {
|
||||
referrer_url: None,
|
||||
referrer_policy: None,
|
||||
request_source: global.request_source(),
|
||||
pipeline_id: Some(global.pipeline())
|
||||
};
|
||||
|
||||
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
|
||||
let init = prepare_workerscope_init(global,
|
||||
"Service Worker".to_owned(),
|
||||
script_url.clone(),
|
||||
devtools_sender.clone(),
|
||||
closing);
|
||||
|
||||
// represents a service worker client
|
||||
let sw_client = Client::new(global.as_window());
|
||||
let trusted_client = Trusted::new(&*sw_client);
|
||||
|
||||
ServiceWorkerGlobalScope::run_serviceworker_scope(
|
||||
init, script_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref,
|
||||
global.script_chan(), sender, receiver, trusted_client, worker_load_origin);
|
||||
|
||||
worker
|
||||
pub fn install_serviceworker(global: GlobalRef,
|
||||
script_url: Url,
|
||||
skip_waiting: bool) -> Root<ServiceWorker> {
|
||||
ServiceWorker::new(global,
|
||||
script_url.as_str(),
|
||||
skip_waiting)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
|
|||
script_url,
|
||||
scope_str.clone(),
|
||||
self);
|
||||
ScriptThread::set_registration(scope, &*worker_registration);
|
||||
ScriptThread::set_registration(scope, &*worker_registration, self.global().r().pipeline());
|
||||
Ok(worker_registration)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
use devtools;
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt, SimpleWorkerErrorHandler};
|
||||
use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
|
||||
use dom::abstractworker::WorkerScriptMsg;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
|
||||
|
@ -13,66 +12,34 @@ use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWo
|
|||
use dom::bindings::global::{GlobalRef, global_root_from_context};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::{Root, RootCollection};
|
||||
use dom::bindings::refcounted::{Trusted, LiveDOMReferences};
|
||||
use dom::bindings::refcounted::LiveDOMReferences;
|
||||
use dom::bindings::reflector::Reflectable;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::client::Client;
|
||||
use dom::messageevent::MessageEvent;
|
||||
use dom::serviceworker::TrustedServiceWorkerAddress;
|
||||
use dom::workerglobalscope::WorkerGlobalScope;
|
||||
use dom::workerglobalscope::WorkerGlobalScopeInit;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{LoadContext, load_whole_resource, CustomResponse, IpcSend};
|
||||
use rand::random;
|
||||
use script_runtime::ScriptThreadEventCategory::ServiceWorkerEvent;
|
||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
|
||||
use script_traits::{TimerEvent, TimerSource};
|
||||
use std::mem::replace;
|
||||
use net_traits::{LoadContext, load_whole_resource, IpcSend};
|
||||
use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx};
|
||||
use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg};
|
||||
use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
use util::prefs::PREFS;
|
||||
use util::thread::spawn_named;
|
||||
use util::thread_state;
|
||||
use util::thread_state::{IN_WORKER, SCRIPT};
|
||||
|
||||
/// Set the `worker` field of a related ServiceWorkerGlobalScope object to a particular
|
||||
/// value for the duration of this object's lifetime. This ensures that the related Worker
|
||||
/// object only lives as long as necessary (ie. while events are being executed), while
|
||||
/// providing a reference that can be cloned freely.
|
||||
struct AutoWorkerReset<'a> {
|
||||
workerscope: &'a ServiceWorkerGlobalScope,
|
||||
old_worker: Option<TrustedServiceWorkerAddress>,
|
||||
}
|
||||
|
||||
impl<'a> AutoWorkerReset<'a> {
|
||||
fn new(workerscope: &'a ServiceWorkerGlobalScope,
|
||||
worker: TrustedServiceWorkerAddress)
|
||||
-> AutoWorkerReset<'a> {
|
||||
AutoWorkerReset {
|
||||
workerscope: workerscope,
|
||||
old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for AutoWorkerReset<'a> {
|
||||
fn drop(&mut self) {
|
||||
*self.workerscope.worker.borrow_mut() = self.old_worker.clone();
|
||||
}
|
||||
}
|
||||
|
||||
enum MixedMessage {
|
||||
pub enum MixedMessage {
|
||||
FromServiceWorker((TrustedServiceWorkerAddress, WorkerScriptMsg)),
|
||||
FromScheduler((TrustedServiceWorkerAddress, TimerEvent)),
|
||||
FromDevtools(DevtoolScriptControlMsg),
|
||||
FromNetwork(IpcSender<Option<CustomResponse>>),
|
||||
FromTimeoutThread(()),
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -84,14 +51,13 @@ pub struct ServiceWorkerGlobalScope {
|
|||
#[ignore_heap_size_of = "Defined in std"]
|
||||
own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
|
||||
timer_event_port: Receiver<()>,
|
||||
#[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"]
|
||||
worker: DOMRefCell<Option<TrustedServiceWorkerAddress>>,
|
||||
#[ignore_heap_size_of = "Can't measure trait objects"]
|
||||
/// Sender to the parent thread.
|
||||
parent_sender: Box<ScriptChan + Send>,
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
service_worker_client: Trusted<Client>
|
||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
scope_url: Url
|
||||
}
|
||||
|
||||
impl ServiceWorkerGlobalScope {
|
||||
|
@ -100,26 +66,27 @@ impl ServiceWorkerGlobalScope {
|
|||
id: PipelineId,
|
||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
runtime: Runtime,
|
||||
parent_sender: Box<ScriptChan + Send>,
|
||||
own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
|
||||
client: Trusted<Client>)
|
||||
timer_event_port: Receiver<()>,
|
||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||
scope_url: Url)
|
||||
-> ServiceWorkerGlobalScope {
|
||||
ServiceWorkerGlobalScope {
|
||||
workerglobalscope: WorkerGlobalScope::new_inherited(init,
|
||||
worker_url,
|
||||
runtime,
|
||||
from_devtools_receiver,
|
||||
timer_event_chan),
|
||||
timer_event_chan,
|
||||
None),
|
||||
id: id,
|
||||
receiver: receiver,
|
||||
own_sender: own_sender,
|
||||
timer_event_port: timer_event_port,
|
||||
parent_sender: parent_sender,
|
||||
own_sender: own_sender,
|
||||
worker: DOMRefCell::new(None),
|
||||
service_worker_client: client
|
||||
swmanager_sender: swmanager_sender,
|
||||
scope_url: scope_url
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,12 +95,12 @@ impl ServiceWorkerGlobalScope {
|
|||
id: PipelineId,
|
||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
runtime: Runtime,
|
||||
parent_sender: Box<ScriptChan + Send>,
|
||||
own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
|
||||
client: Trusted<Client>)
|
||||
timer_event_port: Receiver<()>,
|
||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||
scope_url: Url)
|
||||
-> Root<ServiceWorkerGlobalScope> {
|
||||
let cx = runtime.cx();
|
||||
let scope = box ServiceWorkerGlobalScope::new_inherited(init,
|
||||
|
@ -141,42 +108,39 @@ impl ServiceWorkerGlobalScope {
|
|||
id,
|
||||
from_devtools_receiver,
|
||||
runtime,
|
||||
parent_sender,
|
||||
own_sender,
|
||||
receiver,
|
||||
timer_event_chan,
|
||||
timer_event_port,
|
||||
client);
|
||||
swmanager_sender,
|
||||
scope_url);
|
||||
ServiceWorkerGlobalScopeBinding::Wrap(cx, scope)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn run_serviceworker_scope(init: WorkerGlobalScopeInit,
|
||||
worker_url: Url,
|
||||
id: PipelineId,
|
||||
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
||||
main_thread_rt: Arc<Mutex<Option<SharedRt>>>,
|
||||
worker: TrustedServiceWorkerAddress,
|
||||
parent_sender: Box<ScriptChan + Send>,
|
||||
pub fn run_serviceworker_scope(scope_things: ScopeThings,
|
||||
own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
|
||||
client: Trusted<Client>,
|
||||
worker_load_origin: WorkerScriptLoadOrigin) {
|
||||
let serialized_worker_url = worker_url.to_string();
|
||||
devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
|
||||
swmanager_sender: IpcSender<ServiceWorkerMsg>,
|
||||
scope_url: Url) {
|
||||
let ScopeThings { script_url,
|
||||
pipeline_id,
|
||||
init,
|
||||
worker_load_origin,
|
||||
.. } = scope_things;
|
||||
|
||||
let serialized_worker_url = script_url.to_string();
|
||||
spawn_named(format!("ServiceWorker for {}", serialized_worker_url), move || {
|
||||
thread_state::initialize(SCRIPT | IN_WORKER);
|
||||
|
||||
let roots = RootCollection::new();
|
||||
let _stack_roots_tls = StackRootTLS::new(&roots);
|
||||
|
||||
let (url, source) = match load_whole_resource(LoadContext::Script,
|
||||
&init.resource_threads.sender(),
|
||||
worker_url,
|
||||
script_url,
|
||||
&worker_load_origin) {
|
||||
Err(_) => {
|
||||
println!("error loading script {}", serialized_worker_url);
|
||||
parent_sender.send(CommonScriptMsg::RunnableMsg(ServiceWorkerEvent,
|
||||
box SimpleWorkerErrorHandler::new(worker))).unwrap();
|
||||
return;
|
||||
}
|
||||
Ok((metadata, bytes)) => {
|
||||
|
@ -185,25 +149,18 @@ impl ServiceWorkerGlobalScope {
|
|||
};
|
||||
|
||||
let runtime = unsafe { new_rt_and_cx() };
|
||||
*main_thread_rt.lock().unwrap() = Some(SharedRt::new(&runtime));
|
||||
|
||||
let (devtools_mpsc_chan, devtools_mpsc_port) = channel();
|
||||
ROUTER.route_ipc_receiver_to_mpsc_sender(from_devtools_receiver, devtools_mpsc_chan);
|
||||
ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_receiver, devtools_mpsc_chan);
|
||||
|
||||
let (timer_tx, timer_rx) = channel();
|
||||
let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
|
||||
let worker_for_route = worker.clone();
|
||||
ROUTER.add_route(timer_ipc_port.to_opaque(), box move |message| {
|
||||
let event = message.to().unwrap();
|
||||
timer_tx.send((worker_for_route.clone(), event)).unwrap();
|
||||
});
|
||||
// TODO XXXcreativcoder use this timer_ipc_port, when we have a service worker instance here
|
||||
let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap();
|
||||
let (timer_chan, timer_port) = channel();
|
||||
|
||||
let global = ServiceWorkerGlobalScope::new(
|
||||
init, url, id, devtools_mpsc_port, runtime,
|
||||
parent_sender.clone(), own_sender, receiver,
|
||||
timer_ipc_chan, timer_rx, client);
|
||||
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
|
||||
// registration (#6631), so we instead use a random number and cross our fingers.
|
||||
init, url, pipeline_id, devtools_mpsc_port, runtime,
|
||||
own_sender, receiver,
|
||||
timer_ipc_chan, timer_port, swmanager_sender, scope_url);
|
||||
let scope = global.upcast::<WorkerGlobalScope>();
|
||||
|
||||
unsafe {
|
||||
|
@ -211,35 +168,25 @@ impl ServiceWorkerGlobalScope {
|
|||
JS_SetInterruptCallback(scope.runtime(), Some(interrupt_callback));
|
||||
}
|
||||
|
||||
if scope.is_closing() {
|
||||
return;
|
||||
}
|
||||
scope.execute_script(DOMString::from(source));
|
||||
|
||||
{
|
||||
let _ar = AutoWorkerReset::new(global.r(), worker);
|
||||
scope.execute_script(DOMString::from(source));
|
||||
}
|
||||
|
||||
|
||||
let reporter_name = format!("service-worker-reporter-{}", random::<u64>());
|
||||
scope.mem_profiler_chan().run_with_memory_reporting(|| {
|
||||
// Service workers are time limited
|
||||
let sw_lifetime = Instant::now();
|
||||
// Service workers are time limited
|
||||
spawn_named("SWTimeoutThread".to_owned(), move || {
|
||||
let sw_lifetime_timeout = PREFS.get("dom.serviceworker.timeout_seconds").as_u64().unwrap();
|
||||
while let Ok(event) = global.receive_event() {
|
||||
if scope.is_closing() {
|
||||
break;
|
||||
}
|
||||
global.handle_event(event);
|
||||
if sw_lifetime.elapsed().as_secs() == sw_lifetime_timeout {
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::new(sw_lifetime_timeout, 0));
|
||||
let _ = timer_chan.send(());
|
||||
});
|
||||
|
||||
// TODO XXXcreativcoder bring back run_with_memory_reporting when things are more concrete here.
|
||||
while let Ok(event) = global.receive_event() {
|
||||
if !global.handle_event(event) {
|
||||
break;
|
||||
}
|
||||
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_event(&self, event: MixedMessage) {
|
||||
fn handle_event(&self, event: MixedMessage) -> bool {
|
||||
match event {
|
||||
MixedMessage::FromDevtools(msg) => {
|
||||
let global_ref = GlobalRef::Worker(self.upcast());
|
||||
|
@ -252,26 +199,15 @@ impl ServiceWorkerGlobalScope {
|
|||
devtools::handle_wants_live_notifications(&global_ref, bool_val),
|
||||
_ => debug!("got an unusable devtools control message inside the worker!"),
|
||||
}
|
||||
},
|
||||
MixedMessage::FromScheduler((linked_worker, timer_event)) => {
|
||||
match timer_event {
|
||||
TimerEvent(TimerSource::FromWorker, id) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
let scope = self.upcast::<WorkerGlobalScope>();
|
||||
scope.handle_fire_timer(id);
|
||||
},
|
||||
TimerEvent(_, _) => {
|
||||
panic!("The service worker received a TimerEvent from a window.")
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
MixedMessage::FromServiceWorker((linked_worker, msg)) => {
|
||||
let _ar = AutoWorkerReset::new(self, linked_worker);
|
||||
MixedMessage::FromServiceWorker((_, msg)) => {
|
||||
self.handle_script_event(msg);
|
||||
},
|
||||
MixedMessage::FromNetwork(network_sender) => {
|
||||
// We send None as of now
|
||||
let _ = network_sender.send(None);
|
||||
true
|
||||
}
|
||||
MixedMessage::FromTimeoutThread(_) => {
|
||||
let _ = self.swmanager_sender.send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -307,44 +243,33 @@ impl ServiceWorkerGlobalScope {
|
|||
fn receive_event(&self) -> Result<MixedMessage, RecvError> {
|
||||
let scope = self.upcast::<WorkerGlobalScope>();
|
||||
let worker_port = &self.receiver;
|
||||
let timer_event_port = &self.timer_event_port;
|
||||
let devtools_port = scope.from_devtools_receiver();
|
||||
let msg_port = scope.custom_message_port();
|
||||
let timer_event_port = &self.timer_event_port;
|
||||
|
||||
let sel = Select::new();
|
||||
let mut worker_handle = sel.handle(worker_port);
|
||||
let mut timer_event_handle = sel.handle(timer_event_port);
|
||||
let mut devtools_handle = sel.handle(devtools_port);
|
||||
let mut msg_port_handle = sel.handle(msg_port);
|
||||
let mut timer_port_handle = sel.handle(timer_event_port);
|
||||
unsafe {
|
||||
worker_handle.add();
|
||||
timer_event_handle.add();
|
||||
if scope.from_devtools_sender().is_some() {
|
||||
devtools_handle.add();
|
||||
}
|
||||
msg_port_handle.add();
|
||||
timer_port_handle.add();
|
||||
}
|
||||
|
||||
let ret = sel.wait();
|
||||
if ret == worker_handle.id() {
|
||||
Ok(MixedMessage::FromServiceWorker(try!(worker_port.recv())))
|
||||
} else if ret == timer_event_handle.id() {
|
||||
Ok(MixedMessage::FromScheduler(try!(timer_event_port.recv())))
|
||||
} else if ret == devtools_handle.id() {
|
||||
}else if ret == devtools_handle.id() {
|
||||
Ok(MixedMessage::FromDevtools(try!(devtools_port.recv())))
|
||||
} else if ret == msg_port_handle.id() {
|
||||
Ok(MixedMessage::FromNetwork(try!(msg_port.recv())))
|
||||
} else if ret == timer_port_handle.id() {
|
||||
Ok(MixedMessage::FromTimeoutThread(try!(timer_event_port.recv())))
|
||||
} else {
|
||||
panic!("unexpected select result!")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
|
||||
box WorkerThreadWorkerChan {
|
||||
sender: self.own_sender.clone(),
|
||||
worker: self.worker.borrow().as_ref().unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipeline(&self) -> PipelineId {
|
||||
self.id
|
||||
}
|
||||
|
@ -352,15 +277,6 @@ impl ServiceWorkerGlobalScope {
|
|||
pub fn process_event(&self, msg: CommonScriptMsg) {
|
||||
self.handle_script_event(WorkerScriptMsg::Common(msg));
|
||||
}
|
||||
|
||||
pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
|
||||
let (tx, rx) = channel();
|
||||
let chan = box SendableWorkerScriptChan {
|
||||
sender: tx,
|
||||
worker: self.worker.borrow().as_ref().unwrap().clone(),
|
||||
};
|
||||
(chan, box rx)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -11,6 +11,8 @@ use dom::bindings::str::USVString;
|
|||
use dom::eventtarget::EventTarget;
|
||||
use dom::serviceworker::ServiceWorker;
|
||||
use dom::serviceworkercontainer::Controllable;
|
||||
use dom::workerglobalscope::prepare_workerscope_init;
|
||||
use script_traits::{WorkerScriptLoadOrigin, ScopeThings};
|
||||
use url::Url;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -19,7 +21,7 @@ pub struct ServiceWorkerRegistration {
|
|||
active: Option<JS<ServiceWorker>>,
|
||||
installing: Option<JS<ServiceWorker>>,
|
||||
waiting: Option<JS<ServiceWorker>>,
|
||||
scope: String,
|
||||
scope: String
|
||||
}
|
||||
|
||||
impl ServiceWorkerRegistration {
|
||||
|
@ -29,7 +31,7 @@ impl ServiceWorkerRegistration {
|
|||
active: Some(JS::from_ref(active_sw)),
|
||||
installing: None,
|
||||
waiting: None,
|
||||
scope: scope
|
||||
scope: scope,
|
||||
}
|
||||
}
|
||||
#[allow(unrooted_must_root)]
|
||||
|
@ -37,11 +39,47 @@ impl ServiceWorkerRegistration {
|
|||
script_url: Url,
|
||||
scope: String,
|
||||
container: &Controllable) -> Root<ServiceWorkerRegistration> {
|
||||
let active_worker = ServiceWorker::init_service_worker(global, script_url, true);
|
||||
let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), true);
|
||||
active_worker.set_transition_state(ServiceWorkerState::Installed);
|
||||
container.set_controller(&*active_worker.clone());
|
||||
reflect_dom_object(box ServiceWorkerRegistration::new_inherited(&*active_worker, scope), global, Wrap)
|
||||
}
|
||||
|
||||
pub fn get_installed(&self) -> &ServiceWorker {
|
||||
self.active.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn create_scope_things(global: GlobalRef, script_url: Url) -> ScopeThings {
|
||||
let worker_load_origin = WorkerScriptLoadOrigin {
|
||||
referrer_url: None,
|
||||
referrer_policy: None,
|
||||
pipeline_id: Some(global.pipeline())
|
||||
};
|
||||
|
||||
let worker_id = global.get_next_worker_id();
|
||||
let init = prepare_workerscope_init(global, None);
|
||||
ScopeThings {
|
||||
script_url: script_url,
|
||||
pipeline_id: global.pipeline(),
|
||||
init: init,
|
||||
worker_load_origin: worker_load_origin,
|
||||
devtools_chan: global.devtools_chan(),
|
||||
worker_id: worker_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn longest_prefix_match(stored_scope: &Url, potential_match: &Url) -> bool {
|
||||
if stored_scope.origin() != potential_match.origin() {
|
||||
return false;
|
||||
}
|
||||
let scope_chars = stored_scope.path().chars();
|
||||
let matching_chars = potential_match.path().chars();
|
||||
if scope_chars.count() > matching_chars.count() {
|
||||
return false;
|
||||
}
|
||||
|
||||
stored_scope.path().chars().zip(potential_match.path().chars()).all(|(scope, matched)| scope == matched)
|
||||
}
|
||||
|
||||
impl ServiceWorkerRegistrationMethods for ServiceWorkerRegistration {
|
||||
|
|
|
@ -44,10 +44,10 @@ use js::rust::CompileOptionsWrapper;
|
|||
use js::rust::Runtime;
|
||||
use libc;
|
||||
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, SubpageId, WindowSizeType};
|
||||
use net_traits::ResourceThreads;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use net_traits::{ResourceThreads, CustomResponseSender};
|
||||
use num_traits::ToPrimitive;
|
||||
use open;
|
||||
use profile_traits::mem;
|
||||
|
@ -155,8 +155,6 @@ pub struct Window {
|
|||
image_cache_thread: ImageCacheThread,
|
||||
#[ignore_heap_size_of = "channels are hard"]
|
||||
image_cache_chan: ImageCacheChan,
|
||||
#[ignore_heap_size_of = "channels are hard"]
|
||||
custom_message_chan: IpcSender<CustomResponseSender>,
|
||||
browsing_context: MutNullableHeap<JS<BrowsingContext>>,
|
||||
performance: MutNullableHeap<JS<Performance>>,
|
||||
navigation_start: u64,
|
||||
|
@ -314,10 +312,6 @@ impl Window {
|
|||
self.image_cache_chan.clone()
|
||||
}
|
||||
|
||||
pub fn custom_message_chan(&self) -> IpcSender<CustomResponseSender> {
|
||||
self.custom_message_chan.clone()
|
||||
}
|
||||
|
||||
pub fn get_next_worker_id(&self) -> WorkerId {
|
||||
let worker_id = self.next_worker_id.get();
|
||||
let WorkerId(id_num) = worker_id;
|
||||
|
@ -1605,7 +1599,6 @@ impl Window {
|
|||
history_task_source: HistoryTraversalTaskSource,
|
||||
file_task_source: FileReadingTaskSource,
|
||||
image_cache_chan: ImageCacheChan,
|
||||
custom_message_chan: IpcSender<CustomResponseSender>,
|
||||
image_cache_thread: ImageCacheThread,
|
||||
resource_threads: ResourceThreads,
|
||||
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
|
@ -1641,7 +1634,6 @@ impl Window {
|
|||
history_traversal_task_source: history_task_source,
|
||||
file_reading_task_source: file_task_source,
|
||||
image_cache_chan: image_cache_chan,
|
||||
custom_message_chan: custom_message_chan,
|
||||
console: Default::default(),
|
||||
crypto: Default::default(),
|
||||
navigator: Default::default(),
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* 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 devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolsPageInfo};
|
||||
use dom::abstractworker::WorkerScriptMsg;
|
||||
use dom::abstractworker::{SimpleWorkerErrorHandler, SharedRt, WorkerErrorHandler};
|
||||
use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg};
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||
use dom::bindings::codegen::Bindings::WorkerBinding;
|
||||
use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods;
|
||||
|
@ -26,6 +26,7 @@ use ipc_channel::ipc;
|
|||
use js::jsapi::{HandleValue, JSContext, JSAutoCompartment};
|
||||
use js::jsval::UndefinedValue;
|
||||
use script_thread::Runnable;
|
||||
use script_traits::WorkerScriptLoadOrigin;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -81,21 +82,28 @@ impl Worker {
|
|||
let worker_load_origin = WorkerScriptLoadOrigin {
|
||||
referrer_url: None,
|
||||
referrer_policy: None,
|
||||
request_source: global.request_source(),
|
||||
pipeline_id: Some(global.pipeline())
|
||||
};
|
||||
|
||||
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
|
||||
let worker_id = global.get_next_worker_id();
|
||||
if let Some(ref chan) = global.devtools_chan() {
|
||||
let pipeline_id = global.pipeline();
|
||||
let title = format!("Worker for {}", worker_url);
|
||||
let page_info = DevtoolsPageInfo {
|
||||
title: title,
|
||||
url: worker_url.clone(),
|
||||
};
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)),
|
||||
devtools_sender.clone(),
|
||||
page_info));
|
||||
}
|
||||
|
||||
let init = prepare_workerscope_init(global,
|
||||
"Worker".to_owned(),
|
||||
worker_url.clone(),
|
||||
devtools_sender.clone(),
|
||||
closing);
|
||||
let init = prepare_workerscope_init(global, Some(devtools_sender));
|
||||
|
||||
DedicatedWorkerGlobalScope::run_worker_scope(
|
||||
init, worker_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref,
|
||||
global.script_chan(), sender, receiver, worker_load_origin);
|
||||
global.script_chan(), sender, receiver, worker_load_origin, closing);
|
||||
|
||||
Ok(worker)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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 devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId, DevtoolsPageInfo};
|
||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
||||
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
|
||||
use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
|
||||
use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception};
|
||||
|
@ -19,18 +19,18 @@ use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
|||
use dom::window::{base64_atob, base64_btoa};
|
||||
use dom::workerlocation::WorkerLocation;
|
||||
use dom::workernavigator::WorkerNavigator;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use js::jsapi::{HandleValue, JSContext, JSRuntime};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::{PipelineId, ReferrerPolicy, PanicMsg};
|
||||
use net_traits::{LoadContext, ResourceThreads, load_whole_resource};
|
||||
use net_traits::{RequestSource, LoadOrigin, CustomResponseSender, IpcSend};
|
||||
use net_traits::{LoadOrigin, IpcSend};
|
||||
use profile_traits::{mem, time};
|
||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, maybe_take_panic_result};
|
||||
use script_thread::RunnableWrapper;
|
||||
use script_traits::ScriptMsg as ConstellationMsg;
|
||||
use script_traits::WorkerGlobalScopeInit;
|
||||
use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource};
|
||||
use std::cell::Cell;
|
||||
use std::default::Default;
|
||||
|
@ -48,52 +48,19 @@ pub enum WorkerGlobalScopeTypeId {
|
|||
DedicatedWorkerGlobalScope,
|
||||
}
|
||||
|
||||
pub struct WorkerGlobalScopeInit {
|
||||
pub resource_threads: ResourceThreads,
|
||||
pub mem_profiler_chan: mem::ProfilerChan,
|
||||
pub time_profiler_chan: time::ProfilerChan,
|
||||
pub to_devtools_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||
pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
|
||||
pub constellation_chan: IpcSender<ConstellationMsg>,
|
||||
pub scheduler_chan: IpcSender<TimerEventRequest>,
|
||||
pub panic_chan: IpcSender<PanicMsg>,
|
||||
pub worker_id: WorkerId,
|
||||
pub closing: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
pub fn prepare_workerscope_init(global: GlobalRef,
|
||||
worker_type: String,
|
||||
worker_url: Url,
|
||||
devtools_sender: IpcSender<DevtoolScriptControlMsg>,
|
||||
closing: Arc<AtomicBool>) -> WorkerGlobalScopeInit {
|
||||
devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>) -> WorkerGlobalScopeInit {
|
||||
let worker_id = global.get_next_worker_id();
|
||||
let optional_sender = match global.devtools_chan() {
|
||||
Some(ref chan) => {
|
||||
let pipeline_id = global.pipeline();
|
||||
let title = format!("{} for {}", worker_type, worker_url);
|
||||
let page_info = DevtoolsPageInfo {
|
||||
title: title,
|
||||
url: worker_url,
|
||||
};
|
||||
chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)),
|
||||
devtools_sender.clone(),
|
||||
page_info)).unwrap();
|
||||
Some(devtools_sender)
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let init = WorkerGlobalScopeInit {
|
||||
resource_threads: global.resource_threads(),
|
||||
mem_profiler_chan: global.mem_profiler_chan().clone(),
|
||||
to_devtools_sender: global.devtools_chan(),
|
||||
time_profiler_chan: global.time_profiler_chan().clone(),
|
||||
from_devtools_sender: optional_sender,
|
||||
from_devtools_sender: devtools_sender,
|
||||
constellation_chan: global.constellation_chan().clone(),
|
||||
panic_chan: global.panic_chan().clone(),
|
||||
scheduler_chan: global.scheduler_chan().clone(),
|
||||
worker_id: worker_id,
|
||||
closing: closing,
|
||||
worker_id: worker_id
|
||||
};
|
||||
|
||||
init
|
||||
|
@ -105,7 +72,7 @@ pub struct WorkerGlobalScope {
|
|||
eventtarget: EventTarget,
|
||||
worker_id: WorkerId,
|
||||
worker_url: Url,
|
||||
closing: Arc<AtomicBool>,
|
||||
closing: Option<Arc<AtomicBool>>,
|
||||
#[ignore_heap_size_of = "Defined in js"]
|
||||
runtime: Runtime,
|
||||
next_worker_id: Cell<WorkerId>,
|
||||
|
@ -146,12 +113,6 @@ pub struct WorkerGlobalScope {
|
|||
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
panic_chan: IpcSender<PanicMsg>,
|
||||
|
||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||
custom_msg_chan: IpcSender<CustomResponseSender>,
|
||||
|
||||
#[ignore_heap_size_of = "Defined in std"]
|
||||
custom_msg_port: Receiver<CustomResponseSender>,
|
||||
}
|
||||
|
||||
impl WorkerGlobalScope {
|
||||
|
@ -159,16 +120,15 @@ impl WorkerGlobalScope {
|
|||
worker_url: Url,
|
||||
runtime: Runtime,
|
||||
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
|
||||
timer_event_chan: IpcSender<TimerEvent>)
|
||||
timer_event_chan: IpcSender<TimerEvent>,
|
||||
closing: Option<Arc<AtomicBool>>)
|
||||
-> WorkerGlobalScope {
|
||||
let (msg_chan, msg_port) = ipc::channel().unwrap();
|
||||
let custom_msg_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(msg_port);
|
||||
WorkerGlobalScope {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
next_worker_id: Cell::new(WorkerId(0)),
|
||||
worker_id: init.worker_id,
|
||||
worker_url: worker_url,
|
||||
closing: init.closing,
|
||||
closing: closing,
|
||||
runtime: runtime,
|
||||
resource_threads: init.resource_threads,
|
||||
location: Default::default(),
|
||||
|
@ -185,8 +145,6 @@ impl WorkerGlobalScope {
|
|||
constellation_chan: init.constellation_chan,
|
||||
scheduler_chan: init.scheduler_chan,
|
||||
panic_chan: init.panic_chan,
|
||||
custom_msg_chan: msg_chan,
|
||||
custom_msg_port: custom_msg_port
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,16 +194,12 @@ impl WorkerGlobalScope {
|
|||
self.runtime.cx()
|
||||
}
|
||||
|
||||
pub fn custom_message_chan(&self) -> IpcSender<CustomResponseSender> {
|
||||
self.custom_msg_chan.clone()
|
||||
}
|
||||
|
||||
pub fn custom_message_port(&self) -> &Receiver<CustomResponseSender> {
|
||||
&self.custom_msg_port
|
||||
}
|
||||
|
||||
pub fn is_closing(&self) -> bool {
|
||||
self.closing.load(Ordering::SeqCst)
|
||||
if let Some(ref closing) = self.closing {
|
||||
closing.load(Ordering::SeqCst)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resource_threads(&self) -> &ResourceThreads {
|
||||
|
@ -273,7 +227,7 @@ impl WorkerGlobalScope {
|
|||
|
||||
pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
|
||||
RunnableWrapper {
|
||||
cancelled: self.closing.clone(),
|
||||
cancelled: self.closing.clone().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,9 +239,6 @@ impl LoadOrigin for WorkerGlobalScope {
|
|||
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
|
||||
None
|
||||
}
|
||||
fn request_source(&self) -> RequestSource {
|
||||
RequestSource::None
|
||||
}
|
||||
fn pipeline_id(&self) -> Option<PipelineId> {
|
||||
Some(self.pipeline())
|
||||
}
|
||||
|
@ -451,13 +402,10 @@ impl WorkerGlobalScope {
|
|||
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
|
||||
let dedicated =
|
||||
self.downcast::<DedicatedWorkerGlobalScope>();
|
||||
let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
|
||||
if let Some(dedicated) = dedicated {
|
||||
return dedicated.script_chan();
|
||||
} else if let Some(service_worker) = service_worker {
|
||||
return service_worker.script_chan();
|
||||
} else {
|
||||
panic!("need to implement a sender for SharedWorker")
|
||||
panic!("need to implement a sender for SharedWorker/ServiceWorker")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,13 +427,10 @@ impl WorkerGlobalScope {
|
|||
|
||||
pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
|
||||
let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
|
||||
let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
|
||||
if let Some(dedicated) = dedicated {
|
||||
return dedicated.new_script_pair();
|
||||
} else if let Some(service_worker) = service_worker {
|
||||
return service_worker.new_script_pair();
|
||||
} else {
|
||||
panic!("need to implement a sender for SharedWorker")
|
||||
panic!("need to implement a sender for SharedWorker/ServiceWorker")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ use net_traits::CoreResourceMsg::Fetch;
|
|||
use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
|
||||
use net_traits::trim_http_whitespace;
|
||||
use net_traits::{CoreResourceThread, LoadOrigin};
|
||||
use net_traits::{FetchResponseListener, Metadata, NetworkError, RequestSource};
|
||||
use net_traits::{FetchResponseListener, Metadata, NetworkError};
|
||||
use network_listener::{NetworkListener, PreInvoke};
|
||||
use parse::html::{ParseContext, parse_html};
|
||||
use parse::xml::{self, parse_xml};
|
||||
|
@ -274,13 +274,6 @@ impl LoadOrigin for XMLHttpRequest {
|
|||
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
|
||||
return self.referrer_policy;
|
||||
}
|
||||
fn request_source(&self) -> RequestSource {
|
||||
if self.sync.get() {
|
||||
RequestSource::None
|
||||
} else {
|
||||
self.global().r().request_source()
|
||||
}
|
||||
}
|
||||
fn pipeline_id(&self) -> Option<PipelineId> {
|
||||
let global = self.global();
|
||||
Some(global.r().pipeline())
|
||||
|
|
|
@ -106,6 +106,7 @@ pub mod parse;
|
|||
pub mod script_runtime;
|
||||
#[allow(unsafe_code)]
|
||||
pub mod script_thread;
|
||||
mod serviceworker_manager;
|
||||
mod task_source;
|
||||
pub mod textinput;
|
||||
mod timers;
|
||||
|
@ -113,7 +114,10 @@ mod unpremultiplytable;
|
|||
mod webdriver_handlers;
|
||||
|
||||
use dom::bindings::codegen::RegisterBindings;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use js::jsapi::{Handle, JSContext, JSObject, SetDOMProxyInformation};
|
||||
use script_traits::SWManagerMsg;
|
||||
use serviceworker_manager::ServiceWorkerManager;
|
||||
use std::ptr;
|
||||
use util::opts;
|
||||
|
||||
|
@ -159,11 +163,14 @@ fn perform_platform_specific_initialization() {
|
|||
fn perform_platform_specific_initialization() {}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn init() {
|
||||
pub fn init(from_swmanager_sender: IpcSender<SWManagerMsg>) {
|
||||
unsafe {
|
||||
SetDOMProxyInformation(ptr::null(), 0, Some(script_thread::shadow_check_callback));
|
||||
}
|
||||
|
||||
// Spawn the service worker manager passing the constellation sender
|
||||
ServiceWorkerManager::spawn_manager(from_swmanager_sender);
|
||||
|
||||
// Create the global vtables used by the (generated) DOM
|
||||
// bindings to implement JS proxies.
|
||||
RegisterBindings::RegisterProxyHandlers();
|
||||
|
|
|
@ -65,12 +65,11 @@ use js::jsval::UndefinedValue;
|
|||
use js::rust::Runtime;
|
||||
use mem::heap_size_of_self_and_children;
|
||||
use msg::constellation_msg::{FrameType, LoadData, PanicMsg, PipelineId, PipelineNamespace};
|
||||
use msg::constellation_msg::{ReferrerPolicy, SubpageId, WindowSizeType};
|
||||
use net_traits::LoadData as NetLoadData;
|
||||
use msg::constellation_msg::{SubpageId, WindowSizeType, ReferrerPolicy};
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||
use net_traits::{AsyncResponseTarget, CoreResourceMsg, LoadConsumer, LoadContext, Metadata, ResourceThreads};
|
||||
use net_traits::{RequestSource, CustomResponse, CustomResponseSender, IpcSend};
|
||||
use net_traits::{IpcSend, LoadData as NetLoadData};
|
||||
use network_listener::NetworkListener;
|
||||
use parse::ParserRoot;
|
||||
use parse::html::{ParseContext, parse_html};
|
||||
|
@ -216,8 +215,7 @@ enum MixedMessage {
|
|||
FromScript(MainThreadScriptMsg),
|
||||
FromDevtools(DevtoolScriptControlMsg),
|
||||
FromImageCache(ImageCacheResult),
|
||||
FromScheduler(TimerEvent),
|
||||
FromNetwork(IpcSender<Option<CustomResponse>>),
|
||||
FromScheduler(TimerEvent)
|
||||
}
|
||||
|
||||
/// Messages used to control the script event loop
|
||||
|
@ -342,12 +340,6 @@ pub struct ScriptThread {
|
|||
/// events in the event queue.
|
||||
chan: MainThreadScriptChan,
|
||||
|
||||
/// A handle to network event messages
|
||||
custom_message_chan: IpcSender<CustomResponseSender>,
|
||||
|
||||
/// The port which receives a sender from the network
|
||||
custom_message_port: Receiver<CustomResponseSender>,
|
||||
|
||||
dom_manipulation_task_source: DOMManipulationTaskSource,
|
||||
|
||||
user_interaction_task_source: UserInteractionTaskSource,
|
||||
|
@ -509,10 +501,10 @@ impl ScriptThread {
|
|||
}
|
||||
|
||||
// stores a service worker registration
|
||||
pub fn set_registration(scope_url: Url, registration:&ServiceWorkerRegistration) {
|
||||
pub fn set_registration(scope_url: Url, registration:&ServiceWorkerRegistration, pipeline_id: PipelineId) {
|
||||
SCRIPT_THREAD_ROOT.with(|root| {
|
||||
let script_thread = unsafe { &*root.get().unwrap() };
|
||||
script_thread.handle_serviceworker_registration(scope_url, registration);
|
||||
script_thread.handle_serviceworker_registration(scope_url, registration, pipeline_id);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -562,9 +554,6 @@ impl ScriptThread {
|
|||
let (ipc_devtools_sender, ipc_devtools_receiver) = ipc::channel().unwrap();
|
||||
let devtools_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_devtools_receiver);
|
||||
|
||||
let (ipc_custom_resp_chan, ipc_custom_resp_port) = ipc::channel().unwrap();
|
||||
let custom_msg_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_custom_resp_port);
|
||||
|
||||
// Ask the router to proxy IPC messages from the image cache thread to us.
|
||||
let (ipc_image_cache_channel, ipc_image_cache_port) = ipc::channel().unwrap();
|
||||
let image_cache_port =
|
||||
|
@ -590,8 +579,6 @@ impl ScriptThread {
|
|||
bluetooth_thread: state.bluetooth_thread,
|
||||
|
||||
port: port,
|
||||
custom_message_chan: ipc_custom_resp_chan,
|
||||
custom_message_port: custom_msg_port,
|
||||
|
||||
chan: MainThreadScriptChan(chan.clone()),
|
||||
dom_manipulation_task_source: DOMManipulationTaskSource(chan.clone()),
|
||||
|
@ -653,7 +640,7 @@ impl ScriptThread {
|
|||
/// Handle incoming control messages.
|
||||
fn handle_msgs(&self) -> bool {
|
||||
use self::MixedMessage::{FromConstellation, FromDevtools, FromImageCache};
|
||||
use self::MixedMessage::{FromScheduler, FromScript, FromNetwork};
|
||||
use self::MixedMessage::{FromScheduler, FromScript};
|
||||
|
||||
// Handle pending resize events.
|
||||
// Gather them first to avoid a double mut borrow on self.
|
||||
|
@ -687,7 +674,6 @@ impl ScriptThread {
|
|||
let mut timer_event_port = sel.handle(&self.timer_event_port);
|
||||
let mut devtools_port = sel.handle(&self.devtools_port);
|
||||
let mut image_cache_port = sel.handle(&self.image_cache_port);
|
||||
let mut custom_message_port = sel.handle(&self.custom_message_port);
|
||||
unsafe {
|
||||
script_port.add();
|
||||
control_port.add();
|
||||
|
@ -696,7 +682,6 @@ impl ScriptThread {
|
|||
devtools_port.add();
|
||||
}
|
||||
image_cache_port.add();
|
||||
custom_message_port.add();
|
||||
}
|
||||
let ret = sel.wait();
|
||||
if ret == script_port.id() {
|
||||
|
@ -709,8 +694,6 @@ impl ScriptThread {
|
|||
FromDevtools(self.devtools_port.recv().unwrap())
|
||||
} else if ret == image_cache_port.id() {
|
||||
FromImageCache(self.image_cache_port.recv().unwrap())
|
||||
} else if ret == custom_message_port.id() {
|
||||
FromNetwork(self.custom_message_port.recv().unwrap())
|
||||
} else {
|
||||
panic!("unexpected select result")
|
||||
}
|
||||
|
@ -778,10 +761,7 @@ impl ScriptThread {
|
|||
Err(_) => match self.timer_event_port.try_recv() {
|
||||
Err(_) => match self.devtools_port.try_recv() {
|
||||
Err(_) => match self.image_cache_port.try_recv() {
|
||||
Err(_) => match self.custom_message_port.try_recv() {
|
||||
Err(_) => break,
|
||||
Ok(ev) => event = FromNetwork(ev)
|
||||
},
|
||||
Err(_) => break,
|
||||
Ok(ev) => event = FromImageCache(ev),
|
||||
},
|
||||
Ok(ev) => event = FromDevtools(ev),
|
||||
|
@ -807,7 +787,6 @@ impl ScriptThread {
|
|||
},
|
||||
FromConstellation(inner_msg) => self.handle_msg_from_constellation(inner_msg),
|
||||
FromScript(inner_msg) => self.handle_msg_from_script(inner_msg),
|
||||
FromNetwork(inner_msg) => self.handle_msg_from_network(inner_msg),
|
||||
FromScheduler(inner_msg) => self.handle_timer_event(inner_msg),
|
||||
FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg),
|
||||
FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg),
|
||||
|
@ -866,8 +845,7 @@ impl ScriptThread {
|
|||
_ => ScriptThreadEventCategory::ScriptEvent
|
||||
}
|
||||
},
|
||||
MixedMessage::FromScheduler(_) => ScriptThreadEventCategory::TimerEvent,
|
||||
MixedMessage::FromNetwork(_) => ScriptThreadEventCategory::NetworkEvent
|
||||
MixedMessage::FromScheduler(_) => ScriptThreadEventCategory::TimerEvent
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1056,12 +1034,6 @@ impl ScriptThread {
|
|||
msg.responder.unwrap().respond(msg.image_response);
|
||||
}
|
||||
|
||||
fn handle_msg_from_network(&self, msg: IpcSender<Option<CustomResponse>>) {
|
||||
// We may detect controlling service workers here
|
||||
// We send None as default
|
||||
let _ = msg.send(None);
|
||||
}
|
||||
|
||||
fn handle_webdriver_msg(&self, pipeline_id: PipelineId, msg: WebDriverScriptCommand) {
|
||||
let context = self.root_browsing_context();
|
||||
match msg {
|
||||
|
@ -1457,8 +1429,33 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_serviceworker_registration(&self, scope: Url, registration: &ServiceWorkerRegistration) {
|
||||
self.registration_map.borrow_mut().insert(scope, JS::from_ref(registration));
|
||||
fn handle_serviceworker_registration(&self,
|
||||
scope: Url,
|
||||
registration: &ServiceWorkerRegistration,
|
||||
pipeline_id: PipelineId) {
|
||||
{
|
||||
let ref mut reg_ref = *self.registration_map.borrow_mut();
|
||||
// according to spec we should replace if an older registration exists for
|
||||
// same scope otherwise just insert the new one
|
||||
let _ = reg_ref.remove(&scope);
|
||||
reg_ref.insert(scope.clone(), JS::from_ref(registration));
|
||||
}
|
||||
|
||||
// send ScopeThings to sw-manager
|
||||
let ref maybe_registration_ref = *self.registration_map.borrow();
|
||||
let maybe_registration = match maybe_registration_ref.get(&scope) {
|
||||
Some(r) => r,
|
||||
None => return
|
||||
};
|
||||
if let Some(context) = self.root_browsing_context().find(pipeline_id) {
|
||||
let window = context.active_window();
|
||||
let global_ref = GlobalRef::Window(window.r());
|
||||
let script_url = maybe_registration.get_installed().get_script_url();
|
||||
let scope_things = ServiceWorkerRegistration::create_scope_things(global_ref, script_url);
|
||||
let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope));
|
||||
} else {
|
||||
warn!("Registration failed for {}", pipeline_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles a request for the window title.
|
||||
|
@ -1601,7 +1598,6 @@ impl ScriptThread {
|
|||
HistoryTraversalTaskSource(history_sender.clone()),
|
||||
self.file_reading_task_source.clone(),
|
||||
self.image_cache_channel.clone(),
|
||||
self.custom_message_chan.clone(),
|
||||
self.image_cache_thread.clone(),
|
||||
self.resource_threads.clone(),
|
||||
self.bluetooth_thread.clone(),
|
||||
|
@ -2112,8 +2108,7 @@ impl ScriptThread {
|
|||
pipeline_id: Some(id),
|
||||
credentials_flag: true,
|
||||
referrer_policy: load_data.referrer_policy,
|
||||
referrer_url: load_data.referrer_url,
|
||||
source: RequestSource::Window(self.custom_message_chan.clone())
|
||||
referrer_url: load_data.referrer_url
|
||||
}, LoadConsumer::Listener(response_target), None)).unwrap();
|
||||
|
||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||
|
|
123
components/script/serviceworker_manager.rs
Normal file
123
components/script/serviceworker_manager.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* 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/. */
|
||||
|
||||
//! The service worker manager persists the descriptor of any registered service workers.
|
||||
//! It also stores an active workers map, which holds descriptors of running service workers.
|
||||
//! If an active service worker timeouts, then it removes the descriptor entry from its
|
||||
//! active_workers map
|
||||
|
||||
use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
|
||||
use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||
use dom::serviceworkerregistration::longest_prefix_match;
|
||||
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
||||
use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::mpsc::channel;
|
||||
use url::Url;
|
||||
use util::thread::spawn_named;
|
||||
|
||||
pub struct ServiceWorkerManager {
|
||||
// map of registered service worker descriptors
|
||||
registered_workers: HashMap<Url, ScopeThings>,
|
||||
// map of active service worker descriptors
|
||||
active_workers: HashMap<Url, ScopeThings>,
|
||||
// own sender to send messages here
|
||||
own_sender: IpcSender<ServiceWorkerMsg>,
|
||||
// receiver to receive messages from constellation
|
||||
own_port: IpcReceiver<ServiceWorkerMsg>,
|
||||
}
|
||||
|
||||
impl ServiceWorkerManager {
|
||||
fn new(own_sender: IpcSender<ServiceWorkerMsg>,
|
||||
from_constellation_receiver: IpcReceiver<ServiceWorkerMsg>) -> ServiceWorkerManager {
|
||||
ServiceWorkerManager {
|
||||
registered_workers: HashMap::new(),
|
||||
active_workers: HashMap::new(),
|
||||
own_sender: own_sender,
|
||||
own_port: from_constellation_receiver
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_manager(from_swmanager_sender: IpcSender<SWManagerMsg>) {
|
||||
let (own_sender, from_constellation_receiver) = ipc::channel().unwrap();
|
||||
from_swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone())).unwrap();
|
||||
spawn_named("ServiceWorkerManager".to_owned(), move || {
|
||||
ServiceWorkerManager::new(own_sender, from_constellation_receiver).start();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn prepare_activation(&mut self, load_url: &Url) {
|
||||
let mut scope_url = None;
|
||||
for scope in self.registered_workers.keys() {
|
||||
if longest_prefix_match(&scope, load_url) {
|
||||
scope_url = Some(scope.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref scope_url) = scope_url {
|
||||
if self.active_workers.contains_key(&scope_url) {
|
||||
// do not run the same worker if already active.
|
||||
warn!("Service worker for {:?} already active", scope_url);
|
||||
return;
|
||||
}
|
||||
let scope_things = self.registered_workers.get(&scope_url);
|
||||
if let Some(scope_things) = scope_things {
|
||||
let (sender, receiver) = channel();
|
||||
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
|
||||
if let Some(ref chan) = scope_things.devtools_chan {
|
||||
let title = format!("ServiceWorker for {}", scope_things.script_url);
|
||||
let page_info = DevtoolsPageInfo {
|
||||
title: title,
|
||||
url: scope_things.script_url.clone(),
|
||||
};
|
||||
let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((scope_things.pipeline_id,
|
||||
Some(scope_things.worker_id)),
|
||||
devtools_sender.clone(),
|
||||
page_info));
|
||||
};
|
||||
ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
|
||||
sender,
|
||||
receiver,
|
||||
devtools_receiver,
|
||||
self.own_sender.clone(),
|
||||
scope_url.clone());
|
||||
// store the worker in active_workers map
|
||||
self.active_workers.insert(scope_url.clone(), scope_things.clone());
|
||||
} else {
|
||||
warn!("Unable to activate service worker");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
while let Ok(msg) = self.own_port.recv() {
|
||||
match msg {
|
||||
ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope) => {
|
||||
if self.registered_workers.contains_key(&scope) {
|
||||
warn!("ScopeThings for {:?} already stored in SW-Manager", scope);
|
||||
} else {
|
||||
self.registered_workers.insert(scope, scope_things);
|
||||
}
|
||||
}
|
||||
ServiceWorkerMsg::Timeout(scope) => {
|
||||
if self.active_workers.contains_key(&scope) {
|
||||
let _ = self.active_workers.remove(&scope);
|
||||
} else {
|
||||
warn!("ScopeThings for {:?} is not active", scope);
|
||||
}
|
||||
}
|
||||
ServiceWorkerMsg::ActivateWorker(mediator) => {
|
||||
self.prepare_activation(&mediator.load_url);
|
||||
// TODO XXXcreativcoder this net_sender will need to be send to the appropriate service worker
|
||||
// so that it may do the sending of custom responses.
|
||||
// For now we just send a None from here itself
|
||||
let _ = mediator.response_chan.send(None);
|
||||
|
||||
}
|
||||
ServiceWorkerMsg::Exit => break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue