Skip to content

Commit

Permalink
feat: Add argvs parser (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyaiox authored Aug 9, 2024
1 parent 4143386 commit c3cfb54
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 17 deletions.
15 changes: 15 additions & 0 deletions packages/main/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,18 @@ export function getUserId() {
}
return userId as string;
}

export function getAdditionalArguments(): string[] {
const args = [];

if (process.argv.length > 2) {
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i].toLowerCase();
if (/--(version|prerelease)/.test(arg)) {
args.push(arg);
}
}
}

return args;
}
3 changes: 2 additions & 1 deletion packages/main/src/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fileURLToPath } from 'node:url';
import { app, BrowserWindow, ipcMain } from 'electron';
import { IPC_HANDLERS } from '#shared';
import { downloadApp, openApp, minimizeWindow, isExplorerInstalled, isExplorerUpdated } from './ipc';
import { getOSName, getAppIcon } from './helpers';
import { getOSName, getAppIcon, getAdditionalArguments } from './helpers';

async function createWindow() {
const browserWindow = new BrowserWindow({
Expand All @@ -23,6 +23,7 @@ async function createWindow() {
sandbox: false, // Sandbox disabled because the demo of preload script depend on the Node.js api
webviewTag: false, // The webview tag is not recommended. Consider alternatives like an iframe or Electron's BrowserView. @see https://www.electronjs.org/docs/latest/api/webview-tag#warning
preload: join(app.getAppPath(), 'packages/preload/dist/index.mjs'),
additionalArguments: getAdditionalArguments(),
},
});
browserWindow.setMenuBarVisibility(false);
Expand Down
47 changes: 47 additions & 0 deletions packages/preload/src/argvs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export function isValidVersion(version: string): boolean {
const versionRegex =
/^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
return versionRegex.test(version);
}

/**
* Parse command line arguments.
*
* @returns {Record<string, string>} An object containing parsed argument key-value pairs.
*/
export function parseArgv(): Record<string, string> {
const parsedArgv: Record<string, string> = {};

if (process.argv.length > 2) {
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i].toLowerCase();
if (/--(version|prerelease)/.test(arg)) {
const [key, value] = arg.split('=');
const cleanKey = key.replace('--', '');
parsedArgv[cleanKey] = value ?? 'true';
}
}
}

return parsedArgv;
}

/**
* Retrieves the version from the parsed command-line arguments.
* @returns The version string if available, otherwise undefined.
*/
export function getVersion(): string | undefined {
const parsedArgv = parseArgv();
if (isValidVersion(parsedArgv?.version)) {
return parsedArgv?.version;
}
}

