demos for spacedust

hello terrible terrible atproto hack

+100 -54
+29 -8
server/index.js
··· 49 49 50 50 const handleSubscribe = async (req, res) => { 51 51 const body = await getRequesBody(req); 52 - console.log('got body', body); 53 - doStuff(JSON.parse(body)); 52 + const { did, sub } = JSON.parse(body); 53 + doStuff(did, sub); 54 54 res.setHeader('Content-Type', 'application/json'); 55 55 res.writeHead(201); 56 56 res.end('{"oh": "hi"}'); 57 57 } 58 58 59 - const doStuff = sub => { 60 - let n = 0; 61 - setInterval(() => { 62 - webpush.sendNotification(sub, `oh hi: ${n}`); 63 - n += 1; 64 - }, 2000); 59 + const doStuff = (did, sub) => { 60 + console.log('subscribing for', did); 61 + const ws = new WebSocket(`wss://spacedust.microcosm.blue/subscribe?instant=true&wantedSubjectDids=${did}`); 62 + 63 + ws.addEventListener('message', event => { 64 + console.log('got', event.data); 65 + let data; 66 + try { 67 + data = JSON.parse(event.data); 68 + } catch (err) { 69 + console.error(err); 70 + return; 71 + } 72 + const { link: { source, source_record } } = data; 73 + const title = `new ${source}`; 74 + const body = `from ${source_record}`; 75 + webpush.sendNotification(sub, JSON.stringify({ title, body })); 76 + }); 77 + 78 + ws.addEventListener('error', err => { 79 + console.log('uh oh', err); 80 + }); 81 + 82 + ws.addEventListener('close', () => { 83 + console.log('closed. bye!'); 84 + }); 85 + 65 86 } 66 87 67 88 const requestListener = pubkey => (req, res) => {
+43 -12
server/web-content/index.html
··· 7 7 8 8 hiiiiii 9 9 10 + <label><input id="did" placeholder="did:plc:..." /> DID</label> 10 11 <button id="subscribe">subscribe</button> 11 12 12 13 <p id="error-message"></p> ··· 16 17 const err = m => { 17 18 document.getElementById('error-message').textContent = m; 18 19 throw new Error(m); 20 + }; 21 + const clearErr = () => { 22 + document.getElementById('error-message').textContent = ''; 19 23 }; 20 24 21 25 if (!('serviceWorker' in navigator)) err('service worker not supported'); ··· 86 90 } 87 91 88 92 document.getElementById('subscribe').addEventListener('click', async () => { 89 - const perm = await askPermission(); 90 - console.log({ perm }); 91 - const sub = await subscribeUserToPush(); 92 - console.log({ sub }); 93 - const res = await fetch('/subscribe', { 94 - method: 'POST', 95 - body: JSON.stringify(sub), 96 - headers: { 97 - 'Content-Type': 'application/json', 98 - }, 99 - }); 100 - console.log('res', res); 93 + clearErr(); 94 + 95 + const did = document.getElementById('did').value; 96 + if (!did.startsWith('did:')) err('should start with `did:`'); 97 + 98 + let perm; 99 + try { 100 + perm = await askPermission(); 101 + } catch (err) { 102 + console.error(err); 103 + err('notification permissions are needed to give you notifications'); 104 + } 105 + 106 + let sub; 107 + try { 108 + sub = await subscribeUserToPush(); 109 + } catch (err) { 110 + console.error(err); 111 + err('failed to subscribe for notification'); 112 + } 113 + 114 + let res; 115 + try { 116 + res = await fetch('/subscribe', { 117 + method: 'POST', 118 + body: JSON.stringify({ did, sub }), 119 + headers: { 120 + 'Content-Type': 'application/json', 121 + }, 122 + }); 123 + } catch (err) { 124 + console.error(err); 125 + err('failed to create subscription with backend'); 126 + } 127 + 128 + if (!res.ok) { 129 + console.error(await res.text()); 130 + err('not-ok response trying to create backend subscription'); 131 + } 101 132 }); 102 133 103 134 </script>
+28 -34
server/web-content/service-worker.js
··· 16 16 } 17 17 18 18 self.addEventListener('push', function(event) { 19 - console.log('Received a push message', event); 19 + const { title, body } = event.data.json(); 20 20 21 21 // Display notification or handle data 22 22 // Example: show a notification 23 - const title = 'New Notification'; 24 - const body = event.data.text(); 25 - const icon = '/images/icon.png'; 26 - const tag = 'simple-push-demo-notification-tag'; 23 + // const title = 'New Notification'; 24 + // const body = event.data.text(); 25 + // const icon = '/images/icon.png'; 26 + // const tag = 'simple-push-demo-notification-tag'; 27 27 28 - event.waitUntil( 29 - self.registration.showNotification(title, { 30 - body: body, 31 - icon: icon, 32 - tag: tag 33 - }) 34 - ); 28 + event.waitUntil(self.registration.showNotification(title, { body })); 35 29 36 30 // Attempt to resubscribe after receiving a notification 37 - event.waitUntil(resubscribeToPush()); 31 + // event.waitUntil(resubscribeToPush()); 38 32 }); 39 33 40 - function resubscribeToPush() { 41 - return self.registration.pushManager.getSubscription() 42 - .then(function(subscription) { 43 - if (subscription) { 44 - return subscription.unsubscribe(); 45 - } 46 - }) 47 - .then(function() { 48 - return self.registration.pushManager.subscribe({ 49 - userVisibleOnly: true, 50 - applicationServerKey: urlBase64ToUint8Array(PUBKEY) 51 - }); 52 - }) 53 - .then(function(subscription) { 54 - console.log('Resubscribed to push notifications:', subscription); 55 - // Optionally, send new subscription details to your server 56 - }) 57 - .catch(function(error) { 58 - console.error('Failed to resubscribe:', error); 59 - }); 60 - } 34 + // function resubscribeToPush() { 35 + // return self.registration.pushManager.getSubscription() 36 + // .then(function(subscription) { 37 + // if (subscription) { 38 + // return subscription.unsubscribe(); 39 + // } 40 + // }) 41 + // .then(function() { 42 + // return self.registration.pushManager.subscribe({ 43 + // userVisibleOnly: true, 44 + // applicationServerKey: urlBase64ToUint8Array(PUBKEY) 45 + // }); 46 + // }) 47 + // .then(function(subscription) { 48 + // console.log('Resubscribed to push notifications:', subscription); 49 + // // Optionally, send new subscription details to your server 50 + // }) 51 + // .catch(function(error) { 52 + // console.error('Failed to resubscribe:', error); 53 + // }); 54 + // }