servo: Merge #12910 - Implement postMessage for ServiceWorkers (from creativcoder:swsender); r=jdm

<!-- Please describe your changes on the following line: -->

Fixes #12773
r? @jdm

Changes:
* Implements `postMessage` on `ServiceWorker` object.
* Removes unused channels from sw and their scopes.
* Fixes a crash when calling `scope.script_chan()` in sw-scopes event handling.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #12773

<!-- Either: -->
- [X] There are tests for these changes at `tests/html/service-worker`

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: 0ec4ea4ee188f2e5db9d387d182c34a9d97d07cd
This commit is contained in:
Rahul Sharma 2016-09-15 08:34:22 -05:00
Родитель 3b64ccb98d
Коммит 4dc69a4645
19 изменённых файлов: 256 добавлений и 118 удалений

Просмотреть файл

@ -996,6 +996,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got store registration scope message");
self.handle_register_serviceworker(scope_things, scope);
}
FromScriptMsg::ForwardDOMMessage(msg_vec, scope_url) => {
if let Some(ref mgr) = self.swmanager_chan {
let _ = mgr.send(ServiceWorkerMsg::ForwardDOMMessage(msg_vec, scope_url));
} else {
warn!("Unable to forward DOMMessage for postMessage call");
}
}
}
}

Просмотреть файл

@ -12,11 +12,14 @@ use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_STRUCTURED_CLONE_VERSION};
use js::jsapi::{JS_ClearPendingException, JS_WriteStructuredClone};
use libc::size_t;
use std::ptr;
use std::slice;
/// A buffer for a structured clone.
pub struct StructuredCloneData {
data: *mut u64,
nbytes: size_t,
pub enum StructuredCloneData {
/// A non-serializable (default) variant
Struct(*mut u64, size_t),
/// A variant that can be serialized
Vector(Vec<u8>)
}
impl StructuredCloneData {
@ -39,26 +42,47 @@ impl StructuredCloneData {
}
return Err(Error::DataClone);
}
Ok(StructuredCloneData {
data: data,
nbytes: nbytes,
})
Ok(StructuredCloneData::Struct(data, nbytes))
}
/// Converts a StructuredCloneData to Vec<u8> for inter-thread sharing
pub fn move_to_arraybuffer(self) -> Vec<u8> {
match self {
StructuredCloneData::Struct(data, nbytes) => {
unsafe {
slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
}
}
StructuredCloneData::Vector(msg) => msg
}
}
/// Reads a structured clone.
///
/// Panics if `JS_ReadStructuredClone` fails.
pub fn read(self, global: GlobalRef, rval: MutableHandleValue) {
fn read_clone(global: GlobalRef, data: *mut u64, nbytes: size_t, rval: MutableHandleValue) {
unsafe {
assert!(JS_ReadStructuredClone(global.get_cx(),
self.data,
self.nbytes,
data,
nbytes,
JS_STRUCTURED_CLONE_VERSION,
rval,
ptr::null(),
ptr::null_mut()));
}
}
/// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
pub fn read(self, global: GlobalRef, rval: MutableHandleValue) {
match self {
StructuredCloneData::Vector(mut vec_msg) => {
let nbytes = vec_msg.len();
let data = vec_msg.as_mut_ptr() as *mut u64;
StructuredCloneData::read_clone(global, data, nbytes, rval);
}
StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
}
}
}
unsafe impl Send for StructuredCloneData {}

Просмотреть файл

