Bluesky app fork with some witchin' additions 馃挮
at main 101 lines 3.0 kB view raw
1import {useEffect, useState} from 'react' 2import EventEmitter from 'eventemitter3' 3 4import {FALLBACK_GEOLOCATION_SERVICE_RESPONSE} from '#/geolocation/const' 5import * as debug from '#/geolocation/debug' 6import {logger} from '#/geolocation/logger' 7import {type Geolocation} from '#/geolocation/types' 8import {device} from '#/storage' 9 10const geolocationData = FALLBACK_GEOLOCATION_SERVICE_RESPONSE 11const events = new EventEmitter() 12const EVENT = 'geolocation-service-response-updated' 13const emitGeolocationServiceResponseUpdate = (data: Geolocation) => { 14 events.emit(EVENT, data) 15} 16const onGeolocationServiceResponseUpdate = ( 17 listener: (data: Geolocation) => void, 18) => { 19 events.on(EVENT, listener) 20 return () => { 21 events.off(EVENT, listener) 22 } 23} 24 25async function fetchGeolocationServiceData(): Promise<Geolocation | undefined> { 26 if (debug.enabled) return debug.resolve(debug.geolocation) 27 // Return local geolocation data instead of making HTTP request 28 return geolocationData as Geolocation 29} 30 31/** 32 * Local promise used within this file only. 33 */ 34let geolocationServicePromise: Promise<{success: boolean}> | undefined 35 36/** 37 * Begin the process of resolving geolocation config. This is called right away 38 * at app start, and the promise is awaited later before proceeding with app 39 * startup. 40 */ 41export async function resolve() { 42 if (geolocationServicePromise) { 43 const cached = device.get(['geolocationServiceResponse']) 44 if (cached) { 45 logger.debug(`resolve(): using cache`) 46 } else { 47 logger.debug(`resolve(): no cache`) 48 const {success} = await geolocationServicePromise 49 if (success) { 50 logger.debug(`resolve(): resolved`) 51 } else { 52 logger.info(`resolve(): failed`) 53 } 54 } 55 } else { 56 logger.debug(`resolve(): initiating`) 57 58 geolocationServicePromise = new Promise(async resolvePromise => { 59 let success = false 60 61 function cacheResponseOrThrow(response: Geolocation | undefined) { 62 if (response) { 63 device.set(['geolocationServiceResponse'], response) 64 emitGeolocationServiceResponseUpdate(response) 65 } else { 66 throw new Error(`fetchGeolocationServiceData returned no data`) 67 } 68 } 69 70 try { 71 // Use local data - no need to retry or handle network errors 72 const config = await fetchGeolocationServiceData() 73 cacheResponseOrThrow(config) 74 success = true 75 } catch (e: any) { 76 logger.debug(`resolve(): fetchGeolocationServiceData failed`, { 77 safeMessage: e.message, 78 }) 79 } finally { 80 resolvePromise({success}) 81 } 82 }) 83 } 84} 85 86export function useGeolocationServiceResponse() { 87 const [config, setConfig] = useState(() => { 88 const initial = 89 device.get(['geolocationServiceResponse']) || 90 FALLBACK_GEOLOCATION_SERVICE_RESPONSE 91 return initial 92 }) 93 94 useEffect(() => { 95 return onGeolocationServiceResponseUpdate(config => { 96 setConfig(config) 97 }) 98 }, []) 99 100 return config 101}