import WKT from 'terraformer-wkt-parser' ; import { Polygon } from '@turf/helpers' ; import { BBox } from './bbox' ; import { CRS_IDS , CRS_EPSG4326 , CRS_EPSG3857 , CRS_WGS84 , SUPPORTED_CRS_OBJ } from './crs' ; import { ApiType , MimeType , GetMapParams , OverrideGetMapParams } from './layer/const' ; import { ServiceType } from './layer/wms' ; import { AbstractSentinelHubV3Layer } from './layer/AbstractSentinelHubV3Layer' ; import { LayersFactory } from './layer/LayersFactory' ; import { WmsLayer } from './layer/WmsLayer' ; export async function legacyGetMapFromUrl ( urlWithQueryParams , api = ApiType . WMS , fallbackToWmsApi = false , overrideLayerConstructorParams ? , overrideGetMapParams ? ) { const url = new URL ( urlWithQueryParams ) ; let params = { } ; url . searchParams . forEach ( ( value , key ) => { params [ key ] = value ; } ) ; const baseUrl = `${ url . origin }${ url . pathname }` ; return legacyGetMapFromParams ( baseUrl , params , api , fallbackToWmsApi , overrideLayerConstructorParams , overrideGetMapParams ) ; } export function legacyGetMapWmsUrlFromParams ( baseUrl , wmsParams ) { const { layers , getMapParams } = parseLegacyWmsGetMapParams ( wmsParams ) ; const layer = new WmsLayer ( { baseUrl , layerId : layers } ) ; return layer . getMapUrl ( getMapParams , ApiType . WMS ) ; } export async function legacyGetMapFromParams ( baseUrl , wmsParams , api = ApiType . WMS , fallbackToWmsApi = false , overrideLayerConstructorParams ? , overrideGetMapParams ? ) { const { layers , evalscript , evalscriptUrl , evalsource , getMapParams , otherLayerParams , } = parseLegacyWmsGetMapParams ( wmsParams ) ; let layer ; if ( layers && layers . split ( ',' ) . length > 1 ) { layer = new WmsLayer ( { baseUrl , layerId : layers } ) ; } else { const layerId = layers ; const overrideConstructorParams = { ... otherLayerParams , ... overrideLayerConstructorParams } ; layer = await LayersFactory . makeLayer ( baseUrl , layerId , overrideConstructorParams ) ; if ( ! layer ) { throw new Error ( `Layer with id ${ layerId } was not found on service endpoint ${ baseUrl }` ) ; } if ( evalscript || evalscriptUrl ) { const expectedEvalsource = layer . dataset . shWmsEvalsource ; if ( expectedEvalsource !== evalsource ) { console . warn ( `Evalsource ${ evalsource } is not valid on this layer, will use: ${ expectedEvalsource }` ) ; } if ( evalscriptUrl ) { layer . setEvalscriptUrl ( evalscriptUrl ) ; } else { layer . setEvalscript ( evalscript ) ; } } } const updatedGetMapParams = { ... getMapParams , ... overrideGetMapParams } ; let combinedEffects = { } ; if ( getMapParams . effects && Object . keys ( getMapParams . effects ) . length > 0 ) { combinedEffects = { ... combinedEffects , ... getMapParams . effects } ; } if ( overrideGetMapParams && overrideGetMapParams . effects && Object . keys ( overrideGetMapParams . effects ) . length > 0 ) { combinedEffects = { ... combinedEffects , ... overrideGetMapParams . effects } ; } if ( Object . keys ( combinedEffects ) . length > 0 ) { updatedGetMapParams . effects = combinedEffects ; } switch ( api ) { case ApiType . WMS : return layer . getMap ( updatedGetMapParams , api ) ; case ApiType . PROCESSING : try { if ( ! ( layer instanceof AbstractSentinelHubV3Layer ) ) { throw new Error ( 'Processing API is only possible with SH V3 layers' ) ; } return layer . getMap ( updatedGetMapParams , api ) ; } catch ( ex ) { if ( fallbackToWmsApi ) { return legacyGetMapFromParams ( baseUrl , wmsParams , ApiType . WMS , fallbackToWmsApi , overrideLayerConstructorParams , overrideGetMapParams ) ; } else { throw ex ; } } default : throw new Error ( 'Only WMS and Processing API are supported with legacy functions' ) ; } } const DEFAULT_OGC_VERSIONS = { WMS : '1.3.0' , WCS : '1.1.2' , WFS : '2.0.0' , } ; type ParsedLegacyWmsGetMapParams = { layers : string ; evalscript : string | null ; evalscriptUrl : string | null ; evalsource : string | null ; getMapParams : GetMapParams ; otherLayerParams : Record < string , any > ; } ; export function parseLegacyWmsGetMapParams ( wmsParams ) { const params = convertKeysToLowercase ( wmsParams ) ; const layers = params . layers ; const service = serviceFromParams ( params ) ; const version = versionFromParams ( service , params ) ; let crs = crsFromParams ( service , params ) ; const bbox = bboxFromParams ( service , version , crs , params ) ; const [ fromTime , toTime ] = timeFromParams ( params ) ; const format = mimeTypeFromParams ( params ) ; let getMapParams = { bbox : bbox , fromTime : fromTime , toTime : toTime , format : format , } ; if ( params . resx && params . resy ) { const [ resx , resy ] = resXYFromParams ( params ) ; getMapParams . resx = resx ; getMapParams . resy = resy ; } else if ( params . width && params . height ) { const [ width , height ] = widthHeightFromParams ( params ) ; getMapParams . width = width ; getMapParams . height = height ; } const otherLayerParams = { } ; if ( params . maxcc ) { otherLayerParams . maxCloudCoverPercent = parseInt ( params . maxcc ) ; } if ( params . preview ) { getMapParams . preview = previewFromParams ( params ) ; } if ( params . geometry ) { getMapParams . geometry = WKT . parse ( params . geometry ) as Polygon ; } if ( params . quality ) { getMapParams . quality = parseInt ( params . quality ) ; } if ( params . gain !== undefined && params . gain !== null && params . gain !== '' ) { if ( ! getMapParams . effects ) { getMapParams . effects = { } ; } getMapParams . effects . gain = parseFloat ( params . gain ) ; } if ( params . gamma !== undefined && params . gamma !== null && params . gamma !== '' ) { if ( ! getMapParams . effects ) { getMapParams . effects = { } ; } getMapParams . effects . gamma = parseFloat ( params . gamma ) ; } if ( params . nicename ) { getMapParams . nicename = params . nicename ; } if ( params . showlogo ) { getMapParams . showlogo = ! [ 'false' , '0' , 'no' ] . includes ( params . showlogo . toLowerCase ( ) ) ; } if ( params . bgcolor ) { getMapParams . bgcolor = bgcolorFromParams ( params ) ; } if ( params . transparent ) { getMapParams . transparent = [ 'true' , '1' , 'yes' ] . includes ( params . transparent . toLowerCase ( ) ) ; } if ( params . temporal ) { getMapParams . temporal = [ 'true' , '1' , 'yes' ] . includes ( params . temporal . toLowerCase ( ) ) ; } if ( params . upsampling ) { getMapParams . upsampling = params . upsampling ; } if ( params . downsampling ) { getMapParams . downsampling = params . downsampling ; } const IGNORE_KNOWN_PARAMS = [ 'request' , 'layers' , 'service' , 'version' , 'crs' , 'srs' , 'srsname' , 'time' , ] ; const getMapParamsObjectKeys = Object . keys ( getMapParams ) ; let unknown = { } ; for ( let [ key , value ] of Object . entries ( params ) ) { if ( getMapParamsObjectKeys . includes ( key ) ) { continue ; } if ( IGNORE_KNOWN_PARAMS . includes ( key ) ) { continue ; } unknown [ key ] = value ; } if ( Object . keys ( unknown ) . length > 0 ) { getMapParams . unknown = unknown ; } let decodedEvalscript = null ; if ( params . evalscript ) { if ( typeof window !== 'undefined' && window . atob ) { decodedEvalscript = atob ( params . evalscript ) ; } else { decodedEvalscript = Buffer . from ( params . evalscript , 'base64' ) . toString ( 'utf8' ) ; } } return { layers : layers , evalscript : decodedEvalscript , evalscriptUrl : params . evalscripturl , evalsource : params . evalsource , getMapParams : getMapParams , otherLayerParams : otherLayerParams , } ; } function convertKeysToLowercase ( o ) { let result = { } ; for ( let [ key , value ] of Object . entries ( o ) ) { result [ key . toLowerCase ( ) . trim ( ) ] = '' + value ; } return result ; } function serviceFromParams ( params ) { if ( ! params . service ) { return ServiceType . WMS ; } switch ( params . service . toUpperCase ( ) ) { case ServiceType . WMS : case ServiceType . WCS : case ServiceType . WFS : return params . service . toUpperCase ( ) ; default : throw new Error ( 'Unknown service' ) ; } } function versionFromParams ( service , params ) { return params . version ? params . version : DEFAULT_OGC_VERSIONS [ service ] ; } function crsFromParams ( ogcService , params ) { let crs ; switch ( ogcService ) { case ServiceType . WMS : crs = params . crs ? params . crs : params . srs ; break ; case ServiceType . WCS : crs = params . srs ; break ; case ServiceType . WFS : crs = params . srsname ; break ; } if ( ! crs ) { throw new Error ( 'CRS not defined' ) ; } return crs ; } function bboxFromParams ( service , version , crsAuthId , params ) { if ( ! params . bbox ) { throw new Error ( 'Parameter bbox is mandatory' ) ; } const bboxStr = params . bbox ; const coords = params . bbox instanceof Array ? params . bbox : bboxStr . split ( ',' ) . map ( c => parseFloat ( c ) ) ; const crs = SUPPORTED_CRS_OBJ [ crsAuthId ] ; let minX , minY , maxX , maxY ; switch ( crs ) { case CRS_EPSG3857 : [ minX , minY , maxX , maxY ] = coords ; break ; case CRS_EPSG4326 : case CRS_WGS84 : if ( ( service === 'WMS' && version === '1.1.1' ) || ( service === 'WFS' && version === '1.0.0' ) || ( service === 'WCS' && version === '1.0.0' ) ) { [ minX , minY , maxX , maxY ] = coords ; } else { [ minY , minX , maxY , maxX ] = coords ; } break ; default : throw new Error ( 'Unsupported CRS - bbox could not be parsed' ) ; } [ minX , maxX ] = [ Math . min ( minX , maxX ) , Math . max ( minX , maxX ) ] ; [ minY , maxY ] = [ Math . min ( minY , maxY ) , Math . max ( minY , maxY ) ] ; return new BBox ( crs , minX , minY , maxX , maxY ) ; } function isTimeSpecifiedInDate ( dateStr ) { return dateStr . length > 'YYYY-MM-DD ' . length ; } function timeFromParams ( params ) { if ( ! params . time ) { throw new Error ( 'Time not specified' ) ; } const timeParts = params . time . split ( '/' ) ; let fromTime , toTime ; if ( timeParts . length >= 2 ) { fromTime = new Date ( timeParts [ 0 ] ) ; toTime = new Date ( timeParts [ 1 ] ) ; if ( ! isTimeSpecifiedInDate ( timeParts [ 1 ] ) ) { toTime . setUTCHours ( 23 , 59 , 59 , 999 ) ; } } else if ( timeParts . length === 1 ) { fromTime = new Date ( '1970-01-01' ) ; toTime = new Date ( timeParts [ 0 ] ) ; if ( ! isTimeSpecifiedInDate ( timeParts [ 0 ] ) ) { toTime . setUTCHours ( 23 , 59 , 59 , 999 ) ; } } return [ new Date ( fromTime ) , new Date ( toTime ) ] ; } function mimeTypeFromParams ( params ) { return params . format ? params . format : 'image/png' ; } function resXYFromParams ( params ) { return [ params . resx , params . resy ] ; } function widthHeightFromParams ( params ) { return [ Number . parseInt ( params . width ) , Number . parseInt ( params . height ) ] ; } function previewFromParams ( params ) { if ( params . preview === undefined || params . preview === null ) { return 2 ; } return Math . min ( Math . max ( Number . parseInt ( params . preview ) , 0 ) , 2 ) ; } function bgcolorFromParams ( params ) { if ( ! params . bgcolor ) { return '000000' ; } return params . bgcolor ; }