@ -2,20 +2,23 @@
* 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::{SimpleWorkerErrorHandler, WorkerScriptMsg};
use dom::abstractworker::SimpleWorkerErrorHandler;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
use dom::bindings::error::{ErrorResult, Error};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::USVString;
use dom::bindings::structuredclone::StructuredCloneData;
use dom::eventtarget::EventTarget;
use js::jsapi::{HandleValue, JSContext};
use script_thread::Runnable;
use script_traits::{ScriptMsg, DOMMessage};
use std::cell::Cell;
use std::sync::mpsc::Sender;
use url::Url;
pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
@ -24,28 +27,31 @@ pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
pub struct ServiceWorker {
eventtarget: EventTarget,
script_url: DOMRefCell<String>,
scope_url: Url,
state: Cell<ServiceWorkerState>,
#[ignore_heap_size_of = "Defined in std"]
sender: Option<Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>>,
skip_waiting: Cell<bool>
}
impl ServiceWorker {
fn new_inherited(script_url: &str,
skip_waiting: bool) -> ServiceWorker {
skip_waiting: bool,
scope_url: Url) -> ServiceWorker {
ServiceWorker {
eventtarget: EventTarget::new_inherited(),
sender: None,
script_url: DOMRefCell::new(String::from(script_url)),
state: Cell::new(ServiceWorkerState::Installing),
scope_url: scope_url,
skip_waiting: Cell::new(skip_waiting)
}
}
pub fn new(global: GlobalRef,
script_url: &str,
pub fn install_serviceworker(global: GlobalRef,
script_url: Url,
scope_url: Url,
skip_waiting: bool) -> Root<ServiceWorker> {
reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting), global, Wrap)
reflect_dom_object(box ServiceWorker::new_inherited(script_url.as_str(),
skip_waiting,
scope_url), global, Wrap)
}
pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) {
@ -61,14 +67,6 @@ impl ServiceWorker {
pub fn get_script_url(&self) -> Url {
Url::parse(&self.script_url.borrow().clone()).unwrap()
}
pub fn install_serviceworker(global: GlobalRef,
script_url: Url,
skip_waiting: bool) -> Root<ServiceWorker> {
ServiceWorker::new(global,
script_url.as_str(),
skip_waiting)
}
}
impl ServiceWorkerMethods for ServiceWorker {
@ -82,6 +80,20 @@ impl ServiceWorkerMethods for ServiceWorker {
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 {
// Step 1
if let ServiceWorkerState::Redundant = self.state.get() {
return Err(Error::InvalidState);
}
// Step 7
let data = try!(StructuredCloneData::write(cx, message));
let msg_vec = DOMMessage(data.move_to_arraybuffer());
let _ = self.global().r().constellation_chan().send(ScriptMsg::ForwardDOMMessage(msg_vec,
self.scope_url.clone()));
Ok(())
}
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-onerror-attribute
event_handler!(error, GetOnerror, SetOnerror);

Просмотреть файл

@ -95,10 +95,9 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
return Err(Error::Type("Scope URL contains forbidden characters".to_owned()));
}
let scope_str = scope.as_str().to_owned();
let worker_registration = ServiceWorkerRegistration::new(self.global().r(),
script_url,
scope_str.clone(),
scope.clone(),
self);
ScriptThread::set_registration(scope, &*worker_registration, self.global().r().pipeline_id());
Ok(worker_registration)

Просмотреть файл

@ -5,7 +5,6 @@
use devtools;
use devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::WorkerScriptMsg;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
@ -16,7 +15,6 @@ use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
use dom::eventtarget::EventTarget;
use dom::messageevent::MessageEvent;
use dom::serviceworker::TrustedServiceWorkerAddress;
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
use ipc_channel::router::ROUTER;
@ -26,13 +24,12 @@ use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator};
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 std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
use std::thread;
use std::time::Duration;
use style::thread_state;
use style::thread_state::{IN_WORKER, SCRIPT};
use style::thread_state::{self, IN_WORKER, SCRIPT};
use url::Url;
use util::prefs::PREFS;
use util::thread::spawn_named;
@ -48,7 +45,26 @@ pub enum ServiceWorkerScriptMsg {
pub enum MixedMessage {
FromServiceWorker(ServiceWorkerScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
FromTimeoutThread(()),
FromTimeoutThread(())
}
#[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]
@ -61,12 +77,9 @@ pub struct ServiceWorkerGlobalScope {
own_sender: Sender<ServiceWorkerScriptMsg>,
#[ignore_heap_size_of = "Defined in std"]
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"]
swmanager_sender: IpcSender<ServiceWorkerMsg>,
#[ignore_heap_size_of = "Defined in std"]
scope_url: Url
scope_url: Url,
}
impl ServiceWorkerGlobalScope {
@ -93,7 +106,6 @@ impl ServiceWorkerGlobalScope {
receiver: receiver,
timer_event_port: timer_event_port,
own_sender: own_sender,
worker: DOMRefCell::new(None),
swmanager_sender: swmanager_sender,
scope_url: scope_url
}
@ -228,8 +240,7 @@ impl ServiceWorkerGlobalScope {
CommonWorker(WorkerScriptMsg::DOMMessage(data)) => {
let scope = self.upcast::<WorkerGlobalScope>();
let target = self.upcast();
let _ac = JSAutoCompartment::new(scope.get_cx(),
scope.reflector().get_jsobject().get());
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());
@ -292,6 +303,12 @@ impl ServiceWorkerGlobalScope {
pub fn process_event(&self, msg: CommonScriptMsg) {
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)]

Просмотреть файл

@ -25,21 +25,21 @@ pub struct ServiceWorkerRegistration {
}
impl ServiceWorkerRegistration {
fn new_inherited(active_sw: &ServiceWorker, scope: String) -> ServiceWorkerRegistration {
fn new_inherited(active_sw: &ServiceWorker, scope: Url) -> ServiceWorkerRegistration {
ServiceWorkerRegistration {
eventtarget: EventTarget::new_inherited(),
active: Some(JS::from_ref(active_sw)),
installing: None,
waiting: None,
scope: scope,
scope: scope.as_str().to_owned(),
}
}
#[allow(unrooted_must_root)]
pub fn new(global: GlobalRef,
script_url: Url,
scope: String,
scope: Url,
container: &Controllable) -> Root<ServiceWorkerRegistration> {
let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), true);
let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), scope.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)

Просмотреть файл

@ -7,7 +7,7 @@
interface ServiceWorker : EventTarget {
readonly attribute USVString scriptURL;
readonly attribute ServiceWorkerState state;
//[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
// event
attribute EventHandler onstatechange;

Просмотреть файл

@ -397,12 +397,14 @@ impl WorkerGlobalScope {
}
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
let dedicated =
self.downcast::<DedicatedWorkerGlobalScope>();
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/ServiceWorker")
panic!("need to implement a sender for SharedWorker")
}
}

Просмотреть файл

@ -1450,7 +1450,7 @@ impl ScriptThread {
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);
warn!("Registration failed for {}", scope);
}
}

Просмотреть файл

@ -8,12 +8,14 @@
//! active_workers map
use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
use dom::abstractworker::WorkerScriptMsg;
use dom::bindings::structuredclone::StructuredCloneData;
use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
use dom::serviceworkerregistration::longest_prefix_match;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use net_traits::{CustomResponseMediator, CoreResourceMsg};
use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders};
use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
use std::collections::HashMap;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use url::Url;
@ -29,7 +31,7 @@ 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>,
active_workers: HashMap<Url, Sender<ServiceWorkerScriptMsg>>,
// own sender to send messages here
own_sender: IpcSender<ServiceWorkerMsg>,
// receiver to receive messages from constellation
@ -59,56 +61,52 @@ impl ServiceWorkerManager {
let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan));
let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone()));
spawn_named("ServiceWorkerManager".to_owned(), move || {
ServiceWorkerManager::new(own_sender, from_constellation, resource_port).handle_message();
ServiceWorkerManager::new(own_sender,
from_constellation,
resource_port).handle_message();
});
}
pub fn prepare_activation(&mut self, load_url: &Url) -> Option<Sender<ServiceWorkerScriptMsg>> {
let mut scope_url = None;
pub fn get_matching_scope(&self, load_url: &Url) -> Option<Url> {
for scope in self.registered_workers.keys() {
if longest_prefix_match(&scope, load_url) {
scope_url = Some(scope.clone());
break;
}
}
if let Some(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 None;
}
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.clone(),
receiver,
devtools_receiver,
self.own_sender.clone(),
scope_url.clone());
// We store the activated worker
self.active_workers.insert(scope_url, scope_things.clone());
return Some(sender);
} else {
warn!("Unable to activate service worker");
return Some(scope.clone());
}
}
None
}
pub fn wakeup_serviceworker(&mut self, scope_url: Url) -> Option<Sender<ServiceWorkerScriptMsg>> {
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,
page_info));
};
ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(),
sender.clone(),
receiver,
devtools_receiver,
self.own_sender.clone(),
scope_url.clone());
// We store the activated worker
self.active_workers.insert(scope_url, sender.clone());
return Some(sender);
} else {
warn!("Unable to activate service worker");
None
}
}
fn handle_message(&mut self) {
while let Ok(message) = self.receive_message() {
let should_continue = match message {
@ -125,6 +123,12 @@ impl ServiceWorkerManager {
}
}
fn forward_message(&self, msg: DOMMessage, sender: &Sender<ServiceWorkerScriptMsg>) {
let DOMMessage(data) = msg;
let data = StructuredCloneData::Vector(data);
let _ = sender.send(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(data)));
}
fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool {
match msg {
ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope) => {
@ -139,7 +143,19 @@ impl ServiceWorkerManager {
if self.active_workers.contains_key(&scope) {
let _ = self.active_workers.remove(&scope);
} else {
warn!("ScopeThings for {:?} is not active", scope);
warn!("ServiceWorker for {:?} is not active", scope);
}
true
},
ServiceWorkerMsg::ForwardDOMMessage(msg, scope_url) => {
if self.active_workers.contains_key(&scope_url) {
if let Some(ref sender) = self.active_workers.get(&scope_url) {
self.forward_message(msg, &sender);
}
} else {
if let Some(ref sender) = self.wakeup_serviceworker(scope_url) {
self.forward_message(msg, &sender);
}
}
true
}
@ -147,12 +163,20 @@ impl ServiceWorkerManager {
}
}
#[inline]
fn handle_message_from_resource(&mut self, mediator: CustomResponseMediator) -> bool {
if serviceworker_enabled() {
let worker_sender = self.prepare_activation(&mediator.load_url);
if let Some(ref sender) = worker_sender {
let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator));
if let Some(scope) = self.get_matching_scope(&mediator.load_url) {
if self.active_workers.contains_key(&scope) {
if let Some(sender) = self.active_workers.get(&scope) {
let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator));
}
} else {
if let Some(sender) = self.wakeup_serviceworker(scope) {
let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator));
}
}
} else {
let _ = mediator.response_chan.send(None);
}
} else {
let _ = mediator.response_chan.send(None);

Просмотреть файл

@ -71,7 +71,7 @@ use util::ipc::OptionalOpaqueIpcSender;
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
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
/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
@ -212,7 +212,7 @@ pub enum ConstellationControlMsg {
/// Report an error from a CSS parser for the given pipeline
ReportCSSError(PipelineId, String, usize, usize, String),
/// Reload the given page.
Reload(PipelineId),
Reload(PipelineId)
}
impl fmt::Debug for ConstellationControlMsg {
@ -241,7 +241,7 @@ impl fmt::Debug for ConstellationControlMsg {
DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent",
FramedContentChanged(..) => "FramedContentChanged",
ReportCSSError(..) => "ReportCSSError",
Reload(..) => "Reload",
Reload(..) => "Reload"
})
}
}

