1import { createTemporaryProjectFile } from './dotExpo'; 2 3export type DeviceInfo = { 4 installationId: string; 5 lastUsed: number; 6}; 7 8export type DevicesInfo = { 9 devices: DeviceInfo[]; 10}; 11 12const DEVICES_FILE_NAME = 'devices.json'; 13 14const MILLISECONDS_IN_30_DAYS = 30 * 24 * 60 * 60 * 1000; 15 16export const DevicesFile = createTemporaryProjectFile<DevicesInfo>(DEVICES_FILE_NAME, { 17 devices: [], 18}); 19 20let devicesInfo: DevicesInfo | null = null; 21 22export async function getDevicesInfoAsync(projectRoot: string): Promise<DevicesInfo> { 23 if (devicesInfo) { 24 return devicesInfo; 25 } 26 return readDevicesInfoAsync(projectRoot); 27} 28 29export async function readDevicesInfoAsync(projectRoot: string): Promise<DevicesInfo> { 30 try { 31 devicesInfo = await DevicesFile.readAsync(projectRoot); 32 33 // if the file on disk has old devices, filter them out here before we use them 34 const filteredDevices = filterOldDevices(devicesInfo.devices); 35 if (filteredDevices.length < devicesInfo.devices.length) { 36 devicesInfo = { 37 ...devicesInfo, 38 devices: filteredDevices, 39 }; 40 // save the newly filtered list for consistency 41 try { 42 await setDevicesInfoAsync(projectRoot, devicesInfo); 43 } catch { 44 // do nothing here, we'll just keep using the filtered list in memory for now 45 } 46 } 47 48 return devicesInfo; 49 } catch { 50 return await DevicesFile.setAsync(projectRoot, { devices: [] }); 51 } 52} 53 54export async function setDevicesInfoAsync( 55 projectRoot: string, 56 json: DevicesInfo 57): Promise<DevicesInfo> { 58 devicesInfo = json; 59 return await DevicesFile.setAsync(projectRoot, json); 60} 61 62export async function saveDevicesAsync( 63 projectRoot: string, 64 deviceIds: string | string[] 65): Promise<void> { 66 const currentTime = Date.now(); 67 const newDeviceIds = typeof deviceIds === 'string' ? [deviceIds] : deviceIds; 68 69 const { devices } = await getDevicesInfoAsync(projectRoot); 70 const newDevicesJson = devices 71 .filter((device) => !newDeviceIds.includes(device.installationId)) 72 .concat(newDeviceIds.map((deviceId) => ({ installationId: deviceId, lastUsed: currentTime }))); 73 await setDevicesInfoAsync(projectRoot, { devices: filterOldDevices(newDevicesJson) }); 74} 75 76function filterOldDevices(devices: DeviceInfo[]) { 77 const currentTime = Date.now(); 78 return ( 79 devices 80 // filter out any devices that haven't been used to open this project in 30 days 81 .filter((device) => currentTime - device.lastUsed <= MILLISECONDS_IN_30_DAYS) 82 // keep only the 10 most recently used devices 83 .sort((a, b) => b.lastUsed - a.lastUsed) 84 .slice(0, 10) 85 ); 86} 87