import { config } from './config.js' import { getRedisKey, hash } from './util.js' import { logger } from './logger.js' import * as cache from './cache.js' import * as redis from './redis.js' let latestVersion export const fetchLatestVersion = async () => { const infos = await Promise.all(config.urls.map(async baseUrl => { try { const response = await fetch(new URL('meta.json', baseUrl)) if (!response.ok) throw new Error() const meta = await response.json() const version = meta.commitSha || meta.buildDate || meta.version if (!version) throw new Error() return version } catch (err) { logger.warn(`[Version] UI container at ${baseUrl} does not have meta.json. Fall back to version hash based on manifest.`) } try { const response = await fetch(new URL('manifest.json', baseUrl)) if (!response.ok) throw new Error() const manifest = await response.json() return hash(manifest) } catch (err) { logger.error(`[Version] Cannot fetch manifest from ${baseUrl}. Version info will not be correct.`) } })) return hash(infos) } export async function getLatestVersion () { if (latestVersion) return latestVersion if (redis.isEnabled()) { const version = await redis.client.get(getRedisKey({ name: 'latestVersion' })) if (version) { logger.info(`[Version] Got initial version from redis: '${version}'`) return (latestVersion = version) } } const version = await fetchLatestVersion() logger.info(`[Version] Fetched initial version: '${version}'`) if (redis.isEnabled()) { redis.pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), version) await redis.client.set(getRedisKey({ name: 'latestVersion' }), version) } return (latestVersion = version) } export function registerLatestVersionListener (client) { if (!redis.isEnabled()) return const key = getRedisKey({ name: 'updateLatestVersion' }) client.subscribe(key, (errs, count) => logger.info(`[Redis] Subscribed to ${key}.`)) client.on('message', async (channel, version) => { if (channel !== key) return logger.info(`[Version] Received 'updateLatestVersion' event. Clearing cache. New version: '${version}'`) await config.load() cache.clear() latestVersion = version }) } export async function updateVersionProcessor () { logger.info('[Version] Check for new version') await config.load() const [storedVersion, fetchedVersion] = await Promise.all([ getLatestVersion(), fetchLatestVersion() ]) if (storedVersion === fetchedVersion) { logger.info(`[Version] No new version has been found. No update needed. Current version: ${storedVersion}`) return fetchedVersion } logger.info(`[Version] Found new source version. Current version: '${storedVersion}', new version: '${fetchedVersion}'`) if (redis.isEnabled()) { redis.pubClient.publish(getRedisKey({ name: 'updateLatestVersion' }), fetchedVersion) await redis.client.set(getRedisKey({ name: 'latestVersion' }), fetchedVersion) } else { // if redis is disabled, this will only be trigger by a setInterval and not from a redis event logger.info('[Version] Clear local cache due to version update.') cache.clear() } return (latestVersion = fetchedVersion) }