aboutsummaryrefslogtreecommitdiff
path: root/files/es/conflicting/web/api/push_api/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/es/conflicting/web/api/push_api/index.html')
-rw-r--r--files/es/conflicting/web/api/push_api/index.html434
1 files changed, 0 insertions, 434 deletions
diff --git a/files/es/conflicting/web/api/push_api/index.html b/files/es/conflicting/web/api/push_api/index.html
deleted file mode 100644
index ea87d50427..0000000000
--- a/files/es/conflicting/web/api/push_api/index.html
+++ /dev/null
@@ -1,434 +0,0 @@
----
-title: Usando la API Push
-slug: conflicting/Web/API/Push_API
-translation_of: Web/API/Push_API
-translation_of_original: Web/API/Push_API/Using_the_Push_API
-original_slug: Web/API/Push_API/Using_the_Push_API
----
-<p class="summary"><span class="seoSummary">La W3C <a href="/en-US/docs/Web/API/Push_API">Push API</a> offers some exciting new functionality for developers to use in web applications: this article provides an introduction to getting Push notifications setup and running, with a simple demo.</span></p>
-
-<p>La habilidad de enviar mensajes o notificaciones de un servidor a un cliente en cualquier momento —si la aplicación está activa en su sitema o no—es algo que ha sido disfrutado por las plataformas nativas durante algún tiempo, y esta finalmente llega a la web! el soporte para muchos push está ahora disponible en Firefox 43+ y Chrome 42+ en escritorio, esperamos seguir pronto con las plataformas moviles. {{domxref("PushMessageData")}} actualmente solo es soportada experimentalmente en Firefox (44+), y la implementación está sujeta a cambios.</p>
-
-<div class="note">
-<p><strong>Note</strong>: Early versions of Firefox OS used a proprietary version of this API called <a href="/en-US/docs/Web/API/Simple_Push_API">Simple Push</a>. This is being rendered obsolete by the Push API standard.</p>
-</div>
-
-<h2 id="Demo_las_bases_de_una_simple_app_de_servidor_de_chat">Demo: las bases de una simple app de servidor de chat</h2>
-
-<p>La demo que hemos creado proporciona los principios de una simple app de chat. Esta presenta un formulario para que ingreses un identificador de chat y un boton que al presionar se suscriba a los mensajes push.</p>
-
-<p>En este punto, el nombre de los nuevos suscriptores aparecerá en la lista de suscriptores, junto con un campo de texto y un botón de envío para permitir al suscriptor enviar mensajes.</p>
-
-<p>At this point, the new subscriber's name will appear in the subscriber's list, along with a text field and submit button to allow the subscriber to send messages.</p>
-
-<p><img alt="" src="https://mdn.mozillademos.org/files/11823/push-api-demo.png" style="border: 1px solid black; display: block; height: 406px; margin: 0px auto; width: 705px;"></p>
-
-<p>Para correr la demo, siga las instrucciones de <a href="https://github.com/chrisdavidmills/push-api-demo">push-api-demo README</a>. Tenga en cuenta que el componente server-side aún nesecita un poco de trabajo para que funcione en chrome y se ejecute de una manera más rezonable. Pero los aspectos de push pueden ser explicados a fondo; Nos sumergiremos en ella después de revisar las tecnologías en juego.</p>
-
-<h2 id="Visión_de_la_tecnología">Visión de la tecnología</h2>
-
-<p>Esta sección proporciona un esquema de qué tecnologías están involucradas en este ejemplo.</p>
-
-<p>Los mensajes web push hacen parte de la familia tecnológica <a href="/en-US/docs/Web/API/Service_Worker_API">service workers</a>; en particular, se requiere que un service worker esté activo en la página para recibir mensajes push. el service worker recibe el mensaje push, y acontinuación depende de usted cómo notificar a la página. Usted puede:</p>
-
-<p>Web Push messages are part of the <a href="/en-US/docs/Web/API/Service_Worker_API">service workers</a> technology family; in particular, a service worker is required to be active on the page for it to receive push messages. The service worker receives the push message, and then it is up to you how to then notify the page. You can:</p>
-
-<ul>
- <li>Enviar una <a href="/en-US/docs/Web/API/Notifications_API">notificación web</a> emergente para alertar al usuario. Esto requiere que sean concedidos los permisos para enviar el mensaje push.</li>
- <li>Envía un mensaje a la página principal a través de un  {{domxref("MessageChannel")}}.</li>
-</ul>
-
-<p>A menudo una combinación de los dos será necesario; La demo a continuación muestra un ejemplo de cada uno.</p>
-
-<div class="note">
-<p><strong>Nota</strong>: Usted necesita algún tipo de código que se ejecute en el servidor para manejar el cifrado de punto final/datos y enviar las solicitudes de notificaciones push. En nuestra demostración hemos creado un servidor  quick-and-dirty usando <a href="https://nodejs.org/">NodeJS</a>.</p>
-</div>
-
-<p>El service worker también tiene que suscribirse al servicio de mensajería psuh. Cada sesión recibe su propio punto final único cuando se suscribe al servicio de mensajería. Este punto final es obtenido desde la propiedad  ({{domxref("PushSubscription.endpoint")}}) en el objeto de suscripción. Este punto final se puede enviar a su servidor y se utiliza para enviar un mensaje al service worker asctivo en esta sesión. Cada navegador tiene su propio servidor de mensajería push para manejar el envío del mensaje push.</p>
-
-<h3 id="Encryption">Encryption</h3>
-
-<div class="note">
-<p><strong>Note</strong>: For an interactive walkthrough, try JR Conlin's <a href="https://jrconlin.github.io/WebPushDataTestPage/">Web Push Data Encryption Test Page</a>.</p>
-</div>
-
-<p>To send data via a push message, it needs to be encrypted. This requires a public key created using the {{domxref("PushSubscription.getKey()")}} method, which relies upon some complex encryption mechanisms that are run server-side; read <a href="https://tools.ietf.org/html/draft-ietf-webpush-encryption-01">Message Encryption for Web Push</a> for more details. As time goes on, libraries will appear to handle key generation and encryption/decryption of push messages; for this demo we used Marco Castelluccio's NodeJS <a href="https://github.com/marco-c/web-push">web-push library</a>.</p>
-
-<div class="note">
-<p><strong>Note</strong>: There is also another library to handle the encryption with a Node and Python version available, see <a href="https://github.com/martinthomson/encrypted-content-encoding">encrypted-content-encoding</a>.</p>
-</div>
-
-<h3 id="Push_workflow_summary">Push workflow summary</h3>
-
-<p>To summarize, here is what is needed to implement push messaging. You can find more details about specific parts of the demo code in subsequent sections.</p>
-
-<ol>
- <li>Request permission for web notifications, or anything else you are using that requires permissions.</li>
- <li>Register a service worker to control the page by calling {{domxref("ServiceWorkerContainer.register()")}}.</li>
- <li>Subscribe to the push messaging service using {{domxref("PushManager.subscribe()")}}.</li>
- <li>Retrieve the endpoint associated with the subscription and generate a client public key ({{domxref("PushSubscription.endpoint")}} and {{domxref("PushSubscription.getKey()")}}. Note that <code>getKey()</code> is currently experimental and Firefox only.)</li>
- <li>Send these details to the server so it can send push message when required. This demo uses {{domxref("XMLHttpRequest")}}, but you could use <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a>.</li>
- <li>If you are using the <a href="/en-US/docs/Web/API/Channel_Messaging_API">Channel Messaging API</a> to comunicate with the service worker, set up a new message channel ({{domxref("MessageChannel.MessageChannel()")}}) and send <code>port2</code> over to the service worker by calling {{domxref("Worker.postMessage()")}} on the service worker, in order to open up the communication channel. You should also set up a listener to respond to messages sent back from the service worker.</li>
- <li>On the server side, store the endpoint and any other required details so they are available when a push message needs to be sent to a push subscriber (we are using a simple text file, but you could use a database or whatever you like). In a production app, make sure you keep these details hidden, so malicious parties can't steal endpoints and spam subscribers with push messages.</li>
- <li>To send a push message, you need to send an HTTP <code>POST</code> to the endpoint URL. The request must include a <code>TTL</code> header that limits how long the message should be queued if the user is not online. To include payload data in your request, you must encrypt it (which involves the client public key). In our demo, we are using the <a href="https://github.com/marco-c/web-push">web-push</a> module, which handles all the hard work for you.</li>
- <li>Over in your service worker, set up a <code>push</code> event handler to respond to push messages being received.
- <ol>
- <li>If you want to respond by sending a channel message back to the main context (see Step 6) you need to first get a reference to the <code>port2</code> we sent over to the service worker context ({{domxref("MessagePort")}}). This is available on the {{domxref("MessageEvent")}} object passed to the <code>onmessage</code> handler ({{domxref("ServiceWorkerGlobalScope.onmessage")}}). Specifically, this is found in the <code>ports</code> property, index 0. Once this is done, you can send a message back to <code>port1</code>, using {{domxref("MessagePort.postMessage()")}}.</li>
- <li>If you want to respond by firing a system notification, you can do this by calling {{domxref("ServiceWorkerRegistration.showNotification()")}}. Note that in our code we have run this inside an {{domxref("ExtendableEvent.waitUntil()")}} method — this extends the lifetime of the event until after the notification has been fired, so we can make sure everything has happened that we want to happen.<span id="cke_bm_307E" class="hidden"> </span></li>
- </ol>
- </li>
-</ol>
-
-<h2 id="Construyendo_la_demo">Construyendo la demo</h2>
-
-<p>Vamos a ensayar el código para esta demo, podemos empezar a entender como trabaja todo esto.</p>
-
-<ul>
- <li>
- <h3 id="HTML_y_CSS">HTML y CSS</h3>
- </li>
-</ul>
-
-<p>No hay nada destacalbe sobre el HTML y el CSS para la demo; el HTML inicialmente contiene un simple formulario que permite introducir un udentificador para la sala de chat, un boton que al hacer click se suscribe a las notificaciones push, y dos listas con los suscriptores y los mensajes. Una vez suscrito, aparecerán controles adicionales para permitir al usuario actual escribir mensajes en el chat.</p>
-
-<p>El CSS ha sido muy minimo para no desvirtuar la explicación de la funcionalidad Push Api.</p>
-
-<ul>
- <li>
- <h3 id="El_archivo_JavaScript_principal">El archivo JavaScript principal</h3>
- </li>
-</ul>
-
-<p>El JavaScript es obviamente más sustancial. Echemos un vistazo al archivo JavaScript principal.</p>
-
-<h4 id="Variables_y_configuración_inicial">Variables y configuración inicial</h4>
-
-<p>Para iniciar, nosotros declaramos algunas variables a usar en nuestra app:</p>
-
-<pre class="brush: js">var isPushEnabled = false;
-var useNotifications = false;
-
-var subBtn = document.querySelector('.subscribe');
-var sendBtn;
-var sendInput;
-
-var controlsBlock = document.querySelector('.controls');
-var subscribersList = document.querySelector('.subscribers ul');
-var messagesList = document.querySelector('.messages ul');
-
-var nameForm = document.querySelector('#form');
-var nameInput = document.querySelector('#name-input');
-nameForm.onsubmit = function(e) {
- e.preventDefault()
-};
-nameInput.value = 'Bob';</pre>
-
-<p>Primero, tenemos dos boleanos para hacer un seguimiento si se a suscrito a push, y si ha permitido las notificaciones.</p>
-
-<p>A continuación, tomamos una referencia al suscrito/no-suscrito <code>{{htmlelement("button")}}</code>, y se declaran variables para almacenar referencias a nuestro mensaje enviado boton/entrada (sólo se crean cuando la suscripsión es correcta.)</p>
-
-<p>Las siguientes variables toman referencia a los trés elementos principales <code>{{htmlelement("div")}}</code> en el diseño, por lo que podemos insertar elementos en ellos (por ejemplo cuando aparezca el botón <em>envíar el mensaje de chat</em> o el mensaje de chat aparezca en la lista de <em>mensajes</em>.)</p>
-
-<p>Finalmente tomamos referencia a nuestro formulario de selección de nombre y el elemento <code>{{htmlelement("input")}},</code> damos a la entrada un valor por defecto, y usamos <code><a href="/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code> para detener el envío del formulario cuando este es enviado pulsando return.</p>
-
-<p>A continuación, pedimos permiso para enviar las notificaciones web, usando <code>{{domxref("Notification.requestPermission","requestPermission()")}}</code>:</p>
-
-<pre class="brush: js">Notification.requestPermission();</pre>
-
-<p>Ahora ejecutamos una sección de código cuando se dispara el <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onload">onload</a></code>, para empezar el proceso de inicialización de la app cuando se carga pro primera vez. En primer lugar añadimos un detector de eventos de clik al botón  Sucribirse/unsubscribe que ejecuta nuestra funcion <code>unsubscribe()</code> si actualmente estamos suscritos (<code>isPushEnabled</code> is <code>true</code>), y <code>subscribe()</code> de la otra manera:</p>
-
-<pre class="brush: js">window.addEventListener('load', function() {
- subBtn.addEventListener('click', function() {
- if (isPushEnabled) {
- unsubscribe();
- } else {
- subscribe();
- }
- });</pre>
-
-<p>A continuación verificamos el service worked es soportado. Si es así, registramos un service worker usando <code>{{domxref("ServiceWorkerContainer.register()")}}</code>, y ejecutando nuestra función <code>initialiseState()</code>. Si no es así, entregamos un mensaje de error a la consola.</p>
-
-<pre class="brush: js"> // Check that service workers are supported, if so, progressively
- // enhance and add push messaging support, otherwise continue without it.
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.register('sw.js').then(function(reg) {
- if(reg.installing) {
- console.log('Service worker installing');
- } else if(reg.waiting) {
- console.log('Service worker installed');
- } else if(reg.active) {
- console.log('Service worker active');
- }
-
- initialiseState(reg);
- });
- } else {
- console.log('Service workers aren\'t supported in this browser.');
- }
-});
-</pre>
-
-<p>La siguiente cosa en el código es la función <code>initialiseState()</code> — para el codigo completo comentado, mira en <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/main.js"><code>initialiseState()</code> source on Github</a> (no lo estamos repitiendo aquí por brevedad.)</p>
-
-<p><code>initialiseState()</code> primero comprueba si las notificaciones son soportadas en los service workers, entonces establece la variable  <code>useNotifications</code> a verdadero. A continuación comprueba si dichas notificaciones están permitidas por el usuario y si los mensajes push están soportados, y reacciona deacuerdo a cada uno.</p>
-
-<p>Finalmente, se usa <code>{{domxref("ServiceWorkerContainer.ready()")}}</code> para esperar a que el service worker esté activo y listo para hacer las cosas. Una vez se revuelva el promise, recuperamos nuestra suscripsión para enviar los mensajes push usando la propiedad <code>{{domxref("ServiceWorkerRegistration.pushManager")}}</code>, que devuelve un objeto <code>{{domxref("PushManager")}}</code> cuando llamamos a <code>{{domxref("PushManager.getSubscription()")}}</code>. Una vez la segunda promesa interna se resuelva, habilitamos el botón subscribe/unsubscribe (<code>subBtn.disabled = false;</code>), y verificamos que tenemos un objeto suscripsión para trabajar.</p>
-
-<p>Si lo hacemos, entonces ya estamos suscritos. Esto es posible cuando la app no está abierta en el navegador; el service worker aun puede ser activado en segundo plano. si estamos suscritos, actualizamos la UI para mostrar que estamos suscritos por la actualizacion del label en el botón, entonces establecemos <code>isPushEnabled</code> to <code>true</code>, toma el punto final de suscripsión desde <code>{{domxref("PushSubscription.endpoint")}}</code>, genera una public key usando <code>{{domxref("PushSubscription.getKey()")}}</code>, y ejecutando nuestra función <code>updateStatus()</code>, que como verá más adelante se comunica con el servidor.</p>
-
-<p>Como un bonus añadido, configuramos un nuevo <code>{{domxref("MessageChannel")}}</code> usando el constructor <code>{{domxref("MessageChannel.MessageChannel()")}}</code>, toma una referencia al service worker activo usando <code>{{domxref("ServiceworkerRegistration.active")}}</code>, luego configure un canal entre el contexto principal del navegador y el contexto del service worker usando <code>{{domxref("Worker.postMessage()")}}</code>. El contexto del navegador recive mensajes en <code>{{domxref("MessageChannel.port1")}}</code>; Cuando esto suceda, ejecutamos la función <code>handleChannelMessage()</code> para decidir que hacer con esos datos (mirar la sección <code>{{anch("Handling channel messages sent from the service worker")}}</code> ).</p>
-
-<h4 id="Subscribing_and_unsubscribing">Subscribing and unsubscribing</h4>
-
-<p>Ahora regresamos la atención a las funciones <code>subscribe()</code> y <code>unsubscribe()</code> usadas para subscribe/unsubscribe al servicion de notificaciones push.</p>
-
-<p>In the case of subscription, we again check that our service worker is active and ready by calling {{domxref("ServiceWorkerContainer.ready()")}}. When the promise resolves, we subscribe to the service using {{domxref("PushManager.subscribe()")}}. If the subscription is successful, we get a {{domxref("PushSubscription")}} object, extract the subscription endpoint from this and generate a public key (again, {{domxref("PushSubscription.endpoint")}} and {{domxref("PushSubscription.getKey()")}}), and pass them to our <code>updateStatus()</code> function along with the update type (<code>subscribe</code>) to send the necessary details to the server.</p>
-
-<p>We also make the necessary updates to the app state (set <code>isPushEnabled</code> to <code>true</code>) and UI (enable the subscribe/unsubscribe button and set its label text to show that the next time it is pressed it will unsubscribe.)</p>
-
-<p>The <code>unsubscribe()</code> function is pretty similar in structure, but it basically does the opposite; the most notable difference is that it gets the current subscription using {{domxref("PushManager.getSubscription()")}}, and when that promise resolves it unsubscribes using {{domxref("PushSubscription.unsubscribe()")}}.</p>
-
-<p>Appropriate error handling is also provided in both functions.  </p>
-
-<p>We only show the <code>subscribe()</code> code below, for brevity; see the full <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/main.js">subscribe/unsubscribe code on Github</a>.</p>
-
-<pre class="brush: js">function subscribe() {
- // Disable the button so it can't be changed while
- // we process the permission request
-
- subBtn.disabled = true;
-
- navigator.serviceWorker.ready.then(function(reg) {
- reg.pushManager.subscribe({userVisibleOnly: true})
- .then(function(subscription) {
- // The subscription was successful
- isPushEnabled = true;
- subBtn.textContent = 'Unsubscribe from Push Messaging';
- subBtn.disabled = false;
-
- // Update status to subscribe current user on server, and to let
- // other users know this user has subscribed
- var endpoint = subscription.endpoint;
- var key = subscription.getKey('p256dh');
- updateStatus(endpoint,key,'subscribe');
- })
- .catch(function(e) {
- if (Notification.permission === 'denied') {
- // The user denied the notification permission which
- // means we failed to subscribe and the user will need
- // to manually change the notification permission to
- // subscribe to push messages
- console.log('Permission for Notifications was denied');
-
- } else {
- // A problem occurred with the subscription, this can
- // often be down to an issue or lack of the gcm_sender_id
- // and / or gcm_user_visible_only
- console.log('Unable to subscribe to push.', e);
- subBtn.disabled = false;
- subBtn.textContent = 'Subscribe to Push Messaging';
- }
- });
- });
-}</pre>
-
-<h4 id="Updating_the_status_in_the_app_and_server">Updating the status in the app and server</h4>
-
-<p>The next function in our main JavaScript is <code>updateStatus()</code>, which updates the UI for sending chat messages when subscribing/unsubscribing and sends a request to update this information on the server.</p>
-
-<p>The function does one of three different things, depending on the value of the <code>statusType</code> parameter passed into it:</p>
-
-<ul>
- <li><code>subscribe</code>: The button and text input for sending chat messages are created and inserted into the UI, and an object is sent to the server via XHR containing the status type (<code>subscribe</code>), username of the subscriber, subscription endpoint, and client public key.</li>
- <li><code>unsubscribe</code>: This basically works in the opposite way to subscribe — the chat UI elements are removed, and an object is sent to the server to tell it that the user has unsubscribed.</li>
- <li><code>init</code>: This is run when the app is first loaded/initialised — it creates the chat UI elements, and sends an object to the server to tell it that which user has reinitialised (reloaded.)</li>
-</ul>
-
-<p>Again, we have not included the entire function listing for brevity. Examine the <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/main.js">full <code>updateStatus()</code> code on Github</a>.</p>
-
-<h4 id="Handling_channel_messages_sent_from_the_service_worker">Handling channel messages sent from the service worker</h4>
-
-<p>As mentioned earlier, when a <a href="/en-US/docs/Web/API/Channel_Messaging_API">channel message</a> is received from the service worker, our <code>handleChannelMessage()</code> function is called to handle it. This is done by our handler for the {{event("message")}} event, {{domxref("channel.port1.onmessage")}}:</p>
-
-<pre class="brush: js">channel.port1.onmessage = function(e) {
- handleChannelMessage(e.data);
-}</pre>
-
-<p>This occurs when the <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/sw.js#L8">service worker sends a channel message over</a>.</p>
-
-<p>The <code>handleChannelMessage()</code> function looks like this:</p>
-
-<pre class="brush: js">function handleChannelMessage(data) {
- if(data.action === 'subscribe' || data.action === 'init') {
- var listItem = document.createElement('li');
- listItem.textContent = data.name;
- subscribersList.appendChild(listItem);
- } else if(data.action === 'unsubscribe') {
- for(i = 0; i &lt; subscribersList.children.length; i++) {
- if(subscribersList.children[i].textContent === data.name) {
- subscribersList.children[i].parentNode.removeChild(subscribersList.children[i]);
- }
- }
- nameInput.disabled = false;
- } else if(data.action === 'chatMsg') {
- var listItem = document.createElement('li');
- listItem.textContent = data.name + ": " + data.msg;
- messagesList.appendChild(listItem);
- sendInput.value = '';
- }
-}</pre>
-
-<p>What happens here depends on what the <code>action</code> property on the <code>data</code> object is set to:</p>
-
-<ul>
- <li><code>subscribe</code> or <code>init</code> (at both startup and restart, we need to do the same thing in this sample): An {{htmlelement("li")}} element is created, its text content is set to <code>data.name</code> (the name of the subscriber), and it is appended to the subscribers list (a simple {{htmlelement("ul")}} element) so there is visual feedback that a subscriber has (re)joined the chat.</li>
- <li><code>unsubscribe</code>: We loop through the children of the subscribers list, find the one whose text content is equal to <code>data.name</code> (the name of the unsubscriber), and delete that node to provide visual feedback that someone has unsubscribed.</li>
- <li><code>chatMsg</code>: In a similar manner to the first case, an {{htmlelement("li")}} element is created, its text content is set to <code>data.name + ": " + data.msg</code> (so for example "Chris: This is my message"), and it is appended to the chat messages list; this is how the chat messages appear on the UI for each user.</li>
-</ul>
-
-<div class="note">
-<p><strong>Note</strong>: We have to pass the data back to the main context before we do DOM updates because service workers don't have access to the DOM. You should be aware of the limitations of service workers before attemping to ue them. Read <a href="/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">Using Service Workers</a> for more details.</p>
-</div>
-
-<h4 id="Sending_chat_messages">Sending chat messages</h4>
-
-<p>When the <em>Send Chat Message</em> button is clicked, the content of the associated text field is sent as a chat message. This is handled by the <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/main.js"><code>sendChatMessage()</code> function</a> (again, not shown in full for brevity). This works in a similar way to the different parts of the <code>updateStatus()</code> function (see {{anch("Updating the status in the app and server")}}) — we retrieve an endpoint and public key via a {{domxref("PushSubscription")}} object, which is itself retrieved via {{domxref("ServiceWorkerContainer.ready()")}} and {{domxref("PushManager.subscribe()")}}. These are sent to the server via {{domxref("XMLHttpRequest")}} in a message object, along with the name of the subscribed user, the chat message to send, and a <code>statusType</code> of <code>chatMsg</code>.</p>
-
-<h3 id="The_server">The server</h3>
-
-<p>As mentioned above, we need a server-side component in our app, to handle storing subscription details, and send out push messages when updates occur. We've hacked together a quick-and-dirty server using <a href="http://nodejs.org/">NodeJS</a> (<code><a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/server.js">server.js</a></code>), which handles the XHR requests sent by our client-side JavaScript code.</p>
-
-<p>It uses a text file (<code><a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/endpoint.txt">endpoint.txt</a></code>) to store subscription details; this file starts out empty. There are four different types of request, marked by the <code>statusType</code> property of the object sent over in the request; these are the same as those understood client-side, and perform the required server actions for that same situation. Here's what each means in the context of the server:</p>
-
-<ul>
- <li><code>subscribe</code>: The server adds the new subscriber's details into the subscription data store (<code><a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/endpoint.txt">endpoint.txt</a></code>), including the endpoint, and then sends a push message to all the endpoints it has stored to tell each subscriber that someone new has joined the chat.</li>
- <li><code>unsubscribe</code>: The server finds the sending subscriber's details in the subscription store and removes it, then sends a push message to all remaining subscribers telling them the user has unsubscribed.</li>
- <li><code>init</code>: The server reads all the current subscribers from the text file, and sends each one a push message to tell them a user has initialized (rejoined) the chat.</li>
- <li><code>chatMsg</code>: Sent by a subscriber that wishes to deliver a message to all users; the server reads the list of all current subscribers from the subscription store file, then sends each one a push message containing the new chat message they should display.</li>
-</ul>
-
-<p>A couple more things to note:</p>
-
-<ul>
- <li>We are using the Node.js <a href="https://nodejs.org/api/https.html">https module</a> to create the server, because for security purposes, service workers only work on a secure connection. This is why we need to include the <code>.pfx</code> security cert in the app, and reference it when creating the server in the Node code.</li>
- <li>When you send a push message without data, you simply send it to the endpoint URL using an HTTP <code>POST</code> request. However, when the push message contains data, you need to encrypt it, which is quite a complex process. As time goes on, libraries will appear to do this kind of thing for you; for this demo we used Marco Castelluccio's NodeJS <a href="https://github.com/marco-c/web-push">web-push library</a>. Have a look at the source code to get more of an idea of how the encryption is done (and read <a href="https://tools.ietf.org/html/draft-ietf-webpush-encryption-01">Message Encryption for Web Push</a> for more details.) The library <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/server.js#L43-L46">makes sending a push message simple</a>.</li>
- <li>If you wish to have messages that collapse (newer updates will replace older updates), you can use the Topic feature. A topic is a special class of subscription update that has a <code>Topic</code> header. A topic name can be any URL safe, base64 string. For example, a header like "<code>Topic: MyFavoriteTopic-For2016</code>" is fine, but "<code>Topic: OMG! Kitties :)</code>" is not. Topic messages are collapsed when the subscriber is offline or unavailable. When they come back, they will receive only the lastest message per topic, along with whatever other messages are pending. "<a href="https://hacks.mozilla.org/2016/11/mozilla-push-server-now-supports-topics/">Mozilla Push Server now supports Topics</a>" on the Mozilla Hacks blog gives more details and examples.</li>
-</ul>
-
-<h3 id="The_service_worker">The service worker</h3>
-
-<p>Now let's have a look at the service worker code (<code><a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/sw.js">sw.js</a></code>), which responds to the push messages, represented by {{Event("push")}} events. These are handled on the service worker's scope by the ({{domxref("ServiceWorkerGlobalScope.onpush")}}) event handler; its job is to work out what to do in response to each received message. We first convert the received message back into an object by calling {{domxref("PushMessageData.json()")}}. Next, we check what type of push message it is, by looking at the object's <code>action</code> property:</p>
-
-<ul>
- <li><code>subscribe</code> or <code>unsubscribe</code>: We send a system notification via the <code>fireNotification()</code> function, but also send a message back to the main context on our {{domxref("MessageChannel")}} so we can update the subscriber list accordingly (see {{anch("Handling channel messages sent from the service worker")}} for more details).</li>
- <li><code>init</code> or <code>chatMsg</code>: We just send a channel message back to the main context to handle the <code>init</code> and <code>chatMsg</code> cases (these don't need a system notification).</li>
-</ul>
-
-<pre class="brush: js">self.addEventListener('push', function(event) {
- var obj = event.data.json();
-
- if(obj.action === 'subscribe' || obj.action === 'unsubscribe') {
- fireNotification(obj, event);
- port.postMessage(obj);
- } else if(obj.action === 'init' || obj.action === 'chatMsg') {
- port.postMessage(obj);
- }
-});</pre>
-
-<p>Next, let's look at the <code>fireNotification()</code> function (which is blissfully pretty simple).</p>
-
-<pre class="brush: js">function fireNotification(obj, event) {
- var title = 'Subscription change';
- var body = obj.name + ' has ' + obj.action + 'd.';
- var icon = 'push-icon.png';
- var tag = 'push';
-
- event.waitUntil(self.registration.showNotification(title, {
- body: body,
- icon: icon,
- tag: tag
- }));
-}</pre>
-
-<p>Here we assemble the assets needed by the notification box: the title, body, and icon. Then we send a notification via the {{domxref("ServiceWorkerRegistration.showNotification()")}} method, providing that information as well as the tag "push", which we can use to identify this notification among any other notifications we might be using. When the notification is successfully sent, it manifests as a system notification dialog on the users computers/devices in whatever style system notifications look like on those systems (the following image shows a Mac OSX system notification.)</p>
-
-<p><img alt="" src="https://mdn.mozillademos.org/files/11855/subscribe-notification.png" style="display: block; height: 65px; margin: 0px auto; width: 326px;"></p>
-
-<p>Note that we do this from inside an {{domxref("ExtendableEvent.waitUntil()")}} method; this is to make sure the service worker remains active until the notification has been sent. <code>waitUntil()</code> will extend the life cycle of the service worker until everything inside this method has completed.</p>
-
-<div class="note">
-<p><strong>Note</strong>: Web notifications from service workers were introduced around Firefox version 42, but are likely to be removed again while the surrounding functionality (such as <code>Clients.openWindow()</code>) is properly implemented (see {{bug(1203324)}} for more details.)</p>
-</div>
-
-<h2 id="Handling_premature_subscription_expiration">Handling premature subscription expiration</h2>
-
-<p>Sometimes push subscriptions expire prematurely, without {{domxref("PushSubscription.unsubscribe()")}} being called. This can happen when the server gets overloaded, or if you are offline for a long time, for example.  This is highly server-dependent, so the exact behavior is difficult to predict. In any case, you can handle this problem by watching for the {{Event("pushsubscriptionchange")}} event, which you can listen for by providing a {{domxref("ServiceWorkerGlobalScope.onpushsubscriptionchange")}} event handler; this event is fired only in this specific case.</p>
-
-<pre class="brush: js language-js"><code class="language-js">self<span class="punctuation token">.</span><span class="function token">addEventListener<span class="punctuation token">(</span></span><span class="string token">'pushsubscriptionchange'</span><span class="punctuation token">,</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
- <span class="comment token"> // do something, usually resubscribe to push and
-</span> <span class="comment token"> // send the new subscription details back to the
-</span> <span class="comment token"> // server via XHR or Fetch
-</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre>
-
-<p>Note that we don't cover this case in our demo, as a subscription ending is not a big deal for a simple chat server. But for a more complex example you'd probably want to resubscribe the user.</p>
-
-<h2 id="Extra_steps_for_Chrome_support">Extra steps for Chrome support</h2>
-
-<p>To get the app working on Chrome, we need a few extra steps, as Chrome currently relies on Google's Cloud Messaging service to work.</p>
-
-<h3 id="Setting_up_Google_Cloud_Messaging">Setting up Google Cloud Messaging</h3>
-
-<p>To get this set up, follow these steps:</p>
-
-<ol>
- <li>Navigate to the <a href="https://console.developers.google.com">Google Developers Console</a>  and set up a new project.</li>
- <li>Go to your project's homepage (ours is at <code>https://console.developers.google.com/project/push-project-978</code>, for example), then
- <ol>
- <li>Select the <em>Enable Google APIs for use in your apps</em> option.</li>
- <li>In the next screen, click <em>Cloud Messaging for Android</em> under the <em>Mobile APIs</em> section.</li>
- <li>Click the <em>Enable API</em> button.</li>
- </ol>
- </li>
- <li>Now you need to make a note of your project number and API key because you'll need them later. To find them:
- <ol>
- <li><strong>Project number</strong>: click <em>Home</em> on the left; the project number is clearly marked at the top of your project's home page.</li>
- <li><strong>API key</strong>: click <em>Credentials</em> on the left hand menu; the API key can be found on that screen.</li>
- </ol>
- </li>
-</ol>
-
-<h3 id="manifest.json">manifest.json</h3>
-
-<p>You need to include a Google app-style <code>manifest.json</code> file in your app, which references the project number you made a note of earlier in the <code>gcm_sender_id</code> parameter. Here is our simple example <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/manifest.json">manifest.json</a>:</p>
-
-<pre class="brush: js">{
- "name": "Push Demo",
- "short_name": "Push Demo",
- "icons": [{
- "src": "push-icon.png",
- "sizes": "111x111",
- "type": "image/png"
- }],
- "start_url": "/index.html",
- "display": "standalone",
- "gcm_sender_id": "224273183921"
-}</pre>
-
-<p>You also need to reference your manifest using a {{HTMLElement("link")}} element in your HTML:</p>
-
-<pre class="brush: html">&lt;link rel="manifest" href="manifest.json"&gt;</pre>
-
-<h3 id="userVisibleOnly">userVisibleOnly</h3>
-
-<p>Chrome requires you to set the <a href="/en-US/docs/Web/API/PushManager/subscribe#Parameters"><code>userVisibleOnly</code> parameter</a> to <code>true</code> when subscribing to the push service, which indicates that we are promising to show a notification whenever a push is received. This can be <a href="https://github.com/chrisdavidmills/push-api-demo/blob/gh-pages/main.js#L127">seen in action in our <code>subscribe()</code> function</a>.</p>
-
-<h2 id="See_also">See also</h2>
-
-<ul>
- <li><a href="/en-US/docs/Web/API/Push_API">Push API</a></li>
- <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a></li>
-</ul>
-
-<div class="note">
-<p><strong>Note</strong>: Some of the client-side code in our Push demo is heavily influenced by Matt Gaunt's excellent examples in <a href="http://updates.html5rocks.com/2015/03/push-notificatons-on-the-open-web">Push Notifications on the Open Web</a>. Thanks for the awesome work, Matt!</p>
-</div>