Просмотреть файл

@ -136,6 +136,9 @@ pub enum ScriptMsg {
LogEntry(Option<PipelineId>, Option<String>, LogEntry),
/// Notifies the constellation that this pipeline has exited.
PipelineExited(PipelineId),
/// Send messages from postMessage calls from serviceworker
/// to constellation for storing in service worker manager
ForwardDOMMessage(DOMMessage, Url),
/// Store the data required to activate a service worker for the given scope
RegisterServiceWorker(ScopeThings, Url),
/// Requests that the compositor shut down.
@ -159,6 +162,10 @@ pub struct ScopeThings {
pub worker_id: WorkerId,
}
/// Message that gets passed to service worker scope on postMessage
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct DOMMessage(pub Vec<u8>);
/// Channels to allow service worker manager to communicate with constellation and resource thread
pub struct SWManagerSenders {
/// sender for communicating with constellation
@ -174,6 +181,8 @@ pub enum ServiceWorkerMsg {
RegisterServiceWorker(ScopeThings, Url),
/// Timeout message sent by active service workers
Timeout(Url),
/// Message sent by constellation to forward to a running service worker
ForwardDOMMessage(DOMMessage, Url),
/// Exit the service worker manager
Exit,
}
@ -182,5 +191,6 @@ pub enum ServiceWorkerMsg {
#[derive(Deserialize, Serialize)]
pub enum SWManagerMsg {
/// Provide the constellation with a means of communicating with the Service Worker Manager
OwnSender(IpcSender<ServiceWorkerMsg>),
OwnSender(IpcSender<ServiceWorkerMsg>)
}

Просмотреть файл

@ -8,6 +8,5 @@
<div>
<a href="http://github.com/servo/servo">Servo Project</a>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,3 @@
function test_importScripts() {
console.log('Hi from dummy.js');
}

Просмотреть файл

@ -1,7 +1,11 @@
self.addEventListener('activate', function(e) {
console.log("iframe service worker active");
console.log("iframe service worker active");
});
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(e.data.payload.msg + ' from '+ e.data.payload.worker_id);
})

Просмотреть файл

@ -16,36 +16,56 @@
<button onclick="register_zero()">Register for Root (/)</button>
<button onclick="register_one()">Register for Dashboard (/dashboard)</button>
<button onclick="register_two()">Register for Profile (/profile)</button>
<button onclick="post_message_root()">Msg to Root service worker</button>
</div>
<script>
var reg = navigator.serviceWorker.register('iframe_sw.js', { 'scope': '/demo_iframe.html' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
document.getElementById('iframe_sw').src = 'demo_iframe.html';
post_message('/demo_iframe');
function register_zero() {
var reg = navigator.serviceWorker.register('sw.js', { 'scope': './' });
var reg = navigator.serviceWorker.register('sw.js', { 'scope': './*' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
}
function post_message_root() {
// Testing repeated calls of postMessage
for(var i=0;i<100;i++){
navigator.serviceWorker.controller.postMessage({num:'Dummy message count: '+i});
}
}
function register_one() {
var reg = navigator.serviceWorker.register('sw_dashboard.js', { 'scope': '/dashboard' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
post_message('/dashboard');
}
function register_two() {
var reg = navigator.serviceWorker.register('sw_profile.js', { 'scope': '/profile' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
post_message('/profile');
}
navigator.serviceWorker.addEventListener('controllerchange', function(e) {
console.log("active Service Worker changed");
console.log("navigator.serviceWorker.controller changed");
});
function post_message(worker_id) {
navigator.serviceWorker.controller.postMessage({
payload:{
msg:'Hi there! This is a dummy message for testing of postMessage calls from Service Workers',
worker_id:worker_id
}
});
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,11 @@
self.addEventListener('activate', function(e) {
console.log('Root service worker active');
});
self.addEventListener('fetch', function(e) {
console.log("A fetch event detected by / service worker");
});
self.addEventListener('message', function(e) {
console.log(e.data.num);
})

Просмотреть файл

@ -1,9 +1,11 @@
importScripts('dashboard_helper.js');
self.addEventListener('activate', function(e) {
status_from_dashboard();
console.log('Dashboard service worker active');
});
self.addEventListener('fetch', function(e) {
console.log("A fetch event detected by /dashboard service worker");
});
console.log("A fetch event detected by /dashboard service worker");
});
self.addEventListener('message', function(e) {
console.log(e.data.payload.msg + ' from '+ e.data.payload.worker_id);
})

Просмотреть файл

@ -1,8 +1,12 @@
self.addEventListener('activate', function(e) {
console.log("profile service worker active");
console.log("profile service worker active");
});
self.addEventListener('fetch', function(e) {
console.log("A fetch event detected by /profile service worker");
});
console.log("A fetch event detected by /profile service worker");
});
self.addEventListener('message', function(e) {
console.log(e.data.payload.msg + ' from '+ e.data.payload.worker_id);
})