CINXE.COM
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="initial-scale=0.5, maximum-scale=1"> <link rel="shortcut icon" href="favicon.ico"> <title></title> <style> :root { --font-sans: "-apple-system", BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" } html, body, #sections { margin: 0; padding: 0; overflow: hidden } a { color: #44f !important; margin: 0 0.375rem; text-decoration: none } body { background: #f5f4f3; color: #444; font-family: var(--font-sans); height: 100vh; line-height: 1.5rem; text-align: center } h3 { font-weight: 400; margin: 0.125rem; text-transform: lowercase } p { margin: 0 } section { margin: 0; padding: 2rem 3rem } section:nth-child(odd) { background: #fff } section:nth-child(even) { background: #f9f8f7 } #container { display: flex; align-items: center; justify-content: center; height: 100% } #sections { border-radius: 0.25rem; margin-bottom: 15vh; max-width: 40rem; width: 100%; z-index: 2 } .dot { border-radius: 50%; z-index: 0 } /* https://gist.github.com/AnitaOlsen/c03d46d2c4f304259c1ce3520a4678f6 */ #bunny, #bunny div, .dot { position: absolute } #bunny { margin: auto; margin-top: 8%; opacity: 0; height: 7rem; width: 10rem; z-index: 1 } #bunny .head { top:16.5%; left: 25%; width: 48%; height: 70%; background: #fff; border-radius: 50% } #bunny .head-copy { width: 100%; height: 100%; background: #fff; border-radius: 50%; z-index: 2 } #bunny .ear-left { width: 20%; height: 50%; left: 6%; top: -30%; background: #fff; border-radius: 50%; transform: rotate(160deg); z-index: 1 } #bunny .ear-right { width: 20%; height: 50%; right: 6%; top: -30%; background: #fff; border-radius: 50%; transform: rotate(200deg); z-index: 1 } #bunny .inner-ear { border-radius: 50%; width: 73%; height: 80%; top: 10%; left: 14%; background: #f9bbc9 } #bunny .eye-left { background: pink; width: 13%; height: 20%; top: 37%; left: 27%; border-radius: 50%; transform: rotate(-20deg); z-index: 3 } #bunny .eye-right { background: pink; width: 13%; height: 20%; top: 37%; right: 25%; border-radius: 50%; transform: rotate(20deg); z-index: 3 } #bunny .pupil { width: 73%; height: 70%; top: 15%; left: 15%; border-radius: 50%; background: #cc7080 } #bunny .nose { background: #f9bbc9; width: 13%; height: 10%; left: 45%; top: 70%; border-radius: 50px; z-index: 4 } </style> </head> <body> <div id="container"> <div id="sections"></div> </div> <div id="bunny"> <div class="head"> <div class="head-copy"></div> <div class="ear-left"> <div class="inner-ear"></div> </div> <div class="ear-right"> <div class="inner-ear"></div> </div> <div class="eye-left"> <div class="pupil"></div> </div> <div class="eye-right"> <div class="pupil"></div> </div> <div class="nose"></div> </div> </div> <script> if (window.self !== window.top) { window.top.location.href = window.location.href; } // gateway check hash & test const CHECK_HASH = 'bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3m'; const CHECK_STRING = 'Hello from IPFS Gateway Checker'; // base domain for IPNS const DOMAIN = 'dotapps.io'; // default gateway const GATEWAY = 'https://ipfs.io'; // alternative IPNS-capable gateways, [name, host] const GATEWAYS = [ ['Crust', 'https://crustipfs.xyz'], ['Fleek', 'https://ipfs.fleek.co'], ['IPFS.io', 'https://ipfs.io'], ['Pinata', 'https://gateway.pinata.cloud'] ]; // timeout in seconds const TIMEOUT = 5; // creates a random dot for the background function createDot (color) { const dot = document.createElement('div'); const size = (Math.floor(4000 * Math.random()) / 1000) + 0.5; dot.classList.add('dot'); dot.style.top = `${(window.innerHeight * Math.random())}px`; dot.style.left = `${(window.innerWidth * Math.random())}px`; dot.style.height = `${size}em`; dot.style.width = `${size}em`; dot.style.backgroundColor = color; document.body.appendChild(dot); } // create a link tag function createLink (text, host, path) { const a = document.createElement('a'); a.appendChild(document.createTextNode(text)); a.href = `${host}/${path}`; return a; } function createSectionChildren (inner, children) { children.forEach((c) => inner.appendChild(c)); } // create a section with a title and links as <section><h3>...</h3><p>{children}</p></section> function createSection (sectionId, title, children) { const section = document.createElement('section'); const h = document.createElement('h3'); const inner = document.createElement('p'); createSectionChildren(inner, children); h.appendChild(document.createTextNode(title)); section.setAttribute('id', sectionId); section.appendChild(h); section.appendChild(inner); document.getElementById('sections').appendChild(section); return inner; } // parse the ?<chain> param, returning valid function getChain () { try { const query = decodeURI(window.location.search.substring(1)).trim(); if (query.length && query !== 'www') { return query; } } catch (error) { console.error(error); } return null; } // check a specific gateway for uptime async function checkGateway (host) { const start = Date.now(); try { // check the content of the hash on the supplied host const [isUp, hash] = await Promise.all([ fetch(`${host}/ipfs/${CHECK_HASH}`) .then((result) => result.text()) .then((text) => text.trim() === CHECK_STRING), fetch(`${host}/ipns/dotapps.io/ipfs/pin.json`) .then((result) => result.json()) .then((json) => json.IpfsHash) ]); return [isUp, Date.now() - start, hash]; } catch (error) { console.error(error); } return [false, 0, null]; } // lookup an ipfs hash based on the given ipns domain async function lookupHash (domain) { try { const { Path } = await fetch(`https://ipfs.io/api/v0/name/resolve?arg=${domain}`).then((result) => { if (result.status !== 200) { throw new Error(`Received status=${result.status} on lookup`); } return result.json(); }); return [Path, Path.replace('/ipfs/', '')]; } catch (error) { console.error(error); } return [null, null]; } // Redirect text display (single multiple places, extracted) function getRedirect (timeout) { return `Redirecting in ${timeout.toFixed(1)}s` } // Random background by tweaking the hue. Additionally it adjusts the link & border colors function changeBackground () { const style = document.createElement('style'); let hue = Math.floor(Math.random() * 359); document.head.appendChild(style); setInterval(() => { hue = (hue + 1) % 360; document.body.style.background = `hsl(${hue}, 45%, 85%)`; style.innerHTML = `a { color: hsl(${hue}, 45%, 45%) !important } section:nth-child(even) { background: hsl(${hue}, 45%, 95%) }`; createDot(`hsl(${hue}, 45%, 75%)`); }, 25); } // Sets up the redirect countdown timer function createRedirect (url) { const bunny = document.getElementById('bunny'); const h3 = document.getElementById('redirect').querySelector('h3'); let timeout = TIMEOUT * 10; let bunnyOpacity = 0; const bunnyInc = 0.925 / timeout; bunny.style.top = `${(window.innerHeight * Math.random())}px`; bunny.style.left = `${(window.innerWidth * Math.random())}px`; setInterval(() => { if (--timeout >= 0) { bunnyOpacity += bunnyInc; h3.textContent = getRedirect(timeout / 10); bunny.style.opacity = bunnyOpacity; if (timeout === 0) { window.location.href = url; } } }, 100); } // Creates the content function main () { const chain = getChain(); const ipns = `ipns/${chain ? `${chain}.` : ''}${DOMAIN}`; window.document.title = `Redirecting to ${ipns}`; createSection('redirect', getRedirect(TIMEOUT), [createLink(ipns, GATEWAY, ipns)]); const gateways = createSection('gateways', 'Available gateways', []); // loop through the gateways, adding them in order of appearance Promise .all( GATEWAYS.map(([title, host]) => checkGateway(host).then(([isUp, time, hash]) => [time, isUp, title, host, hash]) ) ) .then((all) => all .sort((a, b) => a[0] - b[0]) .forEach(([time, isUp, title, host, hash]) => { if (isUp && hash) { console.log(`Response from ${host} in ${time}ms with ${hash}`); createSectionChildren(gateways, [createLink(title, host, ipns)]); } else { console.log(`No response from ${host}`); } }) ); // lookup the hash and add a section for it lookupHash(DOMAIN).then(([path, hash]) => { if (path) { createSection('content', 'Link via content hash', [createLink(hash, GATEWAY, path)]); } }); createRedirect(`${GATEWAY}/${ipns}`); changeBackground(); } main(); </script> </body> </html>