Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-ng/display/src/lib/services/file-open-router.service.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * Decides WHICH registered loader should open a file the user picked, dropped
0003  * or typed a URL for.
0004  *
0005  * This is the control that routes; it holds no format knowledge of its own.
0006  * A `.root` file is claimed by name from both registries - the same extension
0007  * carries a detector geometry or a podio event tree - so when the name is
0008  * ambiguous the router probes the file for neutral facts (its top-level keys)
0009  * and asks each loader `canLoadContent()`. The geometry loader knows what a
0010  * TGeoManager looks like, the event loader knows what an 'events' TTree looks
0011  * like, and neither piece of knowledge lives here.
0012  *
0013  * The router only decides. Loading is the caller's move, so a UI can open a
0014  * range picker for events but load geometry straight away.
0015  */
0016 
0017 import { Injectable, inject } from '@angular/core';
0018 import type {
0019   DataSource,
0020   EventDataLoader,
0021   FileContentProbe,
0022   GeometryDataLoader,
0023 } from '@dexvis/firebird-core';
0024 import { sourceName } from '@dexvis/firebird-core/loaders';
0025 import { injectEventLoaders, injectGeometryLoaders } from '@dexvis/firebird-ng/api';
0026 import { RootFileService } from './root-file.service';
0027 
0028 /** Where a source should go, and who takes it there. */
0029 export type FileRoute =
0030   | { kind: 'geometry'; loader: GeometryDataLoader; probe?: FileContentProbe }
0031   | { kind: 'events'; loader: EventDataLoader; probe?: FileContentProbe }
0032   | { kind: 'unknown'; probe?: FileContentProbe; message: string };
0033 
0034 @Injectable({ providedIn: 'root' })
0035 export class FileOpenRouterService {
0036   private geometryLoaders = injectGeometryLoaders();
0037   private eventLoaders = injectEventLoaders();
0038   private rootFiles = inject(RootFileService);
0039 
0040   async route(source: DataSource): Promise<FileRoute> {
0041     const name = sourceName(source);
0042     const geometryClaims = this.geometryLoaders.filter(loader => loader.canLoad(source));
0043     const eventClaims = this.eventLoaders.filter(loader => loader.canLoad(source));
0044 
0045     // Unambiguous by name: one registry claims it, take the first taker
0046     if (geometryClaims.length && !eventClaims.length) {
0047       return { kind: 'geometry', loader: geometryClaims[0] };
0048     }
0049     if (eventClaims.length && !geometryClaims.length) {
0050       return { kind: 'events', loader: eventClaims[0] };
0051     }
0052     if (!geometryClaims.length && !eventClaims.length) {
0053       return { kind: 'unknown', message: `No loader claims '${name}'. ${this.knownFormats()}` };
0054     }
0055 
0056     // Both claim the name. Only ROOT files are ambiguous this way, and only a
0057     // ROOT file can be probed - anything else is a registration mistake worth
0058     // reporting rather than guessing about.
0059     if (!name.split('?')[0].toLowerCase().endsWith('.root')) {
0060       return {
0061         kind: 'unknown',
0062         message:
0063           `Both a geometry and an event loader claim '${name}', and it cannot be ` +
0064           `inspected to tell them apart`,
0065       };
0066     }
0067 
0068     const probe = await this.rootFiles.probe(source);
0069     const geometry = geometryClaims.find(loader => loader.canLoadContent?.(probe));
0070     if (geometry) return { kind: 'geometry', loader: geometry, probe };
0071     const events = eventClaims.find(loader => loader.canLoadContent?.(probe));
0072     if (events) return { kind: 'events', loader: events, probe };
0073 
0074     return { kind: 'unknown', probe, message: this.describeUnrecognized(name, probe) };
0075   }
0076 
0077   private describeUnrecognized(name: string, probe: FileContentProbe): string {
0078     const contents = probe.entries
0079       .filter(entry => entry.name !== 'StreamerInfo')
0080       .map(entry => `${entry.name} (${entry.className})`)
0081       .join(', ');
0082     return (
0083       `'${name}' is a ROOT file, but nothing in it is recognized` +
0084       (contents ? `. It holds: ${contents}` : ' — it looks empty') +
0085       `. Firebird reads detector geometry (TGeoManager) and podio event trees ('events').`
0086     );
0087   }
0088 
0089   private knownFormats(): string {
0090     const all = [...this.geometryLoaders, ...this.eventLoaders];
0091     return `Known formats: ${all.map(l => `${l.meta.label} (${l.meta.fileExtensions.join(', ')})`).join('; ')}`;
0092   }
0093 }