electron-info
Version:
Get useful data about Electron releases.
97 lines (96 loc) • 4.07 kB
JavaScript
import logdown from 'logdown';
import { promises as fs, constants as fsConstants } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { URL } from 'node:url';
import { HTTPService } from './HTTPService.js';
export class FileService {
constructor(options) {
this.options = options;
this.logger = logdown('electron-info/FileService', {
logger: console,
markdown: false,
});
if (this.options.debug) {
this.logger.state.isEnabled = true;
}
this.logger.log('Initialized', this.options);
this.httpService = new HTTPService({
debug: this.options.debug,
timeout: this.options.timeout,
});
}
async getReleases() {
this.logger.log('Parsing releases URL', { releasesUrl: this.options.releasesUrl });
const parsedUrl = new URL(this.options.releasesUrl);
if (!parsedUrl.href) {
throw new Error('Invalid releases URL provided');
}
if (parsedUrl.protocol === 'file') {
this.logger.log('Releases URL points to a local file:', { releasesUrl: this.options.releasesUrl });
return this.loadReleasesFile(path.resolve(this.options.releasesUrl));
}
this.logger.log('Releases URL points to a URL:', { releasesUrl: this.options.releasesUrl });
const tempDirectory = await this.createTempDir();
const tempFile = path.join(tempDirectory, 'latest.json');
const tempFileExists = await this.isPathReadable(tempFile);
if (this.options.forceUpdate) {
this.logger.log(`Force download of the releases file requested`, {
forceUpdate: this.options.forceUpdate,
releasesUrl: this.options.releasesUrl,
tempFile,
});
return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
}
if (tempFileExists) {
this.logger.log('Found a local copy of the releases file:', { tempFile });
const tempFileFromToday = await this.isFileFromToday(tempFile);
this.logger.log(`Releases file "${tempFile}" is less than 24 hours old:`, tempFileFromToday);
if (tempFileFromToday) {
return this.loadReleasesFile(tempFile);
}
}
return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
}
async createTempDir() {
const tempDirectory = this.options.tempDirectory || path.join(os.tmpdir(), 'electron-info');
const tempDirectoryExists = await this.isPathReadable(tempDirectory);
if (!tempDirectoryExists) {
this.logger.log('Creating temp directory', { tempDirectory });
await fs.mkdir(tempDirectory);
}
else {
this.logger.log('Temp directory exists', { tempDirectory });
}
return tempDirectory;
}
async isFileFromToday(fileName) {
const { mtime: fileModifiedDate } = await fs.stat(fileName);
this.logger.log(`File "${fileName}" is from "${fileModifiedDate.toString()}"`);
return isWithinLastDay(fileModifiedDate);
}
async isPathReadable(filePath) {
try {
await fs.access(filePath, fsConstants.F_OK | fsConstants.R_OK);
return true;
}
catch (error) {
this.logger.log('File is not readable:', { errorMessage: error.message });
return false;
}
}
async loadReleasesFile(localPath) {
this.logger.log('Loading local releases file:', { localPath });
const rawData = await fs.readFile(localPath, 'utf8');
const releases = JSON.parse(rawData);
if (!Array.isArray(releases)) {
throw new Error('Invalid data in releases file');
}
return releases;
}
}
export function isWithinLastDay(date, now = new Date()) {
const yesterday = new Date(now);
yesterday.setUTCDate(yesterday.getUTCDate() - 1);
return date > yesterday;
}