3d-tiles-renderer
Version:
https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification
217 lines (136 loc) • 4.49 kB
JavaScript
import { traverseSet } from '../../base/traverseFunctions.js';
import { GoogleAttributionsManager } from './GoogleAttributionsManager.js';
function getSessionToken( root ) {
let sessionToken = null;
traverseSet( root, tile => {
if ( tile.content && tile.content.uri ) {
const [ , params ] = tile.content.uri.split( '?' );
sessionToken = new URLSearchParams( params ).get( 'session' );
return true;
}
return false;
} );
return sessionToken;
}
export class GoogleCloudAuthPlugin {
constructor( { apiToken, autoRefreshToken = false, logoUrl = null, useRecommendedSettings = true } ) {
this.name = 'GOOGLE_CLOUD_AUTH_PLUGIN';
this.priority = - Infinity;
this.apiToken = apiToken;
this.autoRefreshToken = autoRefreshToken;
this.useRecommendedSettings = useRecommendedSettings;
this.logoUrl = logoUrl;
this.sessionToken = null;
this.tiles = null;
this._onLoadCallback = null;
this._visibilityChangeCallback = null;
this._tokenRefreshPromise = null;
this._attributionsManager = new GoogleAttributionsManager();
this._logoAttribution = {
value: '',
type: 'image',
collapsible: false,
};
this._attribution = {
value: '',
type: 'string',
collapsible: true,
};
}
init( tiles ) {
if ( tiles == null ) {
return;
}
// reset the tiles in case this plugin was removed and re-added
tiles.resetFailedTiles();
if ( tiles.rootURL == null ) {
tiles.rootURL = 'https://tile.googleapis.com/v1/3dtiles/root.json';
}
if ( this.useRecommendedSettings ) {
// This plugin changes below values to be more efficient for the photorealistic tiles
tiles.parseQueue.maxJobs = 10;
tiles.downloadQueue.maxJobs = 30;
tiles.errorTarget = 20;
}
this.tiles = tiles;
this._onLoadCallback = ( { tileSet } ) => {
// the first tile set loaded will be the root
this.sessionToken = getSessionToken( tileSet.root );
// clear the callback once the root is loaded
tiles.removeEventListener( 'load-tile-set', this._onLoadCallback );
};
this._visibilityChangeCallback = ( { tile, visible } ) => {
const copyright = tile.cached.metadata.asset.copyright || '';
if ( visible ) {
this._attributionsManager.addAttributions( copyright );
} else {
this._attributionsManager.removeAttributions( copyright );
}
};
tiles.addEventListener( 'load-tile-set', this._onLoadCallback );
tiles.addEventListener( 'tile-visibility-change', this._visibilityChangeCallback );
}
getAttributions( target ) {
if ( this.tiles.visibleTiles.size > 0 ) {
if ( this.logoUrl ) {
this._logoAttribution.value = this.logoUrl;
target.push( this._logoAttribution );
}
this._attribution.value = this._attributionsManager.toString();
target.push( this._attribution );
}
}
preprocessURL( uri ) {
uri = new URL( uri );
if ( /^http/.test( uri.protocol ) ) {
uri.searchParams.append( 'key', this.apiToken );
if ( this.sessionToken !== null ) {
uri.searchParams.append( 'session', this.sessionToken );
}
}
return uri.toString();
}
dispose() {
const { tiles } = this;
tiles.removeEventListener( 'load-tile-set', this._onLoadCallback );
tiles.removeEventListener( 'tile-visibility-change', this._visibilityChangeCallback );
}
async fetchData( uri, options ) {
// wait for the token to refresh if loading
if ( this._tokenRefreshPromise !== null ) {
await this._tokenRefreshPromise;
uri = this.preprocessURL( uri );
}
const res = await fetch( uri, options );
if ( res.status >= 400 && res.status <= 499 && this.autoRefreshToken ) {
await this._refreshToken( options );
return fetch( this.preprocessURL( uri ), options );
} else {
return res;
}
}
_refreshToken( options ) {
if ( this._tokenRefreshPromise === null ) {
// refetch the root if the token has expired
const rootURL = new URL( this.tiles.rootURL );
rootURL.searchParams.append( 'key', this.apiToken );
this._tokenRefreshPromise = fetch( rootURL, options )
.then( res => res.json() )
.then( res => {
this.sessionToken = getSessionToken( res.root );
this._tokenRefreshPromise = null;
} );
// dispatch an error if we fail to refresh the token
this._tokenRefreshPromise
.catch( error => {
this.tiles.dispatchEvent( {
type: 'load-error',
tile: null,
error,
url: rootURL,
} );
} );
}
return this._tokenRefreshPromise;
}
}