import { Logger } from 'besonders-logger' import { createSignal } from 'solid-js' import { getVMs } from '../data/VMs/MappedVMbase' import { ProviderVM } from '../data/VMs/ProviderVM' import { storageState } from '../ipfs/storage' import { useProviderIDs } from './reactive' const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO, { prefix: '[online]' }) // eslint-disable-line unused-imports/no-unused-vars export const [isOnline, setOnline] = createSignal(false) export const [isStorageReachable, setStorageReachable] = createSignal(false) const CID_TO_TEST = 'bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic223w5sk3m' // source: https://github.com/ipfs/public-gateway-checker/blob/main/src/constants.ts#L2 export async function getStorageIssues() { const res: Record = {} if (!navigator.onLine) { WARN('not online') return res } for (const eachPro of storageState.gateways) { const thisURL = `${eachPro.url}${eachPro.type === 'ipfs-gateway' ? `/ipfs/${CID_TO_TEST}` : '/health'}` let eachRes try { eachRes = await fetch(thisURL, { method: 'HEAD' }) } catch (error) { ERROR(error) eachRes = error } res[thisURL] = eachRes } return res } export async function testStorageReachability() { // TODO refactor to use storageState ? maybe ? if (!navigator.onLine) return false const promises = [] try { const storageProviderIDs = useProviderIDs() const storageProviders = getVMs(ProviderVM, storageProviderIDs) const neededURLs = storageProviders.map(eachPro => `${eachPro.url}${eachPro.type === 'ipfs-gateway' ? `/ipfs/${CID_TO_TEST}` : '/health'}`, ) DEBUG({ storageProviders, neededURLs }) for (const eachURL of neededURLs) { promises.push(isReachable(eachURL)) } } catch (error) { ERROR(error) } const results = await Promise.all(promises) DEBUG({ results }) if (results.includes(false)) return false return true } // strategy and code ripped from https://stackoverflow.com/a/44766737/2919380 window.addEventListener('online', handleConnection) window.addEventListener('offline', handleConnection) // TODO listen for changes to storage provider array and check reachability on each change async function handleConnection(skipCheck = false) { VERBOSE(`[handleConnection]`, { navigator, skipCheck, navOnLine: navigator.onLine, isOnline: isOnline() }) if (navigator.onLine) { if (skipCheck) { DEBUG('skipping reachable check') return setOnline(true) } isReachable(getServerUrl()).then(async (online) => { if (online) { // handle online status setOnline(true) DEBUG('online') setStorageReachable(await testStorageReachability()) } else { setOnline(false) DEBUG('navigator.onLine', navigator.onLine, 'but no connectivity') } }) } else { // handle offline status setOnline(false) DEBUG('offline') } } export async function isReachable(url: string) { /** * Note: fetch() still "succeeds" for 404s on subdirectories, * which is ok when only testing for domain reachability. * * Example: * https://google.com/noexist does not throw * https://noexist.com/noexist does throw */ return fetch(url, { method: 'HEAD' /* , mode: 'no-cors' */ }) // if mode is no-cors, results will always be opaque .then((resp) => { VERBOSE({ url, resp }) return !!(resp && (resp.ok || resp.type === 'opaque')) }) .catch((err) => { WARN('[conn test failure]:', { url, err }) return false }) } function getServerUrl() { // use hardcoded url only if app is served from localhost return window.location.origin.includes('localhost') ? 'https://wovin.in/' : window.location.origin } handleConnection(true)