comparison default/static/websocket.js @ 84:b2ef34e602cf

base, js (websocket), css (main style): dynamic pages implementation, first draft: this patch introduces the browser part of dynamic pages. Dynamic pages work by establishing a websocket between server and the current page, if requested by server (which means that needed arguments are present in template). Once the connection is established, the server can, for now, reload the page, append HTML elements, or receive arbitrary data (without reloading the page, in opposition to data post). If connection can't be established, a popup will be displayed and connection will be retried many times after variable timeouts. The browser will finally give up and display an alert to client if the number of retries is too high (20 for now).
author Goffi <goffi@goffi.org>
date Wed, 03 Jan 2018 01:12:16 +0100
parents
children 27d6453a6209
comparison
equal deleted inserted replaced
83:caab77328b1c 84:b2ef34e602cf
1 /*
2 SàT templates: suit of templates for Salut à Toi
3 Copyright (C) 2017 Jérôme Poisson (goffi@goffi.org)
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /* websocket handler */
20
21
22 //TODO: retry websocket instead of reload
23 function WSHandler(url, token, debug=false) {
24 var socket = new WebSocket(url, 'libervia_page_' + token );
25 var retried = 0;
26
27 var errorHandler = function(error) {
28 if (retried > 20) {
29 console.error("Too many tries, can't start websocket");
30 alert("Dynamic connection with server can't be established, please try to reload this page in a while or contact your service administrator");
31 return;
32 }
33 var delay = Math.floor((Math.random() * 10) + 1) + 30 * Math.min(retried, 6);
34 notifyRetry(delay, function() {
35 retried++;
36 socket = new WebSocket(url, 'libervia_page_' + token );
37 socket.addEventListener('error', errorHandler);
38 });
39 };
40
41 socket.addEventListener('error', errorHandler);
42
43 if (debug) {
44 socket.addEventListener('message', function(event) {
45 console.log('WS in <== ', JSON.parse(event.data));
46 });
47 }
48
49 socket.addEventListener('message', function(event) {
50 try {data = JSON.parse(event.data);}
51 catch (e) {
52 console.warn('invalid websocket message received: %s', e);
53 return;
54 }
55 switch (data.type) {
56 case 'reload':
57 location.reload(true);
58 break;
59 case 'dom':
60 selected_element = document.body.querySelector(data.selectors);
61 switch (data.update_type) {
62 case 'append':
63 var template = document.createElement('template');
64 template.innerHTML = data.html;
65 new_element = template.content.firstChild;
66 selected_element.appendChild(new_element);
67 break;
68 default:
69 console.warn('Unknown DOM update type: %s', data.update_type);
70 }
71 break;
72 default:
73 console.warn('Unknown data type: %s', data.type);
74 }
75 });
76
77 socket.addEventListener('open', function (event) {
78 console.log('Websocket opened');
79 retried = 0;
80 }.bind(this));
81
82 this.send = function(data) {
83 if (debug) {
84 console.log('WS out ==> ', data);
85 }
86 socket.send(JSON.stringify(data));
87 };
88
89 function notifyRetry(timeout, retryCb) {
90 /* Show a notification dialog informing the user that server can't be reach
91 * and call retryCb after timeout seconds.
92 * A "retry now" link allows to retry immediately"
93 *
94 * @param timeout(int): delay before retrying, in seconds
95 * @param retryCb(function): function to call when retrying
96 */
97 var startTime = Date.now() / 1000;
98 var retryIntervalID;
99 var notif = document.createElement("div");
100 notif.setAttribute('class', 'notification retry');
101 //FIXME: we use English without translation for now, must be changed when we can use gettext in Libervia pages
102 notif.innerHTML = "<p>Can't reach the server, retrying in <span id='retry_counter'></span> seconds</p><p><a id='retry_now'>retry now</a></p>";
103 document.body.appendChild(notif);
104 var retryCounter = document.getElementById('retry_counter');
105 retryCounter.textContent = timeout;
106
107 var retry = function () {
108 clearInterval(retryIntervalID);
109 notif.parentNode.removeChild(notif);
110 retryCb();
111 };
112
113 var updateTimer = function () {
114 var elapsed = Math.floor(Date.now() / 1000 - startTime);
115 var remaining = timeout - elapsed;
116 if (remaining < 0) {
117 retry();
118 }
119 else {
120 retryCounter.textContent = remaining;
121 }
122 };
123
124 var retryNow = document.getElementById('retry_now');
125 retryNow.addEventListener('click', function(){
126 retry();
127 });
128
129 retryIntervalID = setInterval(updateTimer, 1000);
130 }
131 }