A presentation at DjangoCon Europe 2019 in April 2019 in Copenhagen, Denmark by Aaron Bassett
HTTP/1.1 200 OK Content-Type: text/html; charset=iso-8859-1 Transfer-Encoding: chunked
HTTP/1.1 200 OK Content-Type: text/html; charset=iso-8859-1 Transfer-Encoding: chunked
33 <script> doSomething(); !</script> 33 <script> doSomething(); !</script> 33 <script> doSomething(); !</script>
33 <script> doSomething(); !</script> 33 <script> doSomething(); !</script> 33 <script> doSomething(); !</script>
(function poll() { new Ajax.Request(‘/api/’, { method: ‘get’, timeout: 60000, onSuccess: function() { !// Do something poll(); }, onFailure: function() { !// Do something else poll(); } }); }());
GET / HTTP/1.1 Host: 2019.djangocon.eu Connection: keep-alive Upgrade-insecure-requests: 1 Dnt: 1 User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/ webp,image/apng,/;q=0.8,application/signed-exchange;v=b3 Referer: https:!//!!www.google.com/ Accept-encoding: gzip, deflate, br Accept-language: en-GB,en;q=0.9,en-US;q=0.8
HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) Date: Wed, 10 Apr 2019 17:18:50 GMT Content-Type: text/html Last-Modified: Wed, 10 Apr 2019 12:14:03 GMT Connection: keep-alive ETag: W/”5cadde0b-4c01” Strict-Transport-Security: max-age=31536000; X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Content-Encoding: gzip
GET / HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: !!www.websocket.org
HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade
class CountConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = ??? self.room_group_name = ??? self.redis_client = redis.Redis(???) self.redis_client.incr(‘connections’) self.redis_client.set(‘updated’, time.time()) await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) await self.accept()
class CountConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = ??? self.room_group_name = ??? self.redis_client = redis.Redis(???) self.redis_client.incr(‘connections’) self.redis_client.set(‘updated’, time.time()) await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) await self.accept() class CountConsumer(AsyncWebsocketConsumer): async def connect(self):
class CountConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = ??? self.room_group_name = ??? self.redis_client = redis.Redis(???) self.redis_client.incr(‘connections’) self.redis_client.set(‘updated’, time.time()) await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) await self.accept() self.redis_client.incr(‘connections’) self.redis_client.set(‘updated’, time.time())
class CountConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_name = ??? self.room_group_name = ??? self.redis_client = redis.Redis(???) self.redis_client.incr(‘connections’) self.redis_client.set(‘updated’, time.time()) await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) await self.accept() await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } )
async def disconnect(self, close_code): self.redis_client = redis.Redis(???) self.redis_client.decr(‘connections’) await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } )
async def disconnect(self, close_code): self.redis_client = redis.Redis(???) self.redis_client.decr(‘connections’) await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) async def disconnect(self, close_code): self.redis_client = redis.Redis(???) self.redis_client.decr(‘connections’)
async def disconnect(self, close_code): self.redis_client = redis.Redis(???) self.redis_client.decr(‘connections’) await self.channel_layer.group_discard( self.room_group_name, self.channel_name ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } ) await self.channel_layer.group_send( self.room_group_name, { ‘type’: ‘connection_message’, ‘updated’: ???, ‘connections’: ??? } )
var chatSocket = new WebSocket(URL)
chatSocket.onmessage = function(e) { var data = JSON.parse(e.data) var totalConnections = data[‘connections’] var lastUpdated = data[‘updated’] document.querySelector(‘#count’).textContent = totalConnections document.querySelector(‘#updated’).textContent = lastUpdated }
chatSocket.onclose = function(e) { console.error(‘Chat socket closed unexpectedly’); }
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); };
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start();
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL);
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); };
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); };
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); };
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); };
const connections = []; var sharedWebSocket; onconnect = function(e) { const port = e.ports[0]; connections.push(port); port.start(); if (!sharedWebSocket) { sharedWebSocket = new WebSocket(URL); sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); }; } sharedWebSocket.send(“PING”); }; sharedWebSocket.onmessage = function(e) { connections.forEach(function(connection) { let data = JSON.parse(e.data); connection.postMessage(data); }); };
const worker = new SharedWorker(‘js/shared-worker.js’) worker.port.onmessage = function(e) { var data = e.data var totalConnections = data[‘connections’] var lastUpdated = data[‘updated’] document.querySelector(‘#count’).textContent = totalConnections document.querySelector(‘#updated’).textContent = lastUpdated } worker.port.start()
const worker = new SharedWorker(‘js/shared-worker.js’) worker.port.onmessage = function(e) { var data = e.data var totalConnections = data[‘connections’] var lastUpdated = data[‘updated’] document.querySelector(‘#count’).textContent = totalConnections document.querySelector(‘#updated’).textContent = lastUpdated } worker.port.start() const worker = new SharedWorker(‘js/shared-worker.js’)
const worker = new SharedWorker(‘js/shared-worker.js’) worker.port.onmessage = function(e) { var data = e.data var totalConnections = data[‘connections’] var lastUpdated = data[‘updated’] document.querySelector(‘#count’).textContent = totalConnections document.querySelector(‘#updated’).textContent = lastUpdated } worker.port.start() worker.port.onmessage = function(e) { var data = e.data var totalConnections = data[‘connections’] var lastUpdated = data[‘updated’] document.querySelector(‘#count’).textContent = totalConnections document.querySelector(‘#updated’).textContent = lastUpdated }