Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error handling for load from ext link #182

Merged
merged 3 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/engine/lib/core/loaders/MRIFileLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class MRIFileLoader {
* @param {string} url - The URL of the file to load.
* @returns {Promise<File[]>} A promise that resolves to an array of Files or rejects with an error.
*/
async load(url: string): Promise<File[]> {
async load(url: string): Promise<File[] | null> {
this.filesLoaded = 0;
this.filesProgressByLength = false;
this.store.setLoadingProgress(0);
Expand Down Expand Up @@ -52,15 +52,16 @@ export class MRIFileLoader {
* @param {string} url - The URL from which to fetch the file.
* @returns {Promise<File[]>} A promise that resolves to an array containing the fetched file as a File object.
*/
async fetchSingleFile(url: string): Promise<File[]> {
async fetchSingleFile(url: string): Promise<File[] | null> {
const response = await this.fetchWithProgress(url, this.callbackLoadProgress);

if (!response.ok) {
this.handleVolumeLoadFailed(`Failed to fetch file from URL: ${url}`);
return [];
return null;
}

const blob = await response.blob();

const fileName = getFileNameFromUrl(url);
const file = new File([blob], fileName, {
type: blob.type,
Expand Down Expand Up @@ -91,14 +92,15 @@ export class MRIFileLoader {
* @param {string} txtUrl - The URL of the .txt file containing the list of file URLs.
* @returns {Promise<File[]>} A promise that resolves to an array of File objects.
*/
async fetchTxtFile(txtUrl: string): Promise<File[]> {
async fetchTxtFile(txtUrl: string): Promise<File[] | null> {
this.filesProgressByLength = true;
const base = txtUrl.substring(0, txtUrl.lastIndexOf('/') + 1);
const fileNames = await this.fetchTxtContent(txtUrl);
this.filesLength = fileNames.length;
const filePromises = fileNames.map((filename: string) => this.fetchSingleFile(base + filename));
const files = await Promise.all(filePromises);
return files.flat();
const validFalies = files.filter(Boolean) as Array<File[]>;
return validFalies.flat();
}

/**
Expand Down Expand Up @@ -131,7 +133,9 @@ export class MRIFileLoader {

const files = await Promise.all(filePromises);

return files.flat();
const validFalies = files.filter(Boolean) as Array<File[]>;

return validFalies.flat();
}

/**
Expand All @@ -154,6 +158,10 @@ export class MRIFileLoader {
};

xhr.onload = () => {
if (xhr.status === 403) {
return this.handleVolumeLoadFailed(`Error 403 Forbiden, failed to fetch file from URL: ${url}`);
}

if (this.filesProgressByLength) {
this.filesLoaded = this.filesLoaded + 1;
const percentComplete = this.filesLoaded / this.filesLength;
Expand All @@ -166,7 +174,7 @@ export class MRIFileLoader {

xhr.onerror = () => {
this.handleVolumeLoadFailed(`Failed to fetch file from URL: ${url}`);
reject(new Error());
reject();
};

xhr.responseType = 'blob';
Expand All @@ -189,6 +197,6 @@ export class MRIFileLoader {
*/
handleVolumeLoadFailed(error: string) {
this.events.emit(MriEvents.FILE_READ_ERROR, { error });
this.store.setVolumeLoadFailed(this.fileName, [error]);
this.store.setVolumeLoadFailed(this.fileName);
}
}
7 changes: 5 additions & 2 deletions src/engine/lib/core/readers/MRIReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export class MRIReader {
if (data && data.length && data[0] instanceof File) {
this.fileReader.read(data as File[]);
} else if (isValidUrl(data as string)) {
const files: File[] = await this.fileLoader.load(data as string);
this.fileReader.read(files);
const files: File[] | null = await this.fileLoader.load(data as string);

if (files) {
this.fileReader.read(files);
}
} else {
throw new Error('Invalid input. Expected a File or URL.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export abstract class AbstractFileReader {
*/
public handleVolumeReadFailed(error: string) {
this.events.emit(MriEvents.FILE_READ_ERROR, { error });
this.store.setVolumeLoadFailed(this.fileName, [error]);
this.store.setVolumeLoadFailed(this.fileName);
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/engine/lib/services/StoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,10 @@ export class MRIStoreService {
this.dispatchActions(actions);
}

public setVolumeLoadFailed(fileName: string, errors: string[]): void {
public setVolumeLoadFailed(fileName: string): void {
const actions = [
{ type: StoreActionType.SET_ERR_ARRAY, errors },
{ type: StoreActionType.SET_VOLUME_SET, volume: null },
{ type: StoreActionType.SET_FILENAME, fileName: fileName },
{ type: StoreActionType.SET_FILENAME, fileName },
{ type: StoreActionType.SET_PROGRESS, progress: 0 },
{ type: StoreActionType.SET_SPINNER, spinner: false },
{ type: StoreActionType.SET_IS_LOADED, isLoaded: false },
Expand Down
28 changes: 24 additions & 4 deletions src/ui/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import StoreActionType from '../store/ActionTypes';
import FullScreenToggle from './Toolbars/FullScreen';
import UiModalText from './Modals/UiModalText';
import UiModalAlert from './Modals/ModalAlert';
import UiErrConsole from './UiErrConsole';
import ModeView from '../store/ViewMode';
import Graphics2d from '../engine/Graphics2d';
import BrowserDetector from '../engine/utils/BrowserDetector';
Expand All @@ -28,6 +27,9 @@ import { TopToolbar } from './TopToolbar/TopToolbar';
import { UiAbout } from './Header/UiAbout';
import { MobileSettings } from './MobileSettings/MobileSettings';
import StartScreen from './StartScreen/StartScreen';
import MriViwer from '../engine/lib/MRIViewer';
import { MriEvents } from '../engine/lib/enums';

import css from './Main.module.css';
import cx from 'classnames';
import '../nouislider-custom.css';
Expand All @@ -38,8 +40,9 @@ import UiModalConfirmation from './Modals/UiModalConfirmation';

export const Main = () => {
const dispatch = useDispatch();
const { arrErrors, isLoaded, progress, spinner, viewMode, showModalText, showModalAlert, showModalWindowCW, showModalConfirmation } =
useSelector((state) => state);
const { isLoaded, progress, spinner, viewMode, showModalText, showModalAlert, showModalWindowCW, showModalConfirmation } = useSelector(
(state) => state
);

const [m_fileNameOnLoad, setM_fileNameOnLoad] = useState(false);
const [isWebGl20supported, setIsWebGl20supported] = useState(true);
Expand All @@ -48,6 +51,7 @@ export const Main = () => {
const [isFullMode, setIsFullMode] = useState(false);
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
const appRef = useRef();
const mriViwer = useRef(MriViwer).current;

useEffect(() => {
function handleResize() {
Expand All @@ -60,6 +64,23 @@ export const Main = () => {
window.removeEventListener('resize', handleResize);
};
}, []);

useEffect(() => {
const handleFileReadError = (eventData) => {
setStrAlertTitle('File Read Error');
setStrAlertText(eventData.error);
onShowModalAlert();
};

// Subscribe to the FILE_READ_ERROR event
mriViwer.events.on(MriEvents.FILE_READ_ERROR, handleFileReadError);

// Clean up
return () => {
mriViwer.events.off(MriEvents.FILE_READ_ERROR, handleFileReadError);
};
}, []);

const [, drop] = useDrop(
() => ({
accept: DnDItemTypes.SETTINGS,
Expand Down Expand Up @@ -215,7 +236,6 @@ export const Main = () => {
<MobileSettings />
</div>
)}
{arrErrors.length > 0 && <UiErrConsole />}
{showModalText && (
<UiModalText stateVis={showModalText} onHide={onHideModalText.bind(this)} onShow={onShowModalText.bind(this)} />
)}
Expand Down
Loading