| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | import Uri from "../ThirdParty/Uri.js";import Check from "./Check.js";import Credit from "./Credit.js";import defaultValue from "./defaultValue.js";import defined from "./defined.js";import Ion from "./Ion.js";import Resource from "./Resource.js";import RuntimeError from "./RuntimeError.js";/** * A {@link Resource} instance that encapsulates Cesium ion asset access. * This object is normally not instantiated directly, use {@link IonResource.fromAssetId}. * * @alias IonResource * @constructor * @augments Resource * * @param {Object} endpoint The result of the Cesium ion asset endpoint service. * @param {Resource} endpointResource The resource used to retreive the endpoint. * * @see Ion * @see IonImageryProvider * @see createWorldTerrain * @see https://cesium.com */function IonResource(endpoint, endpointResource) {  //>>includeStart('debug', pragmas.debug);  Check.defined("endpoint", endpoint);  Check.defined("endpointResource", endpointResource);  //>>includeEnd('debug');  let options;  const externalType = endpoint.externalType;  const isExternal = defined(externalType);  if (!isExternal) {    options = {      url: endpoint.url,      retryAttempts: 1,      retryCallback: retryCallback,    };  } else if (    externalType === "3DTILES" ||    externalType === "STK_TERRAIN_SERVER"  ) {    // 3D Tiles and STK Terrain Server external assets can still be represented as an IonResource    options = { url: endpoint.options.url };  } else {    //External imagery assets have additional configuration that can't be represented as a Resource    throw new RuntimeError(      "Ion.createResource does not support external imagery assets; use IonImageryProvider instead."    );  }  Resource.call(this, options);  // The asset endpoint data returned from ion.  this._ionEndpoint = endpoint;  this._ionEndpointDomain = isExternal    ? undefined    : new Uri(endpoint.url).authority();  // The endpoint resource to fetch when a new token is needed  this._ionEndpointResource = endpointResource;  // The primary IonResource from which an instance is derived  this._ionRoot = undefined;  // Shared promise for endpooint requests amd credits (only ever set on the root request)  this._pendingPromise = undefined;  this._credits = undefined;  this._isExternal = isExternal;}if (defined(Object.create)) {  IonResource.prototype = Object.create(Resource.prototype);  IonResource.prototype.constructor = IonResource;}/** * Asynchronously creates an instance. * * @param {Number} assetId The Cesium ion asset id. * @param {Object} [options] An object with the following properties: * @param {String} [options.accessToken=Ion.defaultAccessToken] The access token to use. * @param {String|Resource} [options.server=Ion.defaultServer] The resource to the Cesium ion API server. * @returns {Promise.<IonResource>} A Promise to am instance representing the Cesium ion Asset. * * @example * //Load a Cesium3DTileset with asset ID of 124624234 * viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(124624234) })); * * @example * //Load a CZML file with asset ID of 10890 * Cesium.IonResource.fromAssetId(10890) *   .then(function (resource) { *     viewer.dataSources.add(Cesium.CzmlDataSource.load(resource)); *   }); */IonResource.fromAssetId = function (assetId, options) {  const endpointResource = IonResource._createEndpointResource(    assetId,    options  );  return endpointResource.fetchJson().then(function (endpoint) {    return new IonResource(endpoint, endpointResource);  });};Object.defineProperties(IonResource.prototype, {  /**   * Gets the credits required for attribution of the asset.   *   * @memberof IonResource.prototype   * @type {Credit[]}   * @readonly   */  credits: {    get: function () {      // Only we're not the root, return its credits;      if (defined(this._ionRoot)) {        return this._ionRoot.credits;      }      // We are the root      if (defined(this._credits)) {        return this._credits;      }      this._credits = IonResource.getCreditsFromEndpoint(        this._ionEndpoint,        this._ionEndpointResource      );      return this._credits;    },  },});/** @private */IonResource.getCreditsFromEndpoint = function (endpoint, endpointResource) {  const credits = endpoint.attributions.map(Credit.getIonCredit);  const defaultTokenCredit = Ion.getDefaultTokenCredit(    endpointResource.queryParameters.access_token  );  if (defined(defaultTokenCredit)) {    credits.push(Credit.clone(defaultTokenCredit));  }  return credits;};/** @inheritdoc */IonResource.prototype.clone = function (result) {  // We always want to use the root's information because it's the most up-to-date  const ionRoot = defaultValue(this._ionRoot, this);  if (!defined(result)) {    result = new IonResource(      ionRoot._ionEndpoint,      ionRoot._ionEndpointResource    );  }  result = Resource.prototype.clone.call(this, result);  result._ionRoot = ionRoot;  result._isExternal = this._isExternal;  return result;};IonResource.prototype.fetchImage = function (options) {  if (!this._isExternal) {    const userOptions = options;    options = {      preferBlob: true,    };    if (defined(userOptions)) {      options.flipY = userOptions.flipY;      options.preferImageBitmap = userOptions.preferImageBitmap;    }  }  return Resource.prototype.fetchImage.call(this, options);};IonResource.prototype._makeRequest = function (options) {  // Don't send ion access token to non-ion servers.  if (    this._isExternal ||    new Uri(this.url).authority() !== this._ionEndpointDomain  ) {    return Resource.prototype._makeRequest.call(this, options);  }  if (!defined(options.headers)) {    options.headers = {};  }  options.headers.Authorization = `Bearer ${this._ionEndpoint.accessToken}`;  return Resource.prototype._makeRequest.call(this, options);};/** * @private */IonResource._createEndpointResource = function (assetId, options) {  //>>includeStart('debug', pragmas.debug);  Check.defined("assetId", assetId);  //>>includeEnd('debug');  options = defaultValue(options, defaultValue.EMPTY_OBJECT);  let server = defaultValue(options.server, Ion.defaultServer);  const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken);  server = Resource.createIfNeeded(server);  const resourceOptions = {    url: `v1/assets/${assetId}/endpoint`,  };  if (defined(accessToken)) {    resourceOptions.queryParameters = { access_token: accessToken };  }  return server.getDerivedResource(resourceOptions);};function retryCallback(that, error) {  const ionRoot = defaultValue(that._ionRoot, that);  const endpointResource = ionRoot._ionEndpointResource;  // Image is not available in worker threads, so this avoids  // a ReferenceError  const imageDefined = typeof Image !== "undefined";  // We only want to retry in the case of invalid credentials (401) or image  // requests(since Image failures can not provide a status code)  if (    !defined(error) ||    (error.statusCode !== 401 &&      !(imageDefined && error.target instanceof Image))  ) {    return Promise.resolve(false);  }  // We use a shared pending promise for all derived assets, since they share  // a common access_token.  If we're already requesting a new token for this  // asset, we wait on the same promise.  if (!defined(ionRoot._pendingPromise)) {    ionRoot._pendingPromise = endpointResource      .fetchJson()      .then(function (newEndpoint) {        //Set the token for root resource so new derived resources automatically pick it up        ionRoot._ionEndpoint = newEndpoint;        return newEndpoint;      })      .finally(function (newEndpoint) {        // Pass or fail, we're done with this promise, the next failure should use a new one.        ionRoot._pendingPromise = undefined;        return newEndpoint;      });  }  return ionRoot._pendingPromise.then(function (newEndpoint) {    // Set the new token and endpoint for this resource    that._ionEndpoint = newEndpoint;    return true;  });}export default IonResource;
 |