From cd1c62718304245ce7e70dce8d141518608f9461 Mon Sep 17 00:00:00 2001 From: Oleksandr Zhynzher Date: Thu, 16 Nov 2023 09:33:49 +0200 Subject: [PATCH 1/2] EPMUII-8317 Add errors handling for load from URL --- src/engine/lib/core/loaders/MRIFileLoader.ts | 22 ++++++++++------ src/engine/lib/core/readers/MRIReader.ts | 7 ++++-- .../AbstractFileReader.ts | 2 +- src/engine/lib/services/StoreService.ts | 5 ++-- src/ui/Main.jsx | 25 ++++++++++++++++--- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/engine/lib/core/loaders/MRIFileLoader.ts b/src/engine/lib/core/loaders/MRIFileLoader.ts index 7738988e..7ac99a77 100644 --- a/src/engine/lib/core/loaders/MRIFileLoader.ts +++ b/src/engine/lib/core/loaders/MRIFileLoader.ts @@ -24,7 +24,7 @@ export class MRIFileLoader { * @param {string} url - The URL of the file to load. * @returns {Promise} A promise that resolves to an array of Files or rejects with an error. */ - async load(url: string): Promise { + async load(url: string): Promise { this.filesLoaded = 0; this.filesProgressByLength = false; this.store.setLoadingProgress(0); @@ -52,15 +52,16 @@ export class MRIFileLoader { * @param {string} url - The URL from which to fetch the file. * @returns {Promise} A promise that resolves to an array containing the fetched file as a File object. */ - async fetchSingleFile(url: string): Promise { + async fetchSingleFile(url: string): Promise { 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, @@ -91,14 +92,15 @@ export class MRIFileLoader { * @param {string} txtUrl - The URL of the .txt file containing the list of file URLs. * @returns {Promise} A promise that resolves to an array of File objects. */ - async fetchTxtFile(txtUrl: string): Promise { + async fetchTxtFile(txtUrl: string): Promise { 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; + return validFalies.flat(); } /** @@ -131,7 +133,9 @@ export class MRIFileLoader { const files = await Promise.all(filePromises); - return files.flat(); + const validFalies = files.filter(Boolean) as Array; + + return validFalies.flat(); } /** @@ -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; @@ -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); } } diff --git a/src/engine/lib/core/readers/MRIReader.ts b/src/engine/lib/core/readers/MRIReader.ts index f4e12778..7a3edae0 100644 --- a/src/engine/lib/core/readers/MRIReader.ts +++ b/src/engine/lib/core/readers/MRIReader.ts @@ -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.'); } diff --git a/src/engine/lib/core/readers/abstract-file-reader/AbstractFileReader.ts b/src/engine/lib/core/readers/abstract-file-reader/AbstractFileReader.ts index bbeb9a6a..ce12de81 100644 --- a/src/engine/lib/core/readers/abstract-file-reader/AbstractFileReader.ts +++ b/src/engine/lib/core/readers/abstract-file-reader/AbstractFileReader.ts @@ -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); } /** diff --git a/src/engine/lib/services/StoreService.ts b/src/engine/lib/services/StoreService.ts index e0b1a876..fda90804 100644 --- a/src/engine/lib/services/StoreService.ts +++ b/src/engine/lib/services/StoreService.ts @@ -80,11 +80,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 }, diff --git a/src/ui/Main.jsx b/src/ui/Main.jsx index 1c2c21ac..0568eda7 100644 --- a/src/ui/Main.jsx +++ b/src/ui/Main.jsx @@ -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'; @@ -28,13 +27,16 @@ 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'; export const Main = () => { const dispatch = useDispatch(); - const { arrErrors, isLoaded, progress, spinner, viewMode, showModalText, showModalAlert } = useSelector((state) => state); + const { isLoaded, progress, spinner, viewMode, showModalText, showModalAlert } = useSelector((state) => state); const [m_fileNameOnLoad, setM_fileNameOnLoad] = useState(false); const [isWebGl20supported, setIsWebGl20supported] = useState(true); @@ -43,6 +45,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() { @@ -55,6 +58,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, @@ -204,7 +224,6 @@ export const Main = () => { )} - {arrErrors.length > 0 && } {showModalText && ( )} From 9a7bea7ceadda8906eca0a86bc8e71fde41b60e5 Mon Sep 17 00:00:00 2001 From: Danil Rostov Date: Tue, 19 Dec 2023 22:32:45 -0800 Subject: [PATCH 2/2] Fix onerror xhr reject event --- src/engine/lib/core/loaders/MRIFileLoader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/lib/core/loaders/MRIFileLoader.ts b/src/engine/lib/core/loaders/MRIFileLoader.ts index 7ac99a77..72c4b517 100644 --- a/src/engine/lib/core/loaders/MRIFileLoader.ts +++ b/src/engine/lib/core/loaders/MRIFileLoader.ts @@ -174,7 +174,7 @@ export class MRIFileLoader { xhr.onerror = () => { this.handleVolumeLoadFailed(`Failed to fetch file from URL: ${url}`); - reject(new Error()); + reject(); }; xhr.responseType = 'blob';