Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/services/url.service.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * @file url.service.ts
0003  * @description Provides URL resolution services for handling file downloads and conversions in an Angular application.
0004  *              The service supports different configurations depending on how the application is served and includes
0005  *              protocol aliasing for custom URL schemes.
0006  */
0007 
0008 import { Injectable } from '@angular/core';
0009 import { UserConfigService } from "./user-config.service";
0010 import { ServerConfigService } from "./server-config.service";
0011 
0012 /**
0013  * @class UrlService
0014  * @description This service resolves URLs for downloading and converting files. It handles different scenarios based
0015  *              on whether the application is served as a standalone static site, served by a backend like PyroBird, or
0016  *              configured to use a specific API endpoint. It also supports protocol aliases and special URL schemes.
0017  *
0018  * ### Assumptions:
0019  * - The application may be served in various configurations:
0020  *   - Standalone static site without backend API.
0021  *   - Served by a Flask application (e.g., PyroBird) with a backend API.
0022  *   - Served by another service with or without a backend API.
0023  * - The service needs to resolve URLs for files that may:
0024  *   - Be accessible over HTTP/HTTPS.
0025  *   - Be local files requiring backend API to serve them.
0026  *   - Use custom protocols (e.g., `asset://`, `epic://`).
0027  *
0028  * ### Use Cases:
0029  * - **Case 1: Downloading Files**
0030  *   - **1.1**: Input URL starts with protocol like `root://`, `http://` or `https://`. The URL is used as is.
0031  *   - **1.2**: Input URL has no protocol or is a local file. The service checks if a backend is available and constructs the download endpoint URL.
0032  * - **Case 2: Converting Files**
0033  *   - **2.1 & 2.2**: Input URL is converted using the backend 'convert' endpoint, regardless of the original protocol.
0034  *
0035  * ### Protocol Aliases:
0036  * - `asset://`: Points to assets served from the frontend server.
0037  * - `epic://`: Custom protocol replaced with a specific base URL.
0038  *
0039  * ### Examples:
0040  * - Download URL:
0041  *   - Input: `https://example.com/file.root`
0042  *   - Output: `https://example.com/file.root` (Case 1.1)
0043  * - Download URL:
0044  *   - Input: `/path/to/file.root`
0045  *   - Output: `<serverAddress>/api/v1/download?f=%2Fpath%2Fto%2Ffile.root` (if backend is available) (Case 1.2)
0046  * - Convert URL:
0047  *   - Input: `https://example.com/file.root`, `fileType`, `entries`
0048  *   - Output: `<serverAddress>/api/v1/convert/fileType/entries?f=https%3A%2F%2Fexample.com%2Ffile.root`
0049  */
0050 
0051 @Injectable({
0052   providedIn: 'root'
0053 })
0054 export class UrlService {
0055 
0056   private serverAddress: string = '';
0057   private isBackendAvailable: boolean = false;
0058 
0059   // Protocol aliases mapping
0060   private readonly protocolAliases: { [key: string]: string } = {
0061     'epic://': 'https://eic.github.io/epic/artifacts/',
0062     // Add other protocol aliases here if needed
0063   };
0064 
0065   constructor(
0066     private userConfigService: UserConfigService,
0067     private serverConfigService: ServerConfigService
0068   ) {
0069     this.initializeConfig();
0070   }
0071 
0072   /**
0073    * Initializes the service configuration and subscribes to changes in user and server configurations.
0074    */
0075   private initializeConfig() {
0076     this.updateServerConfig();
0077 
0078     // Subscribe to user configuration changes
0079     this.userConfigService.localServerUrl.subject.subscribe(() => {
0080       this.updateServerConfig();
0081     });
0082     this.userConfigService.localServerUseApi.subject.subscribe(() => {
0083       this.updateServerConfig();
0084     });
0085   }
0086 
0087   /**
0088    * Updates the backend availability and server address based on current configurations.
0089    */
0090   private updateServerConfig() {
0091     const servedByPyrobird = this.serverConfigService.config.servedByPyrobird;
0092     const userUseApi = this.userConfigService.localServerUseApi.value;
0093     const userServerUrl = this.userConfigService.localServerUrl.value;
0094 
0095     this.isBackendAvailable = servedByPyrobird || userUseApi;
0096 
0097     if (servedByPyrobird) {
0098       this.serverAddress = this.serverConfigService.config.apiBaseUrl;
0099     } else if (userUseApi) {
0100       this.serverAddress = userServerUrl;
0101     } else {
0102       this.serverAddress = '';
0103     }
0104   }
0105 
0106   /**
0107    * Resolves protocol aliases in the URL.
0108    *
0109    * - Replaces 'asset://' with the base URI of the application and the 'assets' path.
0110    * - Replaces any custom protocol aliases defined in the `protocolAliases` map.
0111    *
0112    * @param url The URL to resolve.
0113    * @returns The URL with protocol aliases resolved.
0114    */
0115   private resolveProtocolAliases(url: string): string {
0116     if (url.startsWith('asset://')) {
0117       const assetPath = url.substring('asset://'.length);
0118       // Assets are served from where the frontend is served.
0119       // Ensure there's no double slash
0120       const baseUri = document.baseURI.endsWith('/') ? document.baseURI : `${document.baseURI}/`;
0121       return `${baseUri}assets/${assetPath}`;
0122     }
0123 
0124     for (const alias in this.protocolAliases) {
0125       if (url.startsWith(alias)) {
0126         return url.replace(alias, this.protocolAliases[alias]);
0127       }
0128     }
0129     return url;
0130   }
0131 
0132   /**
0133    * Checks if a URL is absolute (i.e., starts with a protocol like 'http://').
0134    *
0135    * @param url The URL to check.
0136    * @returns True if the URL is absolute, false otherwise.
0137    */
0138   private isAbsoluteUrl(url: string): boolean {
0139     return /^[a-z][a-z0-9+.-]*:/.test(url);
0140   }
0141 
0142   /**
0143    * Resolves the URL for downloading a file.
0144    *
0145    * **Case 1.1**: If the URL is absolute (starts with 'http://' or 'https://'), it is returned as is.
0146    *
0147    * **Case 1.2**: If the URL has no protocol, it uses the backend download endpoint if available.
0148    *               Constructs the URL: `<serverAddress>/api/v1/download?f=<encoded inputUrl>`
0149    *
0150    * @param inputUrl The input URL to resolve.
0151    * @returns The resolved URL for downloading.
0152    */
0153   public resolveDownloadUrl(inputUrl: string): string {
0154     inputUrl = this.resolveProtocolAliases(inputUrl);
0155 
0156     if (this.isAbsoluteUrl(inputUrl)) {
0157       // Case 1.1: Leave the URL as is
0158       return inputUrl;
0159     } else {
0160       // Case 1.2: Use the download endpoint if available
0161       if (this.isBackendAvailable && this.serverAddress) {
0162         return `${this.serverAddress}/api/v1/download?f=${encodeURIComponent(inputUrl)}`;
0163       } else {
0164         console.warn("Backend is not available to fetch the file");
0165         return inputUrl;
0166       }
0167     }
0168   }
0169 
0170   /**
0171    * Resolves the URL for converting a file using the 'convert' endpoint.
0172    *
0173    * **Case 2.1 & 2.2**: Constructs the URL using the backend 'convert' endpoint.
0174    *                     Constructs the URL: `<serverAddress>/api/v1/convert/<fileType>/<entries>?f=<encoded inputUrl>`
0175    *
0176    * @param inputUrl The input URL to resolve.
0177    * @param fileType The file type for conversion.
0178    * @param entries Additional entries for conversion.
0179    * @returns The resolved URL for conversion.
0180    */
0181   public resolveConvertUrl(inputUrl: string, fileType: string, entries: string): string {
0182     inputUrl = this.resolveProtocolAliases(inputUrl);
0183 
0184     if (this.isBackendAvailable && this.serverAddress) {
0185       return `${this.serverAddress}/api/v1/convert/${fileType}/${entries}?f=${encodeURIComponent(inputUrl)}`;
0186     } else {
0187       console.warn("Backend is not available to perform conversion");
0188       return inputUrl;
0189     }
0190   }
0191 }