/**
* Determines if should download a prerelease version of the Explorer.
* @returns A boolean value indicating if the Explorer should be downloaded as a prerelease version.
*/
export function getIsPrerelease(): boolean {
const parsedArgv = parseArgv();
return parsedArgv?.prerelease === 'true';
}
3 changes: 3 additions & 0 deletions packages/preload/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
isExplorerUpdated,
getOSName,
} from './ipc';
import { getVersion, getIsPrerelease } from './argvs';
export {
sha256sum,
versions,
Expand All @@ -28,4 +29,6 @@ export {
isExplorerInstalled,
isExplorerUpdated,
getOSName,
getVersion,
getIsPrerelease,
};
68 changes: 52 additions & 16 deletions packages/renderer/src/components/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@ import { IpcRendererEvent } from 'electron';
import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
import { Box, Button, Typography } from 'decentraland-ui2';
import log from 'electron-log/renderer';
import { downloadApp, openApp, isExplorerInstalled, isExplorerUpdated, downloadState, installState, getOSName } from '#preload';
import {
downloadApp,
openApp,
isExplorerInstalled,
isExplorerUpdated,
downloadState,
installState,
getOSName,
getVersion,
getIsPrerelease,
} from '#preload';
import { IPC_EVENT_DATA_TYPE, IpcRendererEventDataError, IpcRendererDownloadProgressStateEventData, IpcRendererEventData } from '#shared';
import { APPS, AppState, GithubReleaseResponse, GithubRelease } from './types';
import { Landscape, LoadingBar } from './Home.styles';
Expand All @@ -11,18 +21,39 @@ import LANDSCAPE_IMG from '/@assets/landscape.png';
const ONE_SECOND = 1000;
const FIVE_SECONDS = 5 * ONE_SECOND;

async function getLatestRelease(): Promise<GithubReleaseResponse> {
function getErrorMessage(error: unknown): string {
if (typeof error === 'string') {
return error;
}

if (error instanceof Error) {
return error.message;
}

return 'An error occurred';
}

async function getLatestRelease(version?: string, isPrerelease?: boolean): Promise<GithubReleaseResponse> {
const resp = await fetch(`https://api.github.com/repos/decentraland/${APPS.Explorer}/releases`);
if (resp.status === 200) {
const releases: GithubRelease[] = await resp.json();
const os = await getOSName();
for (const release of releases) {
for (const asset of release.assets) {
if (asset.name.toLowerCase().includes(os.toLowerCase())) {
const isMatchingOS = asset.name.toLowerCase().includes(os.toLowerCase());
const isValidVersion = !version || version === release.name;
const isValidPrerelease = !isPrerelease || (isPrerelease && !!release.prerelease);
if (isMatchingOS && isValidVersion && isValidPrerelease) {
return {
browser_download_url: asset.browser_download_url,
version: release.name,
};
} else if (!isMatchingOS) {
throw new Error('No asset found for your platform');
} else if (!isValidVersion) {
throw new Error('No asset found for the specified version');
} else if (!isValidPrerelease) {
throw new Error('No asset found with the prerelease flag');
}
}
}
Expand Down Expand Up @@ -130,10 +161,12 @@ export const Home: React.FC = memo(() => {
}, []);

useEffect(() => {
if (!initialized.current) {
initialized.current = true;
getLatestRelease()
.then(async ({ browser_download_url: url, version }) => {
const fetchReleaseData = async () => {
if (!initialized.current) {
initialized.current = true;

try {
const { browser_download_url: url, version } = await getLatestRelease(getVersion(), getIsPrerelease());
setDownloadUrl(url);
const _isInstalled = await isExplorerInstalled();
if (!_isInstalled) {
Expand All @@ -149,12 +182,15 @@ export const Home: React.FC = memo(() => {
return;
}
setIsUpdated(true);
})
.catch((error: Error) => {
setError(error.message);
log.error('[Renderer][Home][GetLatestRelease]', error);
});
}
} catch (error) {
const errorMessage = getErrorMessage(error);
setError(getErrorMessage(errorMessage));
log.error('[Renderer][Home][GetLatestRelease]', errorMessage);
}
}
};

fetchReleaseData();
}, []);

const renderDownloadStep = useCallback(() => {
Expand Down Expand Up @@ -208,10 +244,10 @@ export const Home: React.FC = memo(() => {
return (
<Box>
<Typography variant="h4" align="center">
{isDownloading ? 'Download failed' : 'Install failed'}
{isDownloading ? 'Download failed' : isInstalling ? 'Install failed' : 'Error'}
</Typography>
<Typography variant="body1" align="center">
{isDownloading ? 'Please check your internet connection and try again.' : 'Please try again.'}
{isDownloading ? 'Please check your internet connection and try again.' : isInstalling ? 'Please try again.' : error}
</Typography>
<Box display="flex" justifyContent="center" marginTop={'10px'}>
<Button onClick={() => (isDownloading ? handleRetryDownload(true) : handleRetryInstall(true))}>Retry</Button>
Expand All @@ -227,7 +263,7 @@ export const Home: React.FC = memo(() => {
</Typography>
</Box>
);
}, [downloadRetry, installRetry, state]);
}, [error, downloadRetry, installRetry, state]);

return (
<Box display="flex" alignItems={'center'} justifyContent={'center'} width={'100%'}>
Expand Down
2 changes: 2 additions & 0 deletions packages/renderer/src/components/Home/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export interface GithubRelease {
name: string;
browser_download_url: string;
}[];
draft: boolean;
prerelease: boolean;
}

export enum AppState {
Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class Analytics {
constructor(userId: string) {
this.userId = userId;

if (!import.meta.env.PROD) {
return;
}

if (Analytics.instance) {
return Analytics.instance;
}
Expand Down

0 comments on commit c3cfb54

Please sign in to